@pisell/pisellos 2.3.19 → 2.3.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -10
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +48 -31
- package/dist/modules/Order/types.d.ts +1 -0
- package/dist/modules/Order/utils.js +10 -2
- package/dist/modules/Product/index.d.ts +1 -1
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +392 -253
- package/dist/server/modules/order/types.d.ts +2 -0
- package/dist/server/modules/products/index.d.ts +5 -1
- package/dist/server/modules/products/index.js +383 -315
- package/dist/server/modules/products/types.d.ts +4 -0
- package/dist/solution/BaseSales/index.js +144 -127
- package/dist/solution/BaseSales/types.d.ts +2 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +5 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +34 -12
- package/lib/modules/Order/types.d.ts +1 -0
- package/lib/modules/Order/utils.js +10 -1
- package/lib/modules/Product/index.d.ts +1 -1
- package/lib/server/index.d.ts +4 -0
- package/lib/server/index.js +83 -2
- package/lib/server/modules/order/types.d.ts +2 -0
- package/lib/server/modules/products/index.d.ts +5 -1
- package/lib/server/modules/products/index.js +20 -0
- package/lib/server/modules/products/types.d.ts +4 -0
- package/lib/solution/BaseSales/index.js +40 -22
- package/lib/solution/BaseSales/types.d.ts +2 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +2 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -85,6 +85,8 @@ export interface BaseSalesOrderProduct extends BaseSalesOrderProductIdentity {
|
|
|
85
85
|
booking_uid?: string;
|
|
86
86
|
/** 多语言商品标题快照,随 tempOrder 提交到 checkout。 */
|
|
87
87
|
product_title?: BaseSalesLocalizedText;
|
|
88
|
+
/** 商品封面图快照,随 tempOrder 提交到 checkout。 */
|
|
89
|
+
product_cover?: string;
|
|
88
90
|
/**
|
|
89
91
|
* 行级扩展 metadata。价格相关的权威字段:
|
|
90
92
|
*
|
|
@@ -166,7 +166,8 @@ export function transformBaseProductToOrderProduct(params) {
|
|
|
166
166
|
source_product_price: sourceProductPrice,
|
|
167
167
|
main_product_selling_price: mainProductSellingPrice,
|
|
168
168
|
main_product_original_price: mainProductOriginalPrice,
|
|
169
|
-
price_schema_version: 2
|
|
169
|
+
price_schema_version: 2,
|
|
170
|
+
holder_config: sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct.holder_config
|
|
170
171
|
}, hasPriceOverride ? {
|
|
171
172
|
price_override: String(payload.price_override),
|
|
172
173
|
is_manual_discount: 1
|
|
@@ -198,6 +199,7 @@ export function transformBaseProductToOrderProduct(params) {
|
|
|
198
199
|
metadata: metadata,
|
|
199
200
|
note: payload.note != null ? String(payload.note) : '',
|
|
200
201
|
product_title: productTitle,
|
|
202
|
+
product_cover: sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct.cover,
|
|
201
203
|
_origin: _objectSpread(_objectSpread({}, sourceProduct || {}), {}, {
|
|
202
204
|
callbackData: payload
|
|
203
205
|
})
|
|
@@ -358,7 +358,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
358
358
|
};
|
|
359
359
|
setOtherData(key: string, value: any): void;
|
|
360
360
|
getOtherData(key: string): any;
|
|
361
|
-
getProductTypeById(id: number): Promise<"
|
|
361
|
+
getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
|
|
362
362
|
/**
|
|
363
363
|
* 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
|
|
364
364
|
*
|
|
@@ -136,6 +136,9 @@ function resolveProductTitle(product, booking, sourceProduct) {
|
|
|
136
136
|
const metadata = product.metadata || {};
|
|
137
137
|
return (sourceProduct == null ? void 0 : sourceProduct.title) ?? (sourceProduct == null ? void 0 : sourceProduct.name) ?? metadata.product_title ?? metadata.product_name ?? ((_a = booking == null ? void 0 : booking.product) == null ? void 0 : _a.title) ?? ((_b = booking == null ? void 0 : booking.detail) == null ? void 0 : _b.product_title) ?? "";
|
|
138
138
|
}
|
|
139
|
+
function resolveProductCover(product, booking, sourceProduct) {
|
|
140
|
+
return (sourceProduct == null ? void 0 : sourceProduct.cover) ?? product.product_cover ?? "";
|
|
141
|
+
}
|
|
139
142
|
function resolveMainProductPrice(product, fallback) {
|
|
140
143
|
const metadata = product.metadata || {};
|
|
141
144
|
const value = metadata.main_product_original_price ?? metadata.source_product_price;
|
|
@@ -195,6 +198,7 @@ function buildCacheItemFromOrderLine(input) {
|
|
|
195
198
|
const capacity = resolveCapacityFromBooking(booking);
|
|
196
199
|
const holderId = ((_a = booking.metadata) == null ? void 0 : _a.holder_id) ?? booking.holder_id;
|
|
197
200
|
const productTitle = resolveProductTitle(product, booking, sourceProduct);
|
|
201
|
+
const productCover = resolveProductCover(product, booking, sourceProduct);
|
|
198
202
|
const productOptionString = (0, import_orderLineDisplay.buildProductOptionStringFromOrderLine)(product);
|
|
199
203
|
const other = {
|
|
200
204
|
product_variant_id: product.product_variant_id ?? 0,
|
|
@@ -214,6 +218,7 @@ function buildCacheItemFromOrderLine(input) {
|
|
|
214
218
|
sub_type: booking.sub_type,
|
|
215
219
|
quantity: product.num ?? 1,
|
|
216
220
|
product_name: productTitle,
|
|
221
|
+
product_cover: productCover,
|
|
217
222
|
note: product.note ?? ((_b = booking == null ? void 0 : booking.detail) == null ? void 0 : _b.note) ?? "",
|
|
218
223
|
price: mainProductPrice,
|
|
219
224
|
total: selling,
|
|
@@ -136,6 +136,7 @@ function buildNormalProductCacheItemFromOrderLine(input) {
|
|
|
136
136
|
product_id: resolvedId,
|
|
137
137
|
_id: uid,
|
|
138
138
|
title: (sourceProduct == null ? void 0 : sourceProduct.title) ?? product.product_title ?? "",
|
|
139
|
+
cover: (sourceProduct == null ? void 0 : sourceProduct.cover) ?? product.product_cover ?? "",
|
|
139
140
|
price: (sourceProduct == null ? void 0 : sourceProduct.price) ?? sourcePrice,
|
|
140
141
|
selling_price: product.selling_price,
|
|
141
142
|
original_price: product.original_price,
|
|
@@ -463,7 +463,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
463
463
|
generateIdempotencyToken(): string;
|
|
464
464
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|
|
465
465
|
createOrder(params: CommitOrderParams['query']): {
|
|
466
|
-
type: "
|
|
466
|
+
type: "appointment_booking" | "virtual";
|
|
467
467
|
platform: string;
|
|
468
468
|
sales_channel: string;
|
|
469
469
|
order_sales_channel: string;
|
|
@@ -547,7 +547,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
547
547
|
};
|
|
548
548
|
}
|
|
549
549
|
applyDiscount(options) {
|
|
550
|
-
var _a, _b, _c
|
|
550
|
+
var _a, _b, _c;
|
|
551
551
|
const tempOrder = this.store.tempOrder;
|
|
552
552
|
if (!tempOrder)
|
|
553
553
|
return;
|
|
@@ -560,13 +560,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
560
560
|
const rulesModule = this.store.rules;
|
|
561
561
|
if (!rulesModule)
|
|
562
562
|
return;
|
|
563
|
-
const holders = ((_b = tempOrder.holder) == null ? void 0 : _b.form_record) || [];
|
|
564
563
|
const result = rulesModule.calcDiscount({
|
|
565
564
|
productList: tempOrder.products,
|
|
566
565
|
discountList,
|
|
567
|
-
holders,
|
|
566
|
+
holders: [],
|
|
568
567
|
isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
|
|
569
|
-
orderTotalAmount: Number(((
|
|
568
|
+
orderTotalAmount: Number(((_b = this.store.summary) == null ? void 0 : _b.total_amount) || 0)
|
|
570
569
|
}, {
|
|
571
570
|
reapplyBookingDiscountProductUids: options == null ? void 0 : options.reapplyBookingDiscountProductUids
|
|
572
571
|
});
|
|
@@ -597,7 +596,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
597
596
|
result.productList || tempOrder.products,
|
|
598
597
|
result.discountList
|
|
599
598
|
);
|
|
600
|
-
(
|
|
599
|
+
(_c = this.store.discount) == null ? void 0 : _c.setDiscountList(result.discountList);
|
|
601
600
|
}
|
|
602
601
|
this.hasActiveCustomerBoundDiscount = (tempOrder.products || []).some(
|
|
603
602
|
(product) => this.productHasCustomerBoundDiscount(product)
|
|
@@ -1489,6 +1488,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1489
1488
|
}
|
|
1490
1489
|
restoreOriginalSnapshotIfProductsUnchanged(tempOrder, snapshot) {
|
|
1491
1490
|
const currentFingerprint = this.buildOrderProductsFingerprint(tempOrder.products);
|
|
1491
|
+
const manualDepositOverride = this.getManualDepositOverride(tempOrder);
|
|
1492
1492
|
if (currentFingerprint !== snapshot.productFingerprint) {
|
|
1493
1493
|
const currentStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(tempOrder.products);
|
|
1494
1494
|
const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(
|
|
@@ -1497,11 +1497,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1497
1497
|
if (currentStructuralFingerprint !== snapshotStructuralFingerprint)
|
|
1498
1498
|
return null;
|
|
1499
1499
|
}
|
|
1500
|
-
|
|
1500
|
+
let summary = {
|
|
1501
1501
|
...(0, import_utils.createEmptySummary)(),
|
|
1502
1502
|
...(0, import_lodash_es.cloneDeep)(snapshot.summary || {})
|
|
1503
1503
|
};
|
|
1504
|
-
|
|
1504
|
+
const shouldUseManualDepositOverride = Boolean(
|
|
1505
|
+
manualDepositOverride && manualDepositOverride.productStructuralFingerprint === this.buildOrderProductsStructuralFingerprint(tempOrder.products)
|
|
1506
|
+
);
|
|
1507
|
+
if (shouldUseManualDepositOverride) {
|
|
1508
|
+
summary = this.applyDepositAmountToSummary(
|
|
1509
|
+
tempOrder,
|
|
1510
|
+
summary,
|
|
1511
|
+
manualDepositOverride.amount
|
|
1512
|
+
);
|
|
1513
|
+
} else if (manualDepositOverride) {
|
|
1514
|
+
this.clearManualDepositOverride(tempOrder);
|
|
1515
|
+
}
|
|
1516
|
+
const isPayableAmountUnchanged = this.isSnapshotPayableAmountUnchanged(tempOrder, snapshot, summary);
|
|
1517
|
+
if (!isPayableAmountUnchanged)
|
|
1505
1518
|
return null;
|
|
1506
1519
|
if (Array.isArray(snapshot.products)) {
|
|
1507
1520
|
tempOrder.products = (0, import_lodash_es.cloneDeep)(snapshot.products);
|
|
@@ -3159,10 +3172,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3159
3172
|
if (!paramsList.length) {
|
|
3160
3173
|
return tempOrder.products;
|
|
3161
3174
|
}
|
|
3162
|
-
paramsList.
|
|
3163
|
-
this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
3175
|
+
const reapplyBookingDiscountProductUids = paramsList.reduce((acc, params) => {
|
|
3176
|
+
const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
3177
|
+
if (params.allow_booking_discount_reapply && updatedProductUid) {
|
|
3178
|
+
acc.push(String(updatedProductUid));
|
|
3179
|
+
}
|
|
3180
|
+
return acc;
|
|
3181
|
+
}, []);
|
|
3182
|
+
await this.finalizeAfterProductsMutation(tempOrder, {
|
|
3183
|
+
reapplyBookingDiscountProductUids: reapplyBookingDiscountProductUids.length ? reapplyBookingDiscountProductUids : void 0
|
|
3164
3184
|
});
|
|
3165
|
-
await this.finalizeAfterProductsMutation(tempOrder);
|
|
3166
3185
|
this.logInfo("updateOrderProduct success", {
|
|
3167
3186
|
paramsList
|
|
3168
3187
|
});
|
|
@@ -3271,10 +3290,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3271
3290
|
* @example
|
|
3272
3291
|
* await this.finalizeAfterProductsMutation(tempOrder);
|
|
3273
3292
|
*/
|
|
3274
|
-
async finalizeAfterProductsMutation(tempOrder) {
|
|
3293
|
+
async finalizeAfterProductsMutation(tempOrder, options) {
|
|
3275
3294
|
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
3276
3295
|
await this.applyPromotion();
|
|
3277
|
-
this.applyDiscount(
|
|
3296
|
+
this.applyDiscount({
|
|
3297
|
+
reapplyBookingDiscountProductUids: options == null ? void 0 : options.reapplyBookingDiscountProductUids
|
|
3298
|
+
});
|
|
3278
3299
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
3279
3300
|
await this.recalculateSummary({ createIfMissing: true });
|
|
3280
3301
|
this.persistTempOrder();
|
|
@@ -4213,6 +4234,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
4213
4234
|
if (!existingIdentity) {
|
|
4214
4235
|
row.metadata.unique_identification_number = (0, import_utils.createUuidV4)();
|
|
4215
4236
|
}
|
|
4237
|
+
row.metadata.is_edit_for_runtime = true;
|
|
4216
4238
|
const normalized = (0, import_utils3.normalizeOrderProduct)(row);
|
|
4217
4239
|
normalized.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
|
|
4218
4240
|
normalized.discount_list
|
|
@@ -803,6 +803,9 @@ function normalizeSubmitProduct(product) {
|
|
|
803
803
|
if (rawMetadata.is_rule !== void 0) {
|
|
804
804
|
cleanMetadata.is_rule = rawMetadata.is_rule;
|
|
805
805
|
}
|
|
806
|
+
if (rawMetadata.holder_config !== void 0) {
|
|
807
|
+
cleanMetadata.holder_config = rawMetadata.holder_config;
|
|
808
|
+
}
|
|
806
809
|
const productSku = {
|
|
807
810
|
...submitProduct.product_sku && typeof submitProduct.product_sku === "object" ? submitProduct.product_sku : {},
|
|
808
811
|
option: formatSubmitOptionItems((_a = submitProduct.product_sku) == null ? void 0 : _a.option)
|
|
@@ -1159,11 +1162,16 @@ function isHolderConfigRequired(holderConfig) {
|
|
|
1159
1162
|
return Number(holderConfig.required) === 1;
|
|
1160
1163
|
}
|
|
1161
1164
|
function productRequiresFormSubject(tempOrder, product) {
|
|
1165
|
+
var _a, _b;
|
|
1166
|
+
const _orderProduct = (_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.find((item) => {
|
|
1167
|
+
return item.metadata.unique_identification_number === product._id || item.product_id === product.id;
|
|
1168
|
+
});
|
|
1162
1169
|
const runtimeOrigin = getRuntimeProductOrigin(tempOrder, product);
|
|
1163
|
-
return isHolderConfigRequired(
|
|
1170
|
+
return isHolderConfigRequired((_b = _orderProduct == null ? void 0 : _orderProduct.metadata) == null ? void 0 : _b.holder_config) || isHolderConfigRequired(runtimeOrigin == null ? void 0 : runtimeOrigin.holder_config) || isHolderConfigRequired(product == null ? void 0 : product.holder_config);
|
|
1164
1171
|
}
|
|
1165
1172
|
function resolveIsFormSubject(tempOrder, product) {
|
|
1166
1173
|
var _a;
|
|
1174
|
+
debugger;
|
|
1167
1175
|
if (((_a = tempOrder == null ? void 0 : tempOrder.holder) == null ? void 0 : _a.type) === "form")
|
|
1168
1176
|
return true;
|
|
1169
1177
|
if (product)
|
|
@@ -1192,6 +1200,7 @@ function mergeOrderProductDisplayFields(previous, next) {
|
|
|
1192
1200
|
"product_name",
|
|
1193
1201
|
"product_cover",
|
|
1194
1202
|
"cover",
|
|
1203
|
+
"product_cover",
|
|
1195
1204
|
"variant_title",
|
|
1196
1205
|
"product_sku",
|
|
1197
1206
|
"payment_price"
|
|
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
|
|
|
49
49
|
getCategories(): ProductCategory[];
|
|
50
50
|
setOtherParams(key: string, value: any): void;
|
|
51
51
|
getOtherParams(): any;
|
|
52
|
-
getProductType(): "
|
|
52
|
+
getProductType(): "duration" | "session" | "normal";
|
|
53
53
|
}
|
package/lib/server/index.d.ts
CHANGED
|
@@ -445,6 +445,10 @@ declare class Server {
|
|
|
445
445
|
private sumPaidOrderPayments;
|
|
446
446
|
private toAmountNumber;
|
|
447
447
|
private buildSmallTicketProductMap;
|
|
448
|
+
private collectSalesDetailProductIds;
|
|
449
|
+
private buildSalesDetailProductSnapshotMap;
|
|
450
|
+
private withProductCatalogSnapshots;
|
|
451
|
+
private withSalesDetailProductSnapshots;
|
|
448
452
|
private withPendingSyncProductTitles;
|
|
449
453
|
private buildProductTitleSnapshot;
|
|
450
454
|
private getProductTitleSnapshotCurrentLocale;
|
package/lib/server/index.js
CHANGED
|
@@ -769,12 +769,13 @@ var Server = class {
|
|
|
769
769
|
if (!this.shouldForceRemoteSalesDetail(data)) {
|
|
770
770
|
const localOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
771
771
|
if (localOrder) {
|
|
772
|
+
const enrichedOrder = await this.withSalesDetailProductSnapshots(localOrder);
|
|
772
773
|
this.logInfo("handleOrderSalesDetail: 命中本地订单", { lookup });
|
|
773
774
|
return {
|
|
774
775
|
code: 200,
|
|
775
776
|
status: true,
|
|
776
777
|
message: "",
|
|
777
|
-
data:
|
|
778
|
+
data: enrichedOrder
|
|
778
779
|
};
|
|
779
780
|
}
|
|
780
781
|
}
|
|
@@ -821,11 +822,12 @@ var Server = class {
|
|
|
821
822
|
};
|
|
822
823
|
}
|
|
823
824
|
this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { lookup });
|
|
825
|
+
const enrichedOrder = await this.withSalesDetailProductSnapshots(savedOrder);
|
|
824
826
|
return {
|
|
825
827
|
code: 200,
|
|
826
828
|
status: true,
|
|
827
829
|
message: "",
|
|
828
|
-
data:
|
|
830
|
+
data: enrichedOrder
|
|
829
831
|
};
|
|
830
832
|
} catch (error) {
|
|
831
833
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -3231,6 +3233,85 @@ var Server = class {
|
|
|
3231
3233
|
return map;
|
|
3232
3234
|
}, {});
|
|
3233
3235
|
}
|
|
3236
|
+
collectSalesDetailProductIds(order) {
|
|
3237
|
+
const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
|
|
3238
|
+
const productIds = /* @__PURE__ */ new Set();
|
|
3239
|
+
products.forEach((product) => {
|
|
3240
|
+
const rawProductId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
|
|
3241
|
+
if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
|
|
3242
|
+
return;
|
|
3243
|
+
const productId = Number(rawProductId);
|
|
3244
|
+
if (Number.isFinite(productId))
|
|
3245
|
+
productIds.add(productId);
|
|
3246
|
+
});
|
|
3247
|
+
return Array.from(productIds);
|
|
3248
|
+
}
|
|
3249
|
+
async buildSalesDetailProductSnapshotMap(order) {
|
|
3250
|
+
var _a;
|
|
3251
|
+
const productIds = this.collectSalesDetailProductIds(order);
|
|
3252
|
+
const getSnapshots = (_a = this.products) == null ? void 0 : _a.getProductSnapshotsByIds;
|
|
3253
|
+
if (!productIds.length || typeof getSnapshots !== "function")
|
|
3254
|
+
return {};
|
|
3255
|
+
try {
|
|
3256
|
+
return await getSnapshots.call(this.products, productIds);
|
|
3257
|
+
} catch (error) {
|
|
3258
|
+
this.logWarning("buildSalesDetailProductSnapshotMap: 查询本地商品快照失败", {
|
|
3259
|
+
product_ids: productIds,
|
|
3260
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3261
|
+
});
|
|
3262
|
+
return {};
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
withProductCatalogSnapshots(product, snapshotMap) {
|
|
3266
|
+
if (!product || typeof product !== "object")
|
|
3267
|
+
return product;
|
|
3268
|
+
const rawProductId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
|
|
3269
|
+
if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
|
|
3270
|
+
return product;
|
|
3271
|
+
const productId = Number(rawProductId);
|
|
3272
|
+
if (!Number.isFinite(productId))
|
|
3273
|
+
return product;
|
|
3274
|
+
const snapshot = snapshotMap[String(productId)];
|
|
3275
|
+
if (!snapshot)
|
|
3276
|
+
return product;
|
|
3277
|
+
const shouldFillCover = (product.product_cover === void 0 || product.product_cover === null || product.product_cover === "") && snapshot.cover !== void 0 && snapshot.cover !== null && snapshot.cover !== "";
|
|
3278
|
+
const metadata = product.metadata && typeof product.metadata === "object" ? product.metadata : {};
|
|
3279
|
+
const shouldFillHolderConfig = (metadata.holder_config === void 0 || metadata.holder_config === null) && snapshot.holder_config !== void 0 && snapshot.holder_config !== null;
|
|
3280
|
+
if (!shouldFillCover && !shouldFillHolderConfig)
|
|
3281
|
+
return product;
|
|
3282
|
+
return {
|
|
3283
|
+
...product,
|
|
3284
|
+
...shouldFillCover ? { product_cover: snapshot.cover } : {},
|
|
3285
|
+
...shouldFillHolderConfig ? {
|
|
3286
|
+
metadata: {
|
|
3287
|
+
...metadata,
|
|
3288
|
+
holder_config: snapshot.holder_config
|
|
3289
|
+
}
|
|
3290
|
+
} : {}
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
async withSalesDetailProductSnapshots(order) {
|
|
3294
|
+
const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : null;
|
|
3295
|
+
if (!(products == null ? void 0 : products.length))
|
|
3296
|
+
return order;
|
|
3297
|
+
const snapshotMap = await this.buildSalesDetailProductSnapshotMap(order);
|
|
3298
|
+
if (!Object.keys(snapshotMap).length)
|
|
3299
|
+
return order;
|
|
3300
|
+
let hasChanged = false;
|
|
3301
|
+
const enrichedProducts = products.map((product) => {
|
|
3302
|
+
const nextProduct = this.withProductCatalogSnapshots(product, snapshotMap);
|
|
3303
|
+
if (nextProduct !== product)
|
|
3304
|
+
hasChanged = true;
|
|
3305
|
+
return nextProduct;
|
|
3306
|
+
});
|
|
3307
|
+
if (!hasChanged)
|
|
3308
|
+
return order;
|
|
3309
|
+
const enrichedOrder = {
|
|
3310
|
+
...order,
|
|
3311
|
+
products: enrichedProducts
|
|
3312
|
+
};
|
|
3313
|
+
return enrichedOrder;
|
|
3314
|
+
}
|
|
3234
3315
|
withPendingSyncProductTitles(order, productMap) {
|
|
3235
3316
|
const products = Array.isArray(order.products) ? order.products : null;
|
|
3236
3317
|
if (!(products == null ? void 0 : products.length))
|
|
@@ -104,6 +104,8 @@ export interface OrderProductLineItem {
|
|
|
104
104
|
num: number;
|
|
105
105
|
/** 商品标题快照;本地待同步订单会补齐为多语言对象。 */
|
|
106
106
|
product_title?: OrderProductTitleSnapshot | string | null;
|
|
107
|
+
/** 商品封面图 */
|
|
108
|
+
product_cover?: string | null;
|
|
107
109
|
/** 多规格 ID。来源:Detail.product_variant_id */
|
|
108
110
|
product_variant_id?: number;
|
|
109
111
|
/**
|
|
@@ -2,7 +2,7 @@ import { Module, PisellCore } from '../../../types';
|
|
|
2
2
|
import { BaseModule } from '../../../modules/BaseModule';
|
|
3
3
|
import { ProductData } from '../../../modules/Product/types';
|
|
4
4
|
import type { RouteDefinition } from '../../types';
|
|
5
|
-
import { ProductIdScope, ProductFormatter, ProductFormatterContext } from './types';
|
|
5
|
+
import { ProductIdScope, type ProductSnapshot, ProductFormatter, ProductFormatterContext } from './types';
|
|
6
6
|
/**
|
|
7
7
|
* Products 模块 - 用于获取和管理完整的商品详细数据
|
|
8
8
|
* 相比 ProductList 模块,Products 会获取所有详细信息并缓存
|
|
@@ -185,6 +185,10 @@ export declare class ProductsModule extends BaseModule implements Module {
|
|
|
185
185
|
* 获取商品列表(深拷贝,供外部安全使用)
|
|
186
186
|
*/
|
|
187
187
|
getProducts(): Promise<ProductData[]>;
|
|
188
|
+
/**
|
|
189
|
+
* 批量获取商品轻量快照,供订单详情等响应补齐展示协议字段。
|
|
190
|
+
*/
|
|
191
|
+
getProductSnapshotsByIds(ids: number[]): Promise<Record<string, ProductSnapshot>>;
|
|
188
192
|
/**
|
|
189
193
|
* 内部获取商品列表的直接引用(无拷贝)
|
|
190
194
|
* 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
|
|
@@ -860,6 +860,26 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
|
|
|
860
860
|
(0, import_product.perfMark)("ProductsModule.getProducts(structuredClone)", performance.now() - t0, { count: result.length });
|
|
861
861
|
return result;
|
|
862
862
|
}
|
|
863
|
+
/**
|
|
864
|
+
* 批量获取商品轻量快照,供订单详情等响应补齐展示协议字段。
|
|
865
|
+
*/
|
|
866
|
+
async getProductSnapshotsByIds(ids) {
|
|
867
|
+
const snapshots = {};
|
|
868
|
+
const seen = /* @__PURE__ */ new Set();
|
|
869
|
+
for (const id of ids) {
|
|
870
|
+
if (!Number.isFinite(id) || seen.has(id))
|
|
871
|
+
continue;
|
|
872
|
+
seen.add(id);
|
|
873
|
+
const product = this.store.map.get(id);
|
|
874
|
+
if (!product)
|
|
875
|
+
continue;
|
|
876
|
+
snapshots[String(id)] = {
|
|
877
|
+
cover: product.cover,
|
|
878
|
+
holder_config: product.holder_config
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
return snapshots;
|
|
882
|
+
}
|
|
863
883
|
/**
|
|
864
884
|
* 内部获取商品列表的直接引用(无拷贝)
|
|
865
885
|
* 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
|
|
@@ -102,7 +102,25 @@ function getBaseSalesMetadataUid(item, metadataKey) {
|
|
|
102
102
|
return null;
|
|
103
103
|
return String(uid);
|
|
104
104
|
}
|
|
105
|
-
function
|
|
105
|
+
function isBaseSalesBlankValue(value) {
|
|
106
|
+
return value === void 0 || value === null || value === "";
|
|
107
|
+
}
|
|
108
|
+
function mergeBaseSalesProductSnapshotFields(currentItem, loadedItem) {
|
|
109
|
+
var _a, _b, _c;
|
|
110
|
+
const mergedItem = (0, import_lodash_es.cloneDeep)(loadedItem);
|
|
111
|
+
if (isBaseSalesBlankValue(mergedItem.product_cover) && !isBaseSalesBlankValue(currentItem == null ? void 0 : currentItem.product_cover)) {
|
|
112
|
+
mergedItem.product_cover = currentItem.product_cover;
|
|
113
|
+
}
|
|
114
|
+
const currentHolderConfig = (_a = currentItem == null ? void 0 : currentItem.metadata) == null ? void 0 : _a.holder_config;
|
|
115
|
+
if ((((_b = mergedItem.metadata) == null ? void 0 : _b.holder_config) === void 0 || ((_c = mergedItem.metadata) == null ? void 0 : _c.holder_config) === null) && currentHolderConfig !== void 0 && currentHolderConfig !== null) {
|
|
116
|
+
mergedItem.metadata = {
|
|
117
|
+
...mergedItem.metadata || {},
|
|
118
|
+
holder_config: currentHolderConfig
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
return mergedItem;
|
|
122
|
+
}
|
|
123
|
+
function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey, arrayKey) {
|
|
106
124
|
const result = [];
|
|
107
125
|
const indexByUid = /* @__PURE__ */ new Map();
|
|
108
126
|
const appendOrReplaceByUid = (item) => {
|
|
@@ -114,7 +132,7 @@ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
|
|
|
114
132
|
}
|
|
115
133
|
const existingIndex = indexByUid.get(uid);
|
|
116
134
|
if (existingIndex !== void 0) {
|
|
117
|
-
result[existingIndex] = clonedItem;
|
|
135
|
+
result[existingIndex] = arrayKey === "products" ? mergeBaseSalesProductSnapshotFields(result[existingIndex], clonedItem) : clonedItem;
|
|
118
136
|
return;
|
|
119
137
|
}
|
|
120
138
|
indexByUid.set(uid, result.length);
|
|
@@ -134,7 +152,7 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord) {
|
|
|
134
152
|
if (Array.isArray(currentValue) && Array.isArray(loadedValue)) {
|
|
135
153
|
const metadataKey = getBaseSalesUniqueArrayMetadataKey(key);
|
|
136
154
|
if (metadataKey) {
|
|
137
|
-
return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey);
|
|
155
|
+
return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey, key);
|
|
138
156
|
}
|
|
139
157
|
return [
|
|
140
158
|
...(0, import_lodash_es.cloneDeep)(currentValue),
|
|
@@ -260,7 +278,10 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
260
278
|
if (!this.store.order)
|
|
261
279
|
return;
|
|
262
280
|
this.serverOrderChangeHydrateInFlight = (async () => {
|
|
263
|
-
|
|
281
|
+
var _a, _b;
|
|
282
|
+
const currentTempOrder = (_b = (_a = this.store.order).getTempOrder) == null ? void 0 : _b.call(_a);
|
|
283
|
+
const record = mergeSalesDetailRecordWithTempOrder(currentTempOrder, changedOrder);
|
|
284
|
+
const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
|
|
264
285
|
recalcOnHydrate: false
|
|
265
286
|
});
|
|
266
287
|
this.currentSalesDetail = sales;
|
|
@@ -1094,7 +1115,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1094
1115
|
});
|
|
1095
1116
|
}
|
|
1096
1117
|
async loadDiscountConfig(params) {
|
|
1097
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r
|
|
1118
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
1098
1119
|
if (!this.store.order)
|
|
1099
1120
|
throw new Error("order 模块未初始化");
|
|
1100
1121
|
const tempOrder = this.store.order.ensureTempOrder();
|
|
@@ -1165,13 +1186,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1165
1186
|
};
|
|
1166
1187
|
}
|
|
1167
1188
|
if (rulesModule) {
|
|
1168
|
-
const
|
|
1169
|
-
const orderTotalAmount = Number(((_m = orderStore.summary) == null ? void 0 : _m.total_amount) || 0);
|
|
1189
|
+
const orderTotalAmount = Number(((_l = orderStore.summary) == null ? void 0 : _l.total_amount) || 0);
|
|
1170
1190
|
console.log("[BaseSales.applyDiscountConfig.calcDiscount]");
|
|
1171
1191
|
const result = rulesModule.calcDiscount({
|
|
1172
1192
|
productList: tempOrder.products,
|
|
1173
1193
|
discountList: nextDiscountList,
|
|
1174
|
-
holders,
|
|
1194
|
+
holders: [],
|
|
1175
1195
|
isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
|
|
1176
1196
|
orderTotalAmount
|
|
1177
1197
|
}) || { productList: tempOrder.products, discountList: nextDiscountList };
|
|
@@ -1182,8 +1202,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1182
1202
|
);
|
|
1183
1203
|
}
|
|
1184
1204
|
for (const product of tempOrder.products || []) {
|
|
1185
|
-
const productUid = (
|
|
1186
|
-
const runtimeOrigin = productUid ? (
|
|
1205
|
+
const productUid = (_m = product.metadata) == null ? void 0 : _m.unique_identification_number;
|
|
1206
|
+
const runtimeOrigin = productUid ? (_p = (_o = (_n = tempOrder._extend) == null ? void 0 : _n.productsByUid) == null ? void 0 : _o[productUid]) == null ? void 0 : _p.origin : void 0;
|
|
1187
1207
|
if ((runtimeOrigin == null ? void 0 : runtimeOrigin.isManualDiscount) || isBaseSalesManualProductDiscountProduct(product))
|
|
1188
1208
|
continue;
|
|
1189
1209
|
const totalPerUnitDiscount = (product.discount_list || []).reduce(
|
|
@@ -1191,7 +1211,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1191
1211
|
0
|
|
1192
1212
|
);
|
|
1193
1213
|
const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
|
|
1194
|
-
const sourcePrice = ((
|
|
1214
|
+
const sourcePrice = ((_q = product.metadata) == null ? void 0 : _q.source_product_price) ?? (((_r = product.metadata) == null ? void 0 : _r.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
|
|
1195
1215
|
const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
|
|
1196
1216
|
const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
1197
1217
|
if (product.metadata) {
|
|
@@ -1227,7 +1247,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1227
1247
|
};
|
|
1228
1248
|
}
|
|
1229
1249
|
async bestDiscount(cb) {
|
|
1230
|
-
var _a, _b, _c
|
|
1250
|
+
var _a, _b, _c;
|
|
1231
1251
|
if (!this.store.order)
|
|
1232
1252
|
throw new Error("order 模块未初始化");
|
|
1233
1253
|
const tempOrder = this.store.order.ensureTempOrder();
|
|
@@ -1246,13 +1266,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1246
1266
|
};
|
|
1247
1267
|
await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
|
|
1248
1268
|
if (rulesModule) {
|
|
1249
|
-
const
|
|
1250
|
-
const orderTotalAmount = Number(((_d = orderStore.summary) == null ? void 0 : _d.total_amount) || 0);
|
|
1269
|
+
const orderTotalAmount = Number(((_c = orderStore.summary) == null ? void 0 : _c.total_amount) || 0);
|
|
1251
1270
|
console.log("[BaseSales.bestDiscount.calcDiscount]");
|
|
1252
1271
|
result = rulesModule.calcDiscount({
|
|
1253
1272
|
productList: tempOrder.products,
|
|
1254
1273
|
discountList: nextDiscountList,
|
|
1255
|
-
holders,
|
|
1274
|
+
holders: [],
|
|
1256
1275
|
isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
|
|
1257
1276
|
orderTotalAmount
|
|
1258
1277
|
}) || result;
|
|
@@ -1306,7 +1325,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1306
1325
|
}
|
|
1307
1326
|
// TODO 需要优化,这段逻辑太长了,里面应该有些历史遗留问题
|
|
1308
1327
|
async setDiscountSelected(params) {
|
|
1309
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
1328
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1310
1329
|
try {
|
|
1311
1330
|
if (!this.store.order)
|
|
1312
1331
|
throw new Error("order 模块未初始化");
|
|
@@ -1323,17 +1342,16 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1323
1342
|
const orderStore = this.store.order.store || {};
|
|
1324
1343
|
const discountModule = orderStore.discount;
|
|
1325
1344
|
const rulesModule = orderStore.rules;
|
|
1326
|
-
const holders = ((_a = tempOrder.holder) == null ? void 0 : _a.form_record) || [];
|
|
1327
1345
|
let nextDiscountList = updated;
|
|
1328
1346
|
await (discountModule == null ? void 0 : discountModule.setDiscountList(updated));
|
|
1329
1347
|
if (rulesModule) {
|
|
1330
|
-
const orderTotalAmount = Number(((
|
|
1348
|
+
const orderTotalAmount = Number(((_a = orderStore.summary) == null ? void 0 : _a.total_amount) || 0);
|
|
1331
1349
|
console.log("[BaseSales.setDiscountSelected.calcDiscount]");
|
|
1332
1350
|
const result = rulesModule.calcDiscount(
|
|
1333
1351
|
{
|
|
1334
1352
|
productList: tempOrder.products,
|
|
1335
1353
|
discountList: updated,
|
|
1336
|
-
holders,
|
|
1354
|
+
holders: [],
|
|
1337
1355
|
isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
|
|
1338
1356
|
orderTotalAmount
|
|
1339
1357
|
},
|
|
@@ -1373,8 +1391,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1373
1391
|
return rid != null && selectedResourceIds.has(rid);
|
|
1374
1392
|
});
|
|
1375
1393
|
for (const product of tempOrder.products) {
|
|
1376
|
-
const productUid = (
|
|
1377
|
-
const runtimeOrigin = productUid ? (
|
|
1394
|
+
const productUid = (_b = product.metadata) == null ? void 0 : _b.unique_identification_number;
|
|
1395
|
+
const runtimeOrigin = productUid ? (_e = (_d = (_c = tempOrder._extend) == null ? void 0 : _c.productsByUid) == null ? void 0 : _d[productUid]) == null ? void 0 : _e.origin : void 0;
|
|
1378
1396
|
if ((runtimeOrigin == null ? void 0 : runtimeOrigin.isManualDiscount) || isBaseSalesManualProductDiscountProduct(product))
|
|
1379
1397
|
continue;
|
|
1380
1398
|
product.discount_list = filterSelectedDiscountDetails(product.discount_list);
|
|
@@ -1398,7 +1416,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
|
|
|
1398
1416
|
0
|
|
1399
1417
|
);
|
|
1400
1418
|
const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
|
|
1401
|
-
const sourcePrice = ((
|
|
1419
|
+
const sourcePrice = ((_f = product.metadata) == null ? void 0 : _f.source_product_price) ?? (((_g = product.metadata) == null ? void 0 : _g.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
|
|
1402
1420
|
const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
|
|
1403
1421
|
const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
1404
1422
|
if (product.metadata) {
|
|
@@ -85,6 +85,8 @@ export interface BaseSalesOrderProduct extends BaseSalesOrderProductIdentity {
|
|
|
85
85
|
booking_uid?: string;
|
|
86
86
|
/** 多语言商品标题快照,随 tempOrder 提交到 checkout。 */
|
|
87
87
|
product_title?: BaseSalesLocalizedText;
|
|
88
|
+
/** 商品封面图快照,随 tempOrder 提交到 checkout。 */
|
|
89
|
+
product_cover?: string;
|
|
88
90
|
/**
|
|
89
91
|
* 行级扩展 metadata。价格相关的权威字段:
|
|
90
92
|
*
|
|
@@ -198,6 +198,7 @@ function transformBaseProductToOrderProduct(params) {
|
|
|
198
198
|
main_product_selling_price: mainProductSellingPrice,
|
|
199
199
|
main_product_original_price: mainProductOriginalPrice,
|
|
200
200
|
price_schema_version: 2,
|
|
201
|
+
holder_config: sourceProduct == null ? void 0 : sourceProduct.holder_config,
|
|
201
202
|
...hasPriceOverride ? {
|
|
202
203
|
price_override: String(payload.price_override),
|
|
203
204
|
is_manual_discount: 1
|
|
@@ -236,6 +237,7 @@ function transformBaseProductToOrderProduct(params) {
|
|
|
236
237
|
metadata,
|
|
237
238
|
note: payload.note != null ? String(payload.note) : "",
|
|
238
239
|
product_title: productTitle,
|
|
240
|
+
product_cover: sourceProduct == null ? void 0 : sourceProduct.cover,
|
|
239
241
|
_origin: {
|
|
240
242
|
...sourceProduct || {},
|
|
241
243
|
callbackData: payload
|