Files
trackgo-be/src/modules/sales/packing-slips/dto/packing-slip.dto.ts
T
shancheas 0e73d14381 Add address fields to sales invoices and implement related validations
- Introduced new columns `address`, `latitude`, and `longitude` in the `sales_invoices` table to store location details.
- Updated the `SalesInvoicesService` to handle the new fields, including validation for address format and geographical coordinates.
- Enhanced the `SalesInvoiceDto` and related data transfer objects to include the new fields for API requests and responses.
- Added unit and e2e tests to ensure proper handling of the new fields and validate their integration within the sales invoice workflow.
- Created a new migration script to apply the database schema changes for the sales invoices.
2026-09-01 09:50:19 +07:00

265 lines
5.6 KiB
TypeScript

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import {
ArrayNotEmpty,
IsArray,
IsIn,
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
IsUUID,
Matches,
Max,
MaxLength,
Min,
ValidateNested,
} from 'class-validator';
import {
CodeRelationDto,
DefaultRelationDto,
PaginationQueryDto,
parseQueryIdList,
UserRelationDto,
} from '../../../../common/http/response';
import {
DOCUMENT_ADDRESS_MAX_LENGTH,
DOCUMENT_CODE_MAX_LENGTH,
DOCUMENT_CODE_PATTERN,
DOCUMENT_NOTES_MAX_LENGTH,
PACKING_SLIP_STATUSES,
} from '../../shared/sales-fields';
export class SalesLineDto {
@ApiProperty({ format: 'uuid' })
@IsUUID('4')
productId!: string;
@ApiProperty({ example: '2.0000' })
@IsString()
@IsNotEmpty()
quantity!: string;
@ApiPropertyOptional({ example: '12500.0000' })
@IsOptional()
@IsString()
price?: string;
}
export class CreatePackingSlipDto {
@ApiPropertyOptional({ example: 'PS-20260824-0001' })
@IsOptional()
@IsString()
@MaxLength(DOCUMENT_CODE_MAX_LENGTH)
@Matches(DOCUMENT_CODE_PATTERN)
code?: string;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID('4')
salesOrderId?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
salesOrderNumber?: string;
@ApiPropertyOptional({ example: '2026-08-24T10:00:00+07:00' })
@IsOptional()
@IsString()
date?: string;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID('4')
customerId?: string;
@ApiPropertyOptional({ example: 'Jl Sudirman 1' })
@IsOptional()
@IsString()
@MaxLength(DOCUMENT_ADDRESS_MAX_LENGTH)
address?: string;
@ApiPropertyOptional()
@IsOptional()
@IsNumber()
@Min(-90)
@Max(90)
latitude?: number;
@ApiPropertyOptional()
@IsOptional()
@IsNumber()
@Min(-180)
@Max(180)
longitude?: number;
@ApiPropertyOptional()
@IsOptional()
@IsString()
@MaxLength(DOCUMENT_NOTES_MAX_LENGTH)
notes?: string;
@ApiPropertyOptional({ type: [SalesLineDto] })
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => SalesLineDto)
products?: SalesLineDto[];
@ApiPropertyOptional({ enum: PACKING_SLIP_STATUSES })
@IsOptional()
@IsIn([...PACKING_SLIP_STATUSES])
status?: string;
}
export class UpdatePackingSlipDto {
@ApiPropertyOptional()
@IsOptional()
@IsString()
@MaxLength(DOCUMENT_CODE_MAX_LENGTH)
@Matches(DOCUMENT_CODE_PATTERN)
code?: string;
@ApiPropertyOptional({ format: 'uuid', nullable: true })
@IsOptional()
@IsUUID('4')
salesOrderId?: string | null;
@ApiPropertyOptional()
@IsOptional()
@IsString()
date?: string;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID('4')
customerId?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
@MaxLength(DOCUMENT_ADDRESS_MAX_LENGTH)
address?: string;
@ApiPropertyOptional({ nullable: true })
@IsOptional()
@IsNumber()
latitude?: number | null;
@ApiPropertyOptional({ nullable: true })
@IsOptional()
@IsNumber()
longitude?: number | null;
@ApiPropertyOptional({ nullable: true })
@IsOptional()
@IsString()
notes?: string | null;
@ApiPropertyOptional({ type: [SalesLineDto] })
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => SalesLineDto)
products?: SalesLineDto[];
}
export class UpdatePackingSlipStatusDto {
@ApiProperty({ enum: PACKING_SLIP_STATUSES })
@IsIn([...PACKING_SLIP_STATUSES])
status!: string;
@ApiPropertyOptional({ type: [SalesLineDto] })
@IsOptional()
@IsArray()
@ValidateNested({ each: true })
@Type(() => SalesLineDto)
products?: SalesLineDto[];
}
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: PACKING_SLIP_STATUSES })
@IsIn([...PACKING_SLIP_STATUSES])
status!: string;
}
export class ListPackingSlipsQueryDto extends PaginationQueryDto {
@ApiPropertyOptional()
@IsOptional()
@IsString()
code?: string;
@ApiPropertyOptional({ enum: PACKING_SLIP_STATUSES })
@IsOptional()
@IsIn([...PACKING_SLIP_STATUSES])
status?: string;
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID('4')
customerId?: string;
@ApiPropertyOptional({ type: [String], format: 'uuid' })
@IsOptional()
@Transform(({ value }) => parseQueryIdList(value))
@IsArray()
@IsUUID('4', { each: true })
customerIds?: string[];
@ApiPropertyOptional({ format: 'uuid' })
@IsOptional()
@IsUUID('4')
salesOrderId?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
search?: string;
}
export class PackingSlipDto {
@ApiProperty({ format: 'uuid' })
id!: string;
@ApiProperty()
code!: string;
@ApiPropertyOptional({ type: CodeRelationDto, nullable: true })
salesOrder!: CodeRelationDto | null;
@ApiProperty()
date!: number;
@ApiProperty({ type: DefaultRelationDto, nullable: true })
customer!: DefaultRelationDto | null;
@ApiProperty()
address!: string;
@ApiPropertyOptional({ nullable: true })
latitude!: number | null;
@ApiPropertyOptional({ nullable: true })
longitude!: number | null;
@ApiPropertyOptional({ nullable: true })
notes!: string | null;
@ApiProperty({ enum: PACKING_SLIP_STATUSES })
status!: string;
@ApiProperty()
createdAt!: number;
@ApiProperty()
updatedAt!: number;
@ApiProperty({ type: UserRelationDto })
createdBy!: UserRelationDto;
@ApiProperty({ type: UserRelationDto })
updatedBy!: UserRelationDto;
}