feat(api): product families module with CRUD, auto-group, members, custom members and price overrides
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
import { ApiProperty, PartialType } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsNumberString,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
MaxLength,
|
||||
Min,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
export class CreateProductFamilyDto {
|
||||
@ApiProperty({ example: '180g纯棉T恤(成人款)' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(200)
|
||||
familyName!: string;
|
||||
|
||||
@ApiProperty({ required: false, example: 'DG001' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(100)
|
||||
familyCode?: string;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
familyImage?: string | null;
|
||||
|
||||
@ApiProperty({ required: false, example: '1' })
|
||||
@IsOptional()
|
||||
@IsNumberString()
|
||||
countryId?: string;
|
||||
|
||||
@ApiProperty({ required: false, example: '2' })
|
||||
@IsOptional()
|
||||
@IsNumberString()
|
||||
categoryId?: string;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description: '主链接 origin_good_id(canonical 详情与跳转兜底)',
|
||||
example: '123',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsNumberString()
|
||||
primaryOriginGoodId?: string;
|
||||
|
||||
@ApiProperty({ required: false, type: [String], example: ['123', '124'] })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsNumberString({}, { each: true })
|
||||
originGoodIds?: string[];
|
||||
}
|
||||
|
||||
export class PatchProductFamilyDto extends PartialType(CreateProductFamilyDto) {
|
||||
@ApiProperty({ required: false, description: 'false = 人工锁定,重算只置 stale' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
autoManaged?: boolean;
|
||||
}
|
||||
|
||||
export class QueryProductFamilyDto {
|
||||
@ApiProperty({ required: false, description: '匹配 familyName / familyCode' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
keyword?: string;
|
||||
|
||||
@ApiProperty({ required: false, default: 1 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
page?: number;
|
||||
|
||||
@ApiProperty({ required: false, default: 20 })
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
pageSize?: number;
|
||||
}
|
||||
|
||||
export class AutoGroupDto {
|
||||
@ApiProperty({ required: false, default: false, description: 'true = 实际建族' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
apply?: boolean;
|
||||
}
|
||||
|
||||
export class UpdateFamilyMembersDto {
|
||||
@ApiProperty({ required: false, type: [String] })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsNumberString({}, { each: true })
|
||||
addOriginGoodIds?: string[];
|
||||
|
||||
@ApiProperty({ required: false, type: [String] })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
@IsNumberString({}, { each: true })
|
||||
removeOriginGoodIds?: string[];
|
||||
}
|
||||
|
||||
export class CustomMemberVariantDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
sku!: string;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sizeId?: string | null;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
sizeName?: string | null;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
colorId?: string | null;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
colorName?: string | null;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
colorHex?: string | null;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
imageUrl?: string | null;
|
||||
|
||||
@ApiProperty({ example: '28.00' })
|
||||
@IsNumber()
|
||||
@Min(0.01)
|
||||
price!: number;
|
||||
}
|
||||
|
||||
export class CreateCustomMemberDto {
|
||||
@ApiProperty({ example: '美国(包邮)180g纯棉T恤-DG001-双面印花(自建)' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(300)
|
||||
goodName!: string;
|
||||
|
||||
@ApiProperty({ required: false, nullable: true })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
goodImage?: string | null;
|
||||
|
||||
@ApiProperty({ description: '物流归因(价格矩阵维度,必填)', example: '包邮' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(100)
|
||||
logisticsLabel!: string;
|
||||
|
||||
@ApiProperty({ description: '工艺/印花数量归因(价格矩阵维度,必填)', example: '双面印花' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@MaxLength(100)
|
||||
craftLabel!: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
skuCode?: string;
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
warehouseLabel?: string;
|
||||
|
||||
@ApiProperty({ type: [CustomMemberVariantDto], minItems: 1 })
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CustomMemberVariantDto)
|
||||
variants!: CustomMemberVariantDto[];
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
type: Object,
|
||||
description: '可选人工详情(尺码表/包装规则参与并集)',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
detail?: { sizeChart?: Record<string, unknown>; packageSpecs?: Record<string, unknown> };
|
||||
}
|
||||
|
||||
export class PriceOverrideItemDto {
|
||||
@ApiProperty({ example: 'size_S' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
sizeId!: string;
|
||||
|
||||
@ApiProperty({ example: 'color_blk' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
colorId!: string;
|
||||
|
||||
@ApiProperty({ example: '单面印花' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
craft!: string;
|
||||
|
||||
@ApiProperty({ example: '包邮' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
logistics!: string;
|
||||
|
||||
@ApiProperty({ example: '23.00' })
|
||||
@IsNumber()
|
||||
@Min(0.01)
|
||||
price!: number;
|
||||
|
||||
@ApiProperty({ required: false, description: '改价原因(审计)' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
note?: string;
|
||||
}
|
||||
|
||||
export class PutPriceOverridesDto {
|
||||
@ApiProperty({ type: [PriceOverrideItemDto] })
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => PriceOverrideItemDto)
|
||||
items!: PriceOverrideItemDto[];
|
||||
}
|
||||
|
||||
export class PriceOverrideCellDto {
|
||||
@ApiProperty({ example: 'size_S' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
sizeId!: string;
|
||||
|
||||
@ApiProperty({ example: 'color_blk' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
colorId!: string;
|
||||
|
||||
@ApiProperty({ example: '单面印花' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
craft!: string;
|
||||
|
||||
@ApiProperty({ example: '包邮' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
logistics!: string;
|
||||
}
|
||||
|
||||
export class DeletePriceOverridesDto {
|
||||
@ApiProperty({ type: [PriceOverrideCellDto] })
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => PriceOverrideCellDto)
|
||||
cells!: PriceOverrideCellDto[];
|
||||
}
|
||||
Reference in New Issue
Block a user