Files
trackgo-be/src/modules/field/visits/dto/visit.dto.ts
T
shancheas 365a37b8d2 Add attendance and visit management features with database schema updates
- 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.
2026-09-01 12:27:51 +07:00

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;
}