diff --git a/database/migrations/102_shipping_cost_group_pas_kraye.sql b/database/migrations/102_shipping_cost_group_pas_kraye.sql new file mode 100644 index 0000000..e2bb37b --- /dev/null +++ b/database/migrations/102_shipping_cost_group_pas_kraye.sql @@ -0,0 +1,4 @@ +-- Freight-collect (پس کرایه): shipping is free at checkout but labeled for the customer + +ALTER TABLE shipping_cost_groups + ADD COLUMN IF NOT EXISTS pas_kraye BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5df6f11..670fb8f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1268,6 +1268,7 @@ model ShippingCostGroup { sortOrder Int @default(0) @map("sort_order") isActive Boolean @default(true) @map("is_active") isDefault Boolean @default(false) @map("is_default") + pasKraye Boolean @default(false) @map("pas_kraye") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(6) business Business @relation(fields: [businessId], references: [id], onDelete: Cascade, onUpdate: NoAction) diff --git a/src/store/dto/shipping-cost-groups.dto.ts b/src/store/dto/shipping-cost-groups.dto.ts index ef575c6..ee91636 100644 --- a/src/store/dto/shipping-cost-groups.dto.ts +++ b/src/store/dto/shipping-cost-groups.dto.ts @@ -80,6 +80,10 @@ export class CreateShippingCostGroupDto { @Min(0) defaultAmount!: number; + @IsOptional() + @IsBoolean() + pasKraye?: boolean; + @IsOptional() @IsArray() @IsString({ each: true }) @@ -136,6 +140,10 @@ export class UpdateShippingCostGroupDto { @Min(0) defaultAmount?: number; + @IsOptional() + @IsBoolean() + pasKraye?: boolean; + @IsOptional() @IsArray() @IsString({ each: true }) diff --git a/src/store/shipping-cost-groups.service.ts b/src/store/shipping-cost-groups.service.ts index 1f888ca..309143f 100644 --- a/src/store/shipping-cost-groups.service.ts +++ b/src/store/shipping-cost-groups.service.ts @@ -120,6 +120,8 @@ export class ShippingCostGroupsService { dto.provinceExceptions ?? [], ); const isDefault = dto.isDefault === true; + const pasKraye = dto.pasKraye === true; + const defaultAmount = pasKraye ? 0 : dto.defaultAmount; const created = await this.prisma.$transaction(async (tx) => { if (isDefault) { @@ -136,7 +138,8 @@ export class ShippingCostGroupsService { nameEn: dto.nameEn.trim(), description: dto.description?.trim() || null, methods, - defaultAmount: dto.defaultAmount, + defaultAmount, + pasKraye, sortOrder: dto.sortOrder ?? 0, isActive: dto.isActive ?? true, isDefault, @@ -191,7 +194,13 @@ export class ShippingCostGroupsService { if (dto.methods !== undefined) { data.methods = this.normalizeMethods(dto.methods); } - if (dto.defaultAmount !== undefined) { + if (dto.pasKraye !== undefined) { + data.pasKraye = dto.pasKraye; + if (dto.pasKraye) { + data.defaultAmount = 0; + } + } + if (dto.defaultAmount !== undefined && dto.pasKraye !== true) { data.defaultAmount = dto.defaultAmount; } if (dto.sortOrder !== undefined) data.sortOrder = dto.sortOrder; @@ -319,6 +328,7 @@ export class ShippingCostGroupsService { methodId: string | null; methodLabel: string | null; amount: number; + pasKraye: boolean; itemNames: string[]; }>; }> { @@ -340,6 +350,7 @@ export class ShippingCostGroupsService { methodId: null, methodLabel: null, amount: 0, + pasKraye: false, itemNames: input.cartItems.map((item) => item.productName), }, ], @@ -357,6 +368,7 @@ export class ShippingCostGroupsService { methodId: null, methodLabel: null, amount: 0, + pasKraye: false, itemNames: input.cartItems.map((item) => item.productName), }, ], @@ -381,6 +393,7 @@ export class ShippingCostGroupsService { methodId: null, methodLabel: null, amount, + pasKraye: false, itemNames: input.cartItems.map((item) => item.productName), }, ], @@ -402,6 +415,7 @@ export class ShippingCostGroupsService { title: string; methods: ShippingMethodId[]; amount: number; + pasKraye: boolean; itemNames: string[]; isDefault: boolean; } @@ -419,17 +433,21 @@ export class ShippingCostGroupsService { if (existing) { existing.itemNames.push(item.productName); } else { + const pasKraye = group.pasKraye === true; buckets.set(group.id, { groupId: group.id, title: group.isDefault ? STORE_SHIPPING_TITLE : group.nameFa || group.nameEn, methods: group.methods, - amount: this.resolveProvinceAmount( - group.defaultAmount, - group.provinceExceptions, - provinceId, - ), + amount: pasKraye + ? 0 + : this.resolveProvinceAmount( + group.defaultAmount, + group.provinceExceptions, + provinceId, + ), + pasKraye, itemNames: [item.productName], isDefault: group.isDefault, }); @@ -442,6 +460,7 @@ export class ShippingCostGroupsService { title: STORE_SHIPPING_TITLE, methods: [], amount: 0, + pasKraye: false, itemNames: ungroupedNames, isDefault: true, }); @@ -459,6 +478,7 @@ export class ShippingCostGroupsService { methodId, methodLabel: methodId ? METHOD_LABELS_FA[methodId] : null, amount: bucket.amount, + pasKraye: bucket.pasKraye, itemNames: bucket.itemNames, }; }); @@ -506,6 +526,7 @@ export class ShippingCostGroupsService { nameEn: string; methods: ShippingMethodId[]; defaultAmount: number; + pasKraye: boolean; provinceExceptions?: Array<{ provinceId: string; amount: number }>; }>, categoryIds: string[], @@ -545,6 +566,7 @@ export class ShippingCostGroupsService { sortOrder: group.sortOrder, isActive: group.isActive, isDefault: group.isDefault, + pasKraye: group.pasKraye, categoryIds: group.categories.map((row) => row.categoryId.toString()), categories: group.categories.map((row) => ({ id: row.category.id.toString(),