- Introduced new `attendances` and `visits` tables to manage employee attendance and customer visits, including relevant fields for check-in and check-out details. - Updated `company_settings` to include a `check_in_radius_meters` column for attendance validation. - Implemented foreign key constraints to ensure data integrity between `attendances`, `visits`, `employees`, `branches`, and other related entities. - Created new services and controllers for handling attendance and visit operations, including check-in, check-out, and bulk actions. - Enhanced DTOs for attendance and visit data transfer, including validation for input data. - Added unit and integration tests to validate the new functionalities and ensure proper handling of attendance and visit records. - Created migration scripts to apply the necessary database schema changes for the new features.
231 lines
4.7 KiB
TypeScript
231 lines
4.7 KiB
TypeScript
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
|
import {
|
|
ArrayNotEmpty,
|
|
IsArray,
|
|
IsIn,
|
|
IsLatitude,
|
|
IsLongitude,
|
|
IsNumber,
|
|
IsOptional,
|
|
IsString,
|
|
IsUrl,
|
|
IsUUID,
|
|
ValidateIf,
|
|
} from 'class-validator';
|
|
import { PaginationQueryDto } from '../../../../common/http/response';
|
|
import { CORE_STATUSES } from '../../../../common/value-objects/status/status';
|
|
import { CHECK_IN_METHODS } from '../../shared/check-in-verification';
|
|
|
|
export class VisitCheckInDto {
|
|
@ApiProperty({ format: 'uuid' })
|
|
@IsUUID('4')
|
|
customerId!: string;
|
|
|
|
@ApiPropertyOptional({ format: 'uuid' })
|
|
@IsOptional()
|
|
@IsUUID('4')
|
|
planId?: string;
|
|
|
|
@ApiProperty({ enum: CHECK_IN_METHODS })
|
|
@IsIn([...CHECK_IN_METHODS])
|
|
method!: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@ValidateIf((dto: VisitCheckInDto) => dto.method === 'nfc')
|
|
@IsString()
|
|
nfcId?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@ValidateIf((dto: VisitCheckInDto) => dto.method === 'qr')
|
|
@IsString()
|
|
qrCode?: string;
|
|
|
|
@ApiProperty()
|
|
@IsLatitude()
|
|
latitude!: number;
|
|
|
|
@ApiProperty()
|
|
@IsLongitude()
|
|
longitude!: number;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsUrl({ require_protocol: true, protocols: ['https'] })
|
|
photoUrl?: string;
|
|
}
|
|
|
|
export class VisitCheckOutDto {
|
|
@ApiProperty({ enum: CHECK_IN_METHODS })
|
|
@IsIn([...CHECK_IN_METHODS])
|
|
method!: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@ValidateIf((dto: VisitCheckOutDto) => dto.method === 'nfc')
|
|
@IsString()
|
|
nfcId?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@ValidateIf((dto: VisitCheckOutDto) => dto.method === 'qr')
|
|
@IsString()
|
|
qrCode?: string;
|
|
|
|
@ApiProperty()
|
|
@IsLatitude()
|
|
latitude!: number;
|
|
|
|
@ApiProperty()
|
|
@IsLongitude()
|
|
longitude!: number;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsUrl({ require_protocol: true, protocols: ['https'] })
|
|
photoUrl?: string;
|
|
}
|
|
|
|
export class UpdateVisitStatusDto {
|
|
@ApiProperty({ enum: CORE_STATUSES })
|
|
@IsIn([...CORE_STATUSES])
|
|
status!: string;
|
|
}
|
|
|
|
export class BulkIdsDto {
|
|
@ApiProperty({ type: [String], format: 'uuid' })
|
|
@IsArray()
|
|
@ArrayNotEmpty()
|
|
@IsUUID('4', { each: true })
|
|
ids!: string[];
|
|
}
|
|
|
|
export class BulkStatusDto {
|
|
@ApiProperty({ type: [String], format: 'uuid' })
|
|
@IsArray()
|
|
@ArrayNotEmpty()
|
|
@IsUUID('4', { each: true })
|
|
ids!: string[];
|
|
|
|
@ApiProperty({ enum: CORE_STATUSES })
|
|
@IsIn([...CORE_STATUSES])
|
|
status!: string;
|
|
}
|
|
|
|
export class ListVisitsQueryDto extends PaginationQueryDto {
|
|
@ApiPropertyOptional({ format: 'uuid' })
|
|
@IsOptional()
|
|
@IsUUID('4')
|
|
employeeId?: string;
|
|
|
|
@ApiPropertyOptional({ format: 'uuid' })
|
|
@IsOptional()
|
|
@IsUUID('4')
|
|
customerId?: string;
|
|
|
|
@ApiPropertyOptional({ description: 'Unix ms start of calendar day' })
|
|
@IsOptional()
|
|
@IsNumber()
|
|
date?: number;
|
|
|
|
@ApiPropertyOptional({ enum: CORE_STATUSES })
|
|
@IsOptional()
|
|
@IsIn([...CORE_STATUSES])
|
|
status?: string;
|
|
|
|
@ApiPropertyOptional()
|
|
@IsOptional()
|
|
@IsString()
|
|
search?: string;
|
|
}
|
|
|
|
class RelationDto {
|
|
@ApiProperty({ format: 'uuid' })
|
|
id!: string;
|
|
|
|
@ApiProperty()
|
|
code!: string;
|
|
|
|
@ApiProperty()
|
|
name!: string;
|
|
}
|
|
|
|
class UserRelationDto {
|
|
@ApiProperty({ format: 'uuid' })
|
|
id!: string;
|
|
|
|
@ApiProperty()
|
|
username!: string;
|
|
}
|
|
|
|
export class VisitDto {
|
|
@ApiProperty({ format: 'uuid' })
|
|
id!: string;
|
|
|
|
@ApiProperty({ type: RelationDto })
|
|
employee!: RelationDto;
|
|
|
|
@ApiProperty({ type: RelationDto })
|
|
customer!: RelationDto;
|
|
|
|
@ApiProperty({ format: 'uuid', nullable: true })
|
|
attendanceId!: string | null;
|
|
|
|
@ApiProperty({ format: 'uuid', nullable: true })
|
|
planId!: string | null;
|
|
|
|
@ApiProperty({ format: 'uuid', nullable: true })
|
|
planDestinationId!: string | null;
|
|
|
|
@ApiProperty()
|
|
date!: number;
|
|
|
|
@ApiProperty()
|
|
checkInAt!: number;
|
|
|
|
@ApiProperty({ enum: CHECK_IN_METHODS })
|
|
checkInMethod!: string;
|
|
|
|
@ApiProperty()
|
|
checkInLatitude!: number;
|
|
|
|
@ApiProperty()
|
|
checkInLongitude!: number;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkInPhotoUrl!: string | null;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkInDistanceMeters!: number | null;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkOutAt!: number | null;
|
|
|
|
@ApiProperty({ enum: CHECK_IN_METHODS, nullable: true })
|
|
checkOutMethod!: string | null;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkOutLatitude!: number | null;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkOutLongitude!: number | null;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkOutPhotoUrl!: string | null;
|
|
|
|
@ApiProperty({ nullable: true })
|
|
checkOutDistanceMeters!: number | null;
|
|
|
|
@ApiProperty()
|
|
status!: string;
|
|
|
|
@ApiProperty()
|
|
createdAt!: number;
|
|
|
|
@ApiProperty()
|
|
updatedAt!: number;
|
|
|
|
@ApiProperty({ type: UserRelationDto })
|
|
createdBy!: UserRelationDto;
|
|
|
|
@ApiProperty({ type: UserRelationDto })
|
|
updatedBy!: UserRelationDto;
|
|
}
|