v3.5.4版本提交,修改api
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-08-21 16:22:53 +08:00
parent a01217539c
commit 62e61a9e63
21 changed files with 594 additions and 142 deletions
@@ -12,7 +12,7 @@ import {
mapSkuDto,
mapSpecAttrsDto,
pickDisplaySku,
resolveOrderSku,
resolveOrderSale,
} from './product-sku.util';
export type CatalogViewer = {
@@ -204,7 +204,7 @@ export class CatalogService {
});
}
/** 下单前校验:白名单商品仅全局测试白名单手机号可买;返回 SPU + 解析后的 SKU */
/** 下单前校验:白名单商品仅全局测试白名单手机号可买; SKU 时回落 SPU 字段 */
async assertPurchasable(
productId: bigint,
viewerPhone?: string | null,
@@ -224,8 +224,8 @@ export class CatalogService {
throw new BadRequestException('该商品暂不对当前账号开放');
}
}
const sku = resolveOrderSku(product.skus, skuId);
return { product, sku };
const sale = resolveOrderSale(product, product.skus ?? [], skuId);
return { product, sale };
}
async resolveUserPhone(userId: bigint): Promise<string | null> {
@@ -37,23 +37,79 @@ export function buildSpecText(
.join(' / ');
}
/** 下单用销售快照:有可售 SKU 则用 SKU,否则回落 SPU(旧客户端 / 未回填) */
export type OrderSaleSnapshot = {
skuId: bigint | null;
skuCode: string;
barcode69: string;
specText: string;
price: CommonProductSku['price'];
benefitAmount: CommonProductSku['benefitAmount'];
allowOnSitePickup: boolean;
allowOnlinePurchase: boolean;
allowCrossCityDelivery: boolean;
saleUnit: ProductSaleUnit;
bottlesPerUnit: number;
};
export function saleSnapshotFromProduct(product: CommonProductItem): OrderSaleSnapshot {
return {
skuId: null,
skuCode: product.skuCode,
barcode69: product.barcode69,
specText: product.spec,
price: product.price,
benefitAmount: product.benefitAmount,
allowOnSitePickup: product.allowOnSitePickup,
allowOnlinePurchase: product.allowOnlinePurchase,
allowCrossCityDelivery: product.allowCrossCityDelivery,
saleUnit: 'BOTTLE',
bottlesPerUnit: 1,
};
}
export function saleSnapshotFromSku(
sku: CommonProductSku,
product: CommonProductItem,
): OrderSaleSnapshot {
return {
skuId: sku.id,
skuCode: sku.skuCode,
barcode69: sku.barcode69,
specText: sku.specText || product.spec,
price: sku.price,
benefitAmount: sku.benefitAmount,
allowOnSitePickup: sku.allowOnSitePickup,
allowOnlinePurchase: sku.allowOnlinePurchase,
allowCrossCityDelivery: sku.allowCrossCityDelivery,
saleUnit: sku.saleUnit,
bottlesPerUnit: sku.bottlesPerUnit > 0 ? sku.bottlesPerUnit : sku.saleUnit === 'BOX' ? BOTTLES_PER_BOX : 1,
};
}
/**
* 解析下单 SKU:显式 skuId,或单可售自动回落;多可售且未传则 400。
* 现网兼容:
* - 不传 skuId:有可售 SKU 用默认/唯一可售;一个都没有则回落 SPU 字段(未回填也能下单)
* - 传入 skuId:按 SKU 校验(新客户端选规格)
* 不在旧接口上因「无 SKU」或「多规格未选」打断现网下单。
*/
export function resolveOrderSku(
export function resolveOrderSale(
product: CommonProductItem,
skus: CommonProductSku[],
skuId?: string | null,
): CommonProductSku {
const onSale = skus.filter(isSkuOnSale);
): OrderSaleSnapshot {
if (skuId) {
const found = skus.find((s) => s.id.toString() === String(skuId));
if (!found) throw new BadRequestException('规格不存在');
if (!isSkuOnSale(found)) throw new BadRequestException('该规格暂不可购买');
return found;
return saleSnapshotFromSku(found, product);
}
if (onSale.length === 1) return onSale[0];
if (onSale.length === 0) throw new BadRequestException('商品暂无可售规格');
throw new BadRequestException('请选择规格');
const onSale = skus.filter(isSkuOnSale);
if (onSale.length >= 1) {
const picked = onSale.find((s) => s.isDefault) ?? onSale[0];
return saleSnapshotFromSku(picked, product);
}
return saleSnapshotFromProduct(product);
}
/** 列表/拍平:优先默认可售 → 最低价可售 → 默认任意 → 任意 */