@pisell/pisellos 2.3.75 → 2.3.76
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/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +39 -27
- package/dist/modules/Order/types.d.ts +3 -1
- package/dist/solution/BaseSales/index.js +62 -31
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
- package/dist/solution/BaseSales/utils/cartPromotion.js +15 -6
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +23 -6
- package/lib/modules/Order/types.d.ts +3 -1
- package/lib/solution/BaseSales/index.js +40 -8
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +5 -0
- package/lib/solution/BaseSales/utils/cartPromotion.js +11 -1
- package/package.json +1 -1
|
@@ -562,7 +562,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
562
562
|
*/
|
|
563
563
|
hydrateTempOrderFromRecord(record: Record<string, any>, options?: {
|
|
564
564
|
recalcOnHydrate?: boolean;
|
|
565
|
-
source?: 'salesDetail' | 'sessionStorage';
|
|
565
|
+
source?: 'salesDetail' | 'mergedSalesDetail' | 'sessionStorage';
|
|
566
566
|
}): Promise<OrderTempOrder>;
|
|
567
567
|
/**
|
|
568
568
|
* 兼容后端详情将 holder 放在 metadata.holder 的历史形态,统一补到运行时展示路径。
|
|
@@ -37,7 +37,7 @@ import { isNormalProduct } from "../Product/utils";
|
|
|
37
37
|
import dayjs from 'dayjs';
|
|
38
38
|
import { ensureOrderPaymentNumber, mergeOrderPaymentRecord, resolveOrderPaymentIdentity } from "./payment-utils";
|
|
39
39
|
import { resolvePaymentNumberDevicePrefix, resolvePaymentNumberDevicePrefixFromDeviceId } from "../../utils/payment-number";
|
|
40
|
-
import { processCartPromotion, appendPromotionTags as _appendPromotionTags, getOrderProductUid as getPromotionUid } from "../../solution/BaseSales/utils/cartPromotion";
|
|
40
|
+
import { processCartPromotion, appendPromotionTags as _appendPromotionTags, getOrderProductUid as getPromotionUid, PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY } from "../../solution/BaseSales/utils/cartPromotion";
|
|
41
41
|
import { buildProductLineFingerprint, getProductIdentityIndex, getSafeProductNum, isIdentityMatch, normalizeOrderProduct } from "../../solution/ScanOrder/utils";
|
|
42
42
|
import { hasManualProductDiscountFlag, syncManualProductDiscountProductNum } from "./utils/manualProductDiscount";
|
|
43
43
|
import { expandHydratedProductsForDiscountCollection, restoreHydratedBundleDiscounts } from "./utils/bundleDiscountHydration";
|
|
@@ -2305,6 +2305,8 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
2305
2305
|
}, {
|
|
2306
2306
|
key: "restoreOriginalSnapshotIfProductsUnchanged",
|
|
2307
2307
|
value: function restoreOriginalSnapshotIfProductsUnchanged(tempOrder, snapshot) {
|
|
2308
|
+
// merge hydrate 的商品集合包含本地未提交行,但 summary 仍来自远端旧订单,不能复用。
|
|
2309
|
+
if (snapshot.requiresFullSummaryRecalculation === true) return null;
|
|
2308
2310
|
var currentFingerprint = this.buildOrderProductsFingerprint(tempOrder.products);
|
|
2309
2311
|
var manualDepositOverride = this.getManualDepositOverride(tempOrder);
|
|
2310
2312
|
if (currentFingerprint !== snapshot.productFingerprint) {
|
|
@@ -4018,8 +4020,12 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
4018
4020
|
booking: booking
|
|
4019
4021
|
}) : null;
|
|
4020
4022
|
var productToAdd = (linked === null || linked === void 0 ? void 0 : linked.product) || product;
|
|
4021
|
-
var
|
|
4023
|
+
var disableMerge = (options === null || options === void 0 ? void 0 : options.disableMerge) === true;
|
|
4024
|
+
var incomingFingerprint = disableMerge ? '' : buildProductLineFingerprint(getProductSkuOptions(productToAdd), productToAdd.product_bundle);
|
|
4022
4025
|
var normalizedIncoming = mergeOrderProductDisplayFields(productToAdd, normalizeOrderProduct(productToAdd));
|
|
4026
|
+
if (disableMerge) {
|
|
4027
|
+
normalizedIncoming.metadata = _objectSpread(_objectSpread({}, normalizedIncoming.metadata || {}), {}, _defineProperty({}, PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY, true));
|
|
4028
|
+
}
|
|
4023
4029
|
var isWeighingProduct = Number(((_normalizedIncoming$p = normalizedIncoming.product_sku) === null || _normalizedIncoming$p === void 0 ? void 0 : _normalizedIncoming$p.open_sold_weight) || 0) === 1;
|
|
4024
4030
|
var netWeight = Number((_normalizedIncoming$p2 = normalizedIncoming.product_sku) === null || _normalizedIncoming$p2 === void 0 ? void 0 : _normalizedIncoming$p2.net_weight);
|
|
4025
4031
|
if (isWeighingProduct && (!Number.isFinite(netWeight) || netWeight <= 0)) {
|
|
@@ -4038,7 +4044,7 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
4038
4044
|
var hasIncomingManualProductDiscount = isManualProductDiscountProduct(normalizedIncoming);
|
|
4039
4045
|
var hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
|
|
4040
4046
|
var isIncomingCustomItem = ((_productToAdd$metadat = productToAdd.metadata) === null || _productToAdd$metadat === void 0 || (_productToAdd$metadat = _productToAdd$metadat.origin) === null || _productToAdd$metadat === void 0 ? void 0 : _productToAdd$metadat.isCustomItem) === true || ((_origin = productToAdd._origin) === null || _origin === void 0 ? void 0 : _origin.isCustomItem) === true;
|
|
4041
|
-
var shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingManualProductDiscount || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
|
|
4047
|
+
var shouldForceNewLine = disableMerge || !!booking || hasIncomingProductNote || hasIncomingManualProductDiscount || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
|
|
4042
4048
|
var matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex(function (item) {
|
|
4043
4049
|
var _item$metadata3;
|
|
4044
4050
|
if (_this27.hasGoodPassDiscount(item)) return false;
|
|
@@ -4168,7 +4174,8 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
4168
4174
|
singleLine.num = 1;
|
|
4169
4175
|
delete singleLine.product_quantity;
|
|
4170
4176
|
_appendResult = this.appendProductLineToTempOrder(tempOrder, singleLine, cloneDeep(booking), {
|
|
4171
|
-
insertAtIndex: insertAtIndex
|
|
4177
|
+
insertAtIndex: insertAtIndex,
|
|
4178
|
+
disableMerge: options === null || options === void 0 ? void 0 : options.disableMerge
|
|
4172
4179
|
});
|
|
4173
4180
|
if (!_appendResult) {
|
|
4174
4181
|
_context21.next = 17;
|
|
@@ -4189,7 +4196,8 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
4189
4196
|
return _context21.abrupt("return", tempOrder.products);
|
|
4190
4197
|
case 24:
|
|
4191
4198
|
appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking, {
|
|
4192
|
-
insertAtIndex: insertAtIndex
|
|
4199
|
+
insertAtIndex: insertAtIndex,
|
|
4200
|
+
disableMerge: options === null || options === void 0 ? void 0 : options.disableMerge
|
|
4193
4201
|
});
|
|
4194
4202
|
if (!appendResult) {
|
|
4195
4203
|
_context21.next = 28;
|
|
@@ -6013,7 +6021,7 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
6013
6021
|
value: (function () {
|
|
6014
6022
|
var _hydrateTempOrderFromRecord = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee42(record, options) {
|
|
6015
6023
|
var _sourceRaw$_extend, _this$store$discount22;
|
|
6016
|
-
var sourceRaw, duplicateProductIdentityRepair, duplicateIdentityReadySource, identityReadySource, normalizedCollections, raw, hasIdentityChanges, identityLogMetadata, hasIdentityWarnings, isSessionStorageHydrate, nextTempOrder, _this$store$discount20, _this$store$discount21, restoredSessionDiscounts, nextExtend, sourceLastOrderInfo, isDraftOrder, syntheticIdentityOptions, rawSummary, summarySurcharges, hadSyntheticDraftOrderId, hydratedEditDiscounts, currentDiscounts, currentScanDiscounts, hydratedDiscountIds, retainedScanDiscounts, nextDiscounts, shouldSkipEmptyDiscountSync, _this$store$discount23, _this$store$discount24;
|
|
6024
|
+
var sourceRaw, duplicateProductIdentityRepair, duplicateIdentityReadySource, identityReadySource, normalizedCollections, raw, hasIdentityChanges, identityLogMetadata, hasIdentityWarnings, isSessionStorageHydrate, isMergedSalesDetailHydrate, nextTempOrder, _this$store$discount20, _this$store$discount21, restoredSessionDiscounts, nextExtend, sourceLastOrderInfo, isDraftOrder, syntheticIdentityOptions, rawSummary, summarySurcharges, hadSyntheticDraftOrderId, hydratedEditDiscounts, currentDiscounts, currentScanDiscounts, hydratedDiscountIds, retainedScanDiscounts, nextDiscounts, shouldSkipEmptyDiscountSync, _this$store$discount23, _this$store$discount24;
|
|
6017
6025
|
return _regeneratorRuntime().wrap(function _callee42$(_context45) {
|
|
6018
6026
|
while (1) switch (_context45.prev = _context45.next) {
|
|
6019
6027
|
case 0:
|
|
@@ -6048,12 +6056,14 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
6048
6056
|
}
|
|
6049
6057
|
}
|
|
6050
6058
|
isSessionStorageHydrate = (options === null || options === void 0 ? void 0 : options.source) === 'sessionStorage';
|
|
6059
|
+
isMergedSalesDetailHydrate = (options === null || options === void 0 ? void 0 : options.source) === 'mergedSalesDetail';
|
|
6051
6060
|
nextTempOrder = this.normalizeTempOrderForRuntime(raw, {
|
|
6052
|
-
|
|
6061
|
+
// merge 前已只给远端商品补标记;这里不能把本地未提交商品一并变成 saved item。
|
|
6062
|
+
makeEditMark: !isSessionStorageHydrate && !isMergedSalesDetailHydrate
|
|
6053
6063
|
});
|
|
6054
6064
|
this.store.tempOrder = nextTempOrder;
|
|
6055
6065
|
if (!isSessionStorageHydrate) {
|
|
6056
|
-
_context45.next =
|
|
6066
|
+
_context45.next = 30;
|
|
6057
6067
|
break;
|
|
6058
6068
|
}
|
|
6059
6069
|
// 会话快照是未提交购物车,不应获得编辑订单的 saved/edit 标记与服务端基线。
|
|
@@ -6069,24 +6079,24 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
6069
6079
|
nextTempOrder.discount_list = restoredSessionDiscounts;
|
|
6070
6080
|
this.store.summary = createEmptySummary();
|
|
6071
6081
|
this.store.lastOrderInfo = undefined;
|
|
6072
|
-
_context45.next =
|
|
6082
|
+
_context45.next = 23;
|
|
6073
6083
|
return (_this$store$discount20 = this.store.discount) === null || _this$store$discount20 === void 0 ? void 0 : _this$store$discount20.setOriginalDiscountList(cloneDeep(restoredSessionDiscounts));
|
|
6074
|
-
case
|
|
6075
|
-
_context45.next =
|
|
6084
|
+
case 23:
|
|
6085
|
+
_context45.next = 25;
|
|
6076
6086
|
return (_this$store$discount21 = this.store.discount) === null || _this$store$discount21 === void 0 ? void 0 : _this$store$discount21.setDiscountList(cloneDeep(restoredSessionDiscounts));
|
|
6077
|
-
case
|
|
6087
|
+
case 25:
|
|
6078
6088
|
if (!(options !== null && options !== void 0 && options.recalcOnHydrate)) {
|
|
6079
|
-
_context45.next =
|
|
6089
|
+
_context45.next = 28;
|
|
6080
6090
|
break;
|
|
6081
6091
|
}
|
|
6082
|
-
_context45.next =
|
|
6092
|
+
_context45.next = 28;
|
|
6083
6093
|
return this.recalculateSummary({
|
|
6084
6094
|
createIfMissing: false
|
|
6085
6095
|
});
|
|
6086
|
-
case
|
|
6096
|
+
case 28:
|
|
6087
6097
|
this.persistTempOrder();
|
|
6088
6098
|
return _context45.abrupt("return", nextTempOrder);
|
|
6089
|
-
case
|
|
6099
|
+
case 30:
|
|
6090
6100
|
// Server list compatibility may synthesize order_id from external_sale_number; tempOrder must not.
|
|
6091
6101
|
sourceLastOrderInfo = sourceRaw.lastOrderInfo || sourceRaw;
|
|
6092
6102
|
isDraftOrder = Number(nextTempOrder.is_draft_order || 0) === 1;
|
|
@@ -6102,7 +6112,7 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
6102
6112
|
surcharges: summarySurcharges
|
|
6103
6113
|
});
|
|
6104
6114
|
nextTempOrder._extend = _objectSpread(_objectSpread({}, nextTempOrder._extend || {}), {}, {
|
|
6105
|
-
originalSalesSnapshot: {
|
|
6115
|
+
originalSalesSnapshot: _objectSpread({
|
|
6106
6116
|
summary: cloneDeep(this.store.summary),
|
|
6107
6117
|
products: cloneDeep(nextTempOrder.products || []),
|
|
6108
6118
|
bookings: cloneDeep(nextTempOrder.bookings || []),
|
|
@@ -6110,7 +6120,9 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
6110
6120
|
surcharges: cloneDeep(nextTempOrder.surcharges || []),
|
|
6111
6121
|
shop_discount: nextTempOrder.shop_discount || '0.00',
|
|
6112
6122
|
productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || [])
|
|
6113
|
-
}
|
|
6123
|
+
}, isMergedSalesDetailHydrate ? {
|
|
6124
|
+
requiresFullSummaryRecalculation: true
|
|
6125
|
+
} : {})
|
|
6114
6126
|
});
|
|
6115
6127
|
this.store.lastOrderInfo = this.withoutSyntheticDraftOrderIdForRuntime(sourceLastOrderInfo, syntheticIdentityOptions);
|
|
6116
6128
|
hadSyntheticDraftOrderId = this.isSyntheticDraftOrderIdForRuntime(raw, syntheticIdentityOptions) || this.isSyntheticDraftOrderIdForRuntime(sourceLastOrderInfo, syntheticIdentityOptions);
|
|
@@ -6131,28 +6143,28 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
6131
6143
|
nextDiscounts = [].concat(_toConsumableArray(hydratedEditDiscounts), _toConsumableArray(retainedScanDiscounts));
|
|
6132
6144
|
shouldSkipEmptyDiscountSync = nextDiscounts.length === 0 && currentDiscounts.length === 0;
|
|
6133
6145
|
if (shouldSkipEmptyDiscountSync) {
|
|
6134
|
-
_context45.next =
|
|
6146
|
+
_context45.next = 53;
|
|
6135
6147
|
break;
|
|
6136
6148
|
}
|
|
6137
6149
|
OrderModule.populateSavedAmounts(nextTempOrder.products, nextDiscounts);
|
|
6138
|
-
_context45.next =
|
|
6150
|
+
_context45.next = 51;
|
|
6139
6151
|
return (_this$store$discount23 = this.store.discount) === null || _this$store$discount23 === void 0 ? void 0 : _this$store$discount23.setOriginalDiscountList(nextDiscounts);
|
|
6140
|
-
case
|
|
6141
|
-
_context45.next =
|
|
6152
|
+
case 51:
|
|
6153
|
+
_context45.next = 53;
|
|
6142
6154
|
return (_this$store$discount24 = this.store.discount) === null || _this$store$discount24 === void 0 ? void 0 : _this$store$discount24.setDiscountList(nextDiscounts);
|
|
6143
|
-
case
|
|
6155
|
+
case 53:
|
|
6144
6156
|
if (!(options !== null && options !== void 0 && options.recalcOnHydrate)) {
|
|
6145
|
-
_context45.next =
|
|
6157
|
+
_context45.next = 56;
|
|
6146
6158
|
break;
|
|
6147
6159
|
}
|
|
6148
|
-
_context45.next =
|
|
6160
|
+
_context45.next = 56;
|
|
6149
6161
|
return this.recalculateSummary({
|
|
6150
6162
|
createIfMissing: false
|
|
6151
6163
|
});
|
|
6152
|
-
case
|
|
6164
|
+
case 56:
|
|
6153
6165
|
this.persistTempOrder();
|
|
6154
6166
|
return _context45.abrupt("return", nextTempOrder);
|
|
6155
|
-
case
|
|
6167
|
+
case 58:
|
|
6156
6168
|
case "end":
|
|
6157
6169
|
return _context45.stop();
|
|
6158
6170
|
}
|
|
@@ -330,6 +330,8 @@ export type AddProductBookingInput = Record<string, any>;
|
|
|
330
330
|
*/
|
|
331
331
|
export interface AddProductToOrderOptions {
|
|
332
332
|
insertAfterProductUid?: string;
|
|
333
|
+
/** 跳过同商品/规格匹配,始终新增购物车行。 */
|
|
334
|
+
disableMerge?: boolean;
|
|
333
335
|
}
|
|
334
336
|
/**
|
|
335
337
|
* 删除商品后的可选位置保持策略。
|
|
@@ -821,7 +823,7 @@ export interface OrderModuleAPI {
|
|
|
821
823
|
saveDraft: () => Promise<void>;
|
|
822
824
|
hydrateTempOrderFromRecord: (record: Record<string, any>, options?: {
|
|
823
825
|
recalcOnHydrate?: boolean;
|
|
824
|
-
source?: 'salesDetail' | 'sessionStorage';
|
|
826
|
+
source?: 'salesDetail' | 'mergedSalesDetail' | 'sessionStorage';
|
|
825
827
|
}) => Promise<OrderTempOrder>;
|
|
826
828
|
syncPaymentsToOrder: <T = any>(params: SyncPaymentsToOrderParams) => Promise<SyncPaymentsToOrderResult<T>>;
|
|
827
829
|
getSalesOrderByLookup: (params: SalesOrderLookupParams) => Promise<any>;
|
|
@@ -370,6 +370,24 @@ function filterPendingPaymentsFromLoadedSalesDetail(sourceRecord) {
|
|
|
370
370
|
}
|
|
371
371
|
return record;
|
|
372
372
|
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* merge hydrate 不会统一给所有商品补 saved 标记,因此先只标记远端已保存商品。
|
|
376
|
+
* 当前 tempOrder 中尚未提交的本地商品会在 merge 后继续保持 current item 语义。
|
|
377
|
+
*/
|
|
378
|
+
function markLoadedSalesDetailProductsAsSaved(sourceRecord) {
|
|
379
|
+
if (!sourceRecord || _typeof(sourceRecord) !== 'object') return sourceRecord;
|
|
380
|
+
if (!Array.isArray(sourceRecord.products)) return sourceRecord;
|
|
381
|
+
return _objectSpread(_objectSpread({}, sourceRecord), {}, {
|
|
382
|
+
products: sourceRecord.products.map(function (product) {
|
|
383
|
+
return _objectSpread(_objectSpread({}, product || {}), {}, {
|
|
384
|
+
metadata: _objectSpread(_objectSpread({}, product !== null && product !== void 0 && product.metadata && _typeof(product.metadata) === 'object' ? product.metadata : {}), {}, {
|
|
385
|
+
is_edit_for_runtime: true
|
|
386
|
+
})
|
|
387
|
+
});
|
|
388
|
+
})
|
|
389
|
+
});
|
|
390
|
+
}
|
|
373
391
|
export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
374
392
|
_inherits(BaseSalesImpl, _BaseModule);
|
|
375
393
|
var _super = _createSuper(BaseSalesImpl);
|
|
@@ -669,7 +687,7 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
669
687
|
}, {
|
|
670
688
|
key: "hydrateLatestLoadedSalesDetail",
|
|
671
689
|
value: function () {
|
|
672
|
-
var _hydrateLatestLoadedSalesDetail = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(record, loadSequence,
|
|
690
|
+
var _hydrateLatestLoadedSalesDetail = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(record, loadSequence, options) {
|
|
673
691
|
var _this4 = this;
|
|
674
692
|
var hydratedSales, skippedBeforeHydrate, hydrateTask, queuedTask;
|
|
675
693
|
return _regeneratorRuntime().wrap(function _callee5$(_context5) {
|
|
@@ -679,7 +697,7 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
679
697
|
skippedBeforeHydrate = false;
|
|
680
698
|
hydrateTask = /*#__PURE__*/function () {
|
|
681
699
|
var _ref10 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
|
|
682
|
-
var sales;
|
|
700
|
+
var hydrateOptions, sales;
|
|
683
701
|
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
|
684
702
|
while (1) switch (_context4.prev = _context4.next) {
|
|
685
703
|
case 0:
|
|
@@ -696,30 +714,39 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
696
714
|
}
|
|
697
715
|
throw new Error('order 模块未初始化');
|
|
698
716
|
case 5:
|
|
699
|
-
|
|
700
|
-
return _this4.store.order.hydrateTempOrderFromRecord(record, hydrateSource === 'sessionStorage' ? {
|
|
701
|
-
recalcOnHydrate: true,
|
|
702
|
-
source: 'sessionStorage'
|
|
703
|
-
} : {
|
|
717
|
+
hydrateOptions = {
|
|
704
718
|
recalcOnHydrate: false
|
|
705
|
-
}
|
|
706
|
-
|
|
719
|
+
};
|
|
720
|
+
if ((options === null || options === void 0 ? void 0 : options.hydrateSource) === 'sessionStorage') {
|
|
721
|
+
hydrateOptions = {
|
|
722
|
+
recalcOnHydrate: true,
|
|
723
|
+
source: 'sessionStorage'
|
|
724
|
+
};
|
|
725
|
+
} else if (options !== null && options !== void 0 && options.merge) {
|
|
726
|
+
hydrateOptions = {
|
|
727
|
+
recalcOnHydrate: true,
|
|
728
|
+
source: 'mergedSalesDetail'
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
_context4.next = 9;
|
|
732
|
+
return _this4.store.order.hydrateTempOrderFromRecord(record, hydrateOptions);
|
|
733
|
+
case 9:
|
|
707
734
|
sales = _context4.sent;
|
|
708
735
|
hydratedSales = sales;
|
|
709
736
|
|
|
710
737
|
// hydrate 期间可能又发起了更新请求;后续任务已串行排队,将负责最终状态。
|
|
711
738
|
if (!(loadSequence !== _this4.salesDetailLoadSequence)) {
|
|
712
|
-
_context4.next =
|
|
739
|
+
_context4.next = 13;
|
|
713
740
|
break;
|
|
714
741
|
}
|
|
715
742
|
return _context4.abrupt("return");
|
|
716
|
-
case
|
|
743
|
+
case 13:
|
|
717
744
|
_this4.currentSalesDetail = sales;
|
|
718
|
-
_context4.next =
|
|
745
|
+
_context4.next = 16;
|
|
719
746
|
return _this4.core.effects.emit("".concat(_this4.name, ":onSalesOrderLoaded"), {
|
|
720
747
|
sales: sales
|
|
721
748
|
});
|
|
722
|
-
case
|
|
749
|
+
case 16:
|
|
723
750
|
case "end":
|
|
724
751
|
return _context4.stop();
|
|
725
752
|
}
|
|
@@ -1534,7 +1561,7 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1534
1561
|
key: "loadSalesDetail",
|
|
1535
1562
|
value: (function () {
|
|
1536
1563
|
var _loadSalesDetail = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee14(orderIdOrParams) {
|
|
1537
|
-
var loadSequence, _ref27, _ref28, _ref29, _ref30, _params$orderId, params, externalSaleNumber, preloadedSalesDetail, lookup, loadedRecord, message, loadedSalesDetail, shouldFilterPendingPayments, remoteRecord, currentTempOrder, mergedRecord, record;
|
|
1564
|
+
var loadSequence, _ref27, _ref28, _ref29, _ref30, _params$orderId, params, externalSaleNumber, preloadedSalesDetail, lookup, loadedRecord, message, loadedSalesDetail, shouldFilterPendingPayments, remoteRecord, mergeSourceRecord, currentTempOrder, mergedRecord, record;
|
|
1538
1565
|
return _regeneratorRuntime().wrap(function _callee14$(_context14) {
|
|
1539
1566
|
while (1) switch (_context14.prev = _context14.next) {
|
|
1540
1567
|
case 0:
|
|
@@ -1586,39 +1613,43 @@ export var BaseSalesImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1586
1613
|
loadedSalesDetail = preloadedSalesDetail !== null && preloadedSalesDetail !== void 0 ? preloadedSalesDetail : loadedRecord.data; // payment_pending 只存在于本地;远端详情需过滤,但会话快照必须完整恢复。
|
|
1587
1614
|
shouldFilterPendingPayments = params.hydrateSource !== 'sessionStorage';
|
|
1588
1615
|
remoteRecord = shouldFilterPendingPayments ? filterPendingPaymentsFromLoadedSalesDetail(loadedSalesDetail) : loadedSalesDetail;
|
|
1616
|
+
mergeSourceRecord = params.merge ? markLoadedSalesDetailProductsAsSaved(remoteRecord) : remoteRecord;
|
|
1589
1617
|
currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
|
|
1590
|
-
mergedRecord = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder,
|
|
1618
|
+
mergedRecord = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder, mergeSourceRecord, 'preserve-local') : mergeSourceRecord;
|
|
1591
1619
|
record = shouldFilterPendingPayments ? filterPendingPaymentsFromLoadedSalesDetail(mergedRecord) : mergedRecord;
|
|
1592
|
-
_context14.next =
|
|
1593
|
-
return this.hydrateLatestLoadedSalesDetail(record, loadSequence,
|
|
1594
|
-
|
|
1595
|
-
|
|
1620
|
+
_context14.next = 31;
|
|
1621
|
+
return this.hydrateLatestLoadedSalesDetail(record, loadSequence, {
|
|
1622
|
+
hydrateSource: params.hydrateSource,
|
|
1623
|
+
merge: params.merge
|
|
1624
|
+
});
|
|
1596
1625
|
case 31:
|
|
1597
|
-
_context14.
|
|
1626
|
+
return _context14.abrupt("return", _context14.sent);
|
|
1627
|
+
case 32:
|
|
1628
|
+
_context14.prev = 32;
|
|
1598
1629
|
this.salesDetailLoadInFlightCount = Math.max(0, this.salesDetailLoadInFlightCount - 1);
|
|
1599
1630
|
if (!(this.salesDetailLoadInFlightCount === 0)) {
|
|
1600
|
-
_context14.next =
|
|
1631
|
+
_context14.next = 43;
|
|
1601
1632
|
break;
|
|
1602
1633
|
}
|
|
1603
|
-
_context14.prev =
|
|
1604
|
-
_context14.next =
|
|
1634
|
+
_context14.prev = 35;
|
|
1635
|
+
_context14.next = 38;
|
|
1605
1636
|
return this.drainQueuedServerOrderChanges();
|
|
1606
|
-
case
|
|
1607
|
-
_context14.next =
|
|
1637
|
+
case 38:
|
|
1638
|
+
_context14.next = 43;
|
|
1608
1639
|
break;
|
|
1609
|
-
case
|
|
1610
|
-
_context14.prev =
|
|
1611
|
-
_context14.t1 = _context14["catch"](
|
|
1640
|
+
case 40:
|
|
1641
|
+
_context14.prev = 40;
|
|
1642
|
+
_context14.t1 = _context14["catch"](35);
|
|
1612
1643
|
this.logError('drain queued server order changes failed', {
|
|
1613
1644
|
error: _context14.t1 instanceof Error ? _context14.t1.message : String(_context14.t1)
|
|
1614
1645
|
});
|
|
1615
|
-
case 42:
|
|
1616
|
-
return _context14.finish(31);
|
|
1617
1646
|
case 43:
|
|
1647
|
+
return _context14.finish(32);
|
|
1648
|
+
case 44:
|
|
1618
1649
|
case "end":
|
|
1619
1650
|
return _context14.stop();
|
|
1620
1651
|
}
|
|
1621
|
-
}, _callee14, this, [[4,,
|
|
1652
|
+
}, _callee14, this, [[4,, 32, 44], [35, 40]]);
|
|
1622
1653
|
}));
|
|
1623
1654
|
function loadSalesDetail(_x13) {
|
|
1624
1655
|
return _loadSalesDetail.apply(this, arguments);
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { OrderProduct } from '../../../modules/Order/types';
|
|
2
|
+
/**
|
|
3
|
+
* 运行态商品行标记:该行由“不合并商品”加车策略创建,促销重算时必须保持独立。
|
|
4
|
+
* `normalizeSubmitProduct` 会按白名单裁剪 metadata,不会把此字段提交到后端。
|
|
5
|
+
*/
|
|
6
|
+
export declare const PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY = "_productLineMergeDisabled";
|
|
2
7
|
/**
|
|
3
8
|
* Cart promotion 工具集(OS 内部纯函数)
|
|
4
9
|
*
|
|
@@ -23,6 +23,12 @@ import { cloneDeep } from 'lodash-es';
|
|
|
23
23
|
import { composeLinePrice, createUuidV4, getProductSkuOptions, sumOptionUnitPrice } from "../../../modules/Order/utils";
|
|
24
24
|
import { buildProductLineFingerprint, getSafeProductNum } from "../../ScanOrder/utils";
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* 运行态商品行标记:该行由“不合并商品”加车策略创建,促销重算时必须保持独立。
|
|
28
|
+
* `normalizeSubmitProduct` 会按白名单裁剪 metadata,不会把此字段提交到后端。
|
|
29
|
+
*/
|
|
30
|
+
export var PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY = '_productLineMergeDisabled';
|
|
31
|
+
|
|
26
32
|
/**
|
|
27
33
|
* Cart promotion 工具集(OS 内部纯函数)
|
|
28
34
|
*
|
|
@@ -483,10 +489,13 @@ function hasGoodPassDiscount(product) {
|
|
|
483
489
|
}
|
|
484
490
|
|
|
485
491
|
/**
|
|
486
|
-
*
|
|
492
|
+
* 不合并商品、商品券、自定义商品、称重行以及编辑订单历史行都有各自的促销合并边界。
|
|
487
493
|
*/
|
|
488
494
|
function getPromotionLineMergeBoundary(product) {
|
|
489
|
-
var _product$product_sku, _product$
|
|
495
|
+
var _product$metadata3, _product$product_sku, _product$metadata4;
|
|
496
|
+
if ((product === null || product === void 0 || (_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3[PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY]) === true) {
|
|
497
|
+
return "separate:".concat(getOrderProductUid(product));
|
|
498
|
+
}
|
|
490
499
|
if ((product === null || product === void 0 ? void 0 : product.product_id) === undefined || (product === null || product === void 0 ? void 0 : product.product_id) === null) {
|
|
491
500
|
return "custom:".concat(getOrderProductUid(product));
|
|
492
501
|
}
|
|
@@ -496,7 +505,7 @@ function getPromotionLineMergeBoundary(product) {
|
|
|
496
505
|
if (Number((product === null || product === void 0 || (_product$product_sku = product.product_sku) === null || _product$product_sku === void 0 ? void 0 : _product$product_sku.open_sold_weight) || 0) === 1) {
|
|
497
506
|
return "weighing:".concat(getOrderProductUid(product));
|
|
498
507
|
}
|
|
499
|
-
if ((product === null || product === void 0 || (_product$
|
|
508
|
+
if ((product === null || product === void 0 || (_product$metadata4 = product.metadata) === null || _product$metadata4 === void 0 ? void 0 : _product$metadata4.is_edit_for_runtime) !== true) return '';
|
|
500
509
|
return "edit:".concat(getOrderProductUid(product));
|
|
501
510
|
}
|
|
502
511
|
function isPersistedGeneratedVoucher(product) {
|
|
@@ -921,13 +930,13 @@ export function resolveStrategyEligibleProducts(matched) {
|
|
|
921
930
|
export function calculateUnfulfilledPromotions(processedProducts, applicableStrategiesResult, mainProducts) {
|
|
922
931
|
var unfulfilledMap = new Map();
|
|
923
932
|
var _loop2 = function _loop2() {
|
|
924
|
-
var _product$
|
|
933
|
+
var _product$metadata5, _ref13, _product$_originalPro, _product$metadata6, _product$num2;
|
|
925
934
|
var product = processedProducts[i];
|
|
926
|
-
var promotion = product === null || product === void 0 || (_product$
|
|
935
|
+
var promotion = product === null || product === void 0 || (_product$metadata5 = product.metadata) === null || _product$metadata5 === void 0 ? void 0 : _product$metadata5._promotion;
|
|
927
936
|
if (!promotion || promotion.inPromotion !== false) return 0; // continue
|
|
928
937
|
var strategyId = promotion.strategyId;
|
|
929
938
|
if (!strategyId) return 0; // continue
|
|
930
|
-
var lookupUid = String((_ref13 = (_product$_originalPro = product === null || product === void 0 ? void 0 : product._originalProductUid) !== null && _product$_originalPro !== void 0 ? _product$_originalPro : product === null || product === void 0 || (_product$
|
|
939
|
+
var lookupUid = String((_ref13 = (_product$_originalPro = product === null || product === void 0 ? void 0 : product._originalProductUid) !== null && _product$_originalPro !== void 0 ? _product$_originalPro : product === null || product === void 0 || (_product$metadata6 = product.metadata) === null || _product$metadata6 === void 0 ? void 0 : _product$metadata6.unique_identification_number) !== null && _ref13 !== void 0 ? _ref13 : '');
|
|
931
940
|
var originalIndex = mainProducts.findIndex(function (item) {
|
|
932
941
|
return getOrderProductUid(item) === lookupUid;
|
|
933
942
|
});
|
|
@@ -562,7 +562,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
562
562
|
*/
|
|
563
563
|
hydrateTempOrderFromRecord(record: Record<string, any>, options?: {
|
|
564
564
|
recalcOnHydrate?: boolean;
|
|
565
|
-
source?: 'salesDetail' | 'sessionStorage';
|
|
565
|
+
source?: 'salesDetail' | 'mergedSalesDetail' | 'sessionStorage';
|
|
566
566
|
}): Promise<OrderTempOrder>;
|
|
567
567
|
/**
|
|
568
568
|
* 兼容后端详情将 holder 放在 metadata.holder 的历史形态,统一补到运行时展示路径。
|
|
@@ -1589,6 +1589,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1589
1589
|
return !new _decimal.default(tempOrder.shop_discount || 0).equals(snapshotShopDiscount || 0);
|
|
1590
1590
|
}
|
|
1591
1591
|
restoreOriginalSnapshotIfProductsUnchanged(tempOrder, snapshot) {
|
|
1592
|
+
// merge hydrate 的商品集合包含本地未提交行,但 summary 仍来自远端旧订单,不能复用。
|
|
1593
|
+
if (snapshot.requiresFullSummaryRecalculation === true) return null;
|
|
1592
1594
|
const currentFingerprint = this.buildOrderProductsFingerprint(tempOrder.products);
|
|
1593
1595
|
const manualDepositOverride = this.getManualDepositOverride(tempOrder);
|
|
1594
1596
|
if (currentFingerprint !== snapshot.productFingerprint) {
|
|
@@ -2805,8 +2807,15 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2805
2807
|
booking
|
|
2806
2808
|
}) : null;
|
|
2807
2809
|
const productToAdd = linked?.product || product;
|
|
2808
|
-
const
|
|
2810
|
+
const disableMerge = options?.disableMerge === true;
|
|
2811
|
+
const incomingFingerprint = disableMerge ? '' : (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(productToAdd), productToAdd.product_bundle);
|
|
2809
2812
|
const normalizedIncoming = (0, _utils.mergeOrderProductDisplayFields)(productToAdd, (0, _utils3.normalizeOrderProduct)(productToAdd));
|
|
2813
|
+
if (disableMerge) {
|
|
2814
|
+
normalizedIncoming.metadata = {
|
|
2815
|
+
...(normalizedIncoming.metadata || {}),
|
|
2816
|
+
[_cartPromotion.PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY]: true
|
|
2817
|
+
};
|
|
2818
|
+
}
|
|
2810
2819
|
const isWeighingProduct = Number(normalizedIncoming.product_sku?.open_sold_weight || 0) === 1;
|
|
2811
2820
|
const netWeight = Number(normalizedIncoming.product_sku?.net_weight);
|
|
2812
2821
|
if (isWeighingProduct && (!Number.isFinite(netWeight) || netWeight <= 0)) {
|
|
@@ -2826,7 +2835,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2826
2835
|
const hasIncomingManualProductDiscount = isManualProductDiscountProduct(normalizedIncoming);
|
|
2827
2836
|
const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
|
|
2828
2837
|
const isIncomingCustomItem = productToAdd.metadata?.origin?.isCustomItem === true || productToAdd._origin?.isCustomItem === true;
|
|
2829
|
-
const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingManualProductDiscount || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
|
|
2838
|
+
const shouldForceNewLine = disableMerge || !!booking || hasIncomingProductNote || hasIncomingManualProductDiscount || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
|
|
2830
2839
|
const matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex(item => {
|
|
2831
2840
|
if (this.hasGoodPassDiscount(item)) return false;
|
|
2832
2841
|
if (this.hasOrderProductLineNote(item)) return false;
|
|
@@ -2944,7 +2953,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2944
2953
|
singleLine.num = 1;
|
|
2945
2954
|
delete singleLine.product_quantity;
|
|
2946
2955
|
const appendResult = this.appendProductLineToTempOrder(tempOrder, singleLine, (0, _lodashEs.cloneDeep)(booking), {
|
|
2947
|
-
insertAtIndex
|
|
2956
|
+
insertAtIndex,
|
|
2957
|
+
disableMerge: options?.disableMerge
|
|
2948
2958
|
});
|
|
2949
2959
|
if (appendResult) await appendResult;
|
|
2950
2960
|
if (insertAtIndex !== undefined) insertAtIndex += 1;
|
|
@@ -2954,7 +2964,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2954
2964
|
}
|
|
2955
2965
|
}
|
|
2956
2966
|
const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking, {
|
|
2957
|
-
insertAtIndex
|
|
2967
|
+
insertAtIndex,
|
|
2968
|
+
disableMerge: options?.disableMerge
|
|
2958
2969
|
});
|
|
2959
2970
|
if (appendResult) await appendResult;
|
|
2960
2971
|
await this.finalizeProductOrderMutation(tempOrder);
|
|
@@ -4134,8 +4145,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4134
4145
|
}
|
|
4135
4146
|
}
|
|
4136
4147
|
const isSessionStorageHydrate = options?.source === 'sessionStorage';
|
|
4148
|
+
const isMergedSalesDetailHydrate = options?.source === 'mergedSalesDetail';
|
|
4137
4149
|
const nextTempOrder = this.normalizeTempOrderForRuntime(raw, {
|
|
4138
|
-
|
|
4150
|
+
// merge 前已只给远端商品补标记;这里不能把本地未提交商品一并变成 saved item。
|
|
4151
|
+
makeEditMark: !isSessionStorageHydrate && !isMergedSalesDetailHydrate
|
|
4139
4152
|
});
|
|
4140
4153
|
this.store.tempOrder = nextTempOrder;
|
|
4141
4154
|
if (isSessionStorageHydrate) {
|
|
@@ -4190,7 +4203,11 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4190
4203
|
payments: (0, _lodashEs.cloneDeep)(nextTempOrder.payments || []),
|
|
4191
4204
|
surcharges: (0, _lodashEs.cloneDeep)(nextTempOrder.surcharges || []),
|
|
4192
4205
|
shop_discount: nextTempOrder.shop_discount || '0.00',
|
|
4193
|
-
productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || [])
|
|
4206
|
+
productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || []),
|
|
4207
|
+
// merged record 的 summary 仍是远端旧值,保留快照仅用于完整重算的价格清理基线。
|
|
4208
|
+
...(isMergedSalesDetailHydrate ? {
|
|
4209
|
+
requiresFullSummaryRecalculation: true
|
|
4210
|
+
} : {})
|
|
4194
4211
|
}
|
|
4195
4212
|
};
|
|
4196
4213
|
this.store.lastOrderInfo = this.withoutSyntheticDraftOrderIdForRuntime(sourceLastOrderInfo, syntheticIdentityOptions);
|
|
@@ -330,6 +330,8 @@ export type AddProductBookingInput = Record<string, any>;
|
|
|
330
330
|
*/
|
|
331
331
|
export interface AddProductToOrderOptions {
|
|
332
332
|
insertAfterProductUid?: string;
|
|
333
|
+
/** 跳过同商品/规格匹配,始终新增购物车行。 */
|
|
334
|
+
disableMerge?: boolean;
|
|
333
335
|
}
|
|
334
336
|
/**
|
|
335
337
|
* 删除商品后的可选位置保持策略。
|
|
@@ -821,7 +823,7 @@ export interface OrderModuleAPI {
|
|
|
821
823
|
saveDraft: () => Promise<void>;
|
|
822
824
|
hydrateTempOrderFromRecord: (record: Record<string, any>, options?: {
|
|
823
825
|
recalcOnHydrate?: boolean;
|
|
824
|
-
source?: 'salesDetail' | 'sessionStorage';
|
|
826
|
+
source?: 'salesDetail' | 'mergedSalesDetail' | 'sessionStorage';
|
|
825
827
|
}) => Promise<OrderTempOrder>;
|
|
826
828
|
syncPaymentsToOrder: <T = any>(params: SyncPaymentsToOrderParams) => Promise<SyncPaymentsToOrderResult<T>>;
|
|
827
829
|
getSalesOrderByLookup: (params: SalesOrderLookupParams) => Promise<any>;
|
|
@@ -331,6 +331,25 @@ function filterPendingPaymentsFromLoadedSalesDetail(sourceRecord) {
|
|
|
331
331
|
}
|
|
332
332
|
return record;
|
|
333
333
|
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* merge hydrate 不会统一给所有商品补 saved 标记,因此先只标记远端已保存商品。
|
|
337
|
+
* 当前 tempOrder 中尚未提交的本地商品会在 merge 后继续保持 current item 语义。
|
|
338
|
+
*/
|
|
339
|
+
function markLoadedSalesDetailProductsAsSaved(sourceRecord) {
|
|
340
|
+
if (!sourceRecord || typeof sourceRecord !== 'object') return sourceRecord;
|
|
341
|
+
if (!Array.isArray(sourceRecord.products)) return sourceRecord;
|
|
342
|
+
return {
|
|
343
|
+
...sourceRecord,
|
|
344
|
+
products: sourceRecord.products.map(product => ({
|
|
345
|
+
...(product || {}),
|
|
346
|
+
metadata: {
|
|
347
|
+
...(product?.metadata && typeof product.metadata === 'object' ? product.metadata : {}),
|
|
348
|
+
is_edit_for_runtime: true
|
|
349
|
+
}
|
|
350
|
+
}))
|
|
351
|
+
};
|
|
352
|
+
}
|
|
334
353
|
class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
335
354
|
defaultName = 'baseSales';
|
|
336
355
|
defaultVersion = '1.0.0';
|
|
@@ -512,7 +531,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
512
531
|
});
|
|
513
532
|
});
|
|
514
533
|
}
|
|
515
|
-
async hydrateLatestLoadedSalesDetail(record, loadSequence,
|
|
534
|
+
async hydrateLatestLoadedSalesDetail(record, loadSequence, options) {
|
|
516
535
|
let hydratedSales = null;
|
|
517
536
|
let skippedBeforeHydrate = false;
|
|
518
537
|
const hydrateTask = async () => {
|
|
@@ -522,12 +541,21 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
522
541
|
return;
|
|
523
542
|
}
|
|
524
543
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
525
|
-
|
|
526
|
-
recalcOnHydrate: true,
|
|
527
|
-
source: 'sessionStorage'
|
|
528
|
-
} : {
|
|
544
|
+
let hydrateOptions = {
|
|
529
545
|
recalcOnHydrate: false
|
|
530
|
-
}
|
|
546
|
+
};
|
|
547
|
+
if (options?.hydrateSource === 'sessionStorage') {
|
|
548
|
+
hydrateOptions = {
|
|
549
|
+
recalcOnHydrate: true,
|
|
550
|
+
source: 'sessionStorage'
|
|
551
|
+
};
|
|
552
|
+
} else if (options?.merge) {
|
|
553
|
+
hydrateOptions = {
|
|
554
|
+
recalcOnHydrate: true,
|
|
555
|
+
source: 'mergedSalesDetail'
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
const sales = await this.store.order.hydrateTempOrderFromRecord(record, hydrateOptions);
|
|
531
559
|
hydratedSales = sales;
|
|
532
560
|
|
|
533
561
|
// hydrate 期间可能又发起了更新请求;后续任务已串行排队,将负责最终状态。
|
|
@@ -1076,10 +1104,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1076
1104
|
// payment_pending 只存在于本地;远端详情需过滤,但会话快照必须完整恢复。
|
|
1077
1105
|
const shouldFilterPendingPayments = params.hydrateSource !== 'sessionStorage';
|
|
1078
1106
|
const remoteRecord = shouldFilterPendingPayments ? filterPendingPaymentsFromLoadedSalesDetail(loadedSalesDetail) : loadedSalesDetail;
|
|
1107
|
+
const mergeSourceRecord = params.merge ? markLoadedSalesDetailProductsAsSaved(remoteRecord) : remoteRecord;
|
|
1079
1108
|
const currentTempOrder = params.merge ? this.store.order.getTempOrder() : null;
|
|
1080
|
-
const mergedRecord = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder,
|
|
1109
|
+
const mergedRecord = params.merge ? mergeSalesDetailRecordWithTempOrder(currentTempOrder, mergeSourceRecord, 'preserve-local') : mergeSourceRecord;
|
|
1081
1110
|
const record = shouldFilterPendingPayments ? filterPendingPaymentsFromLoadedSalesDetail(mergedRecord) : mergedRecord;
|
|
1082
|
-
return await this.hydrateLatestLoadedSalesDetail(record, loadSequence,
|
|
1111
|
+
return await this.hydrateLatestLoadedSalesDetail(record, loadSequence, {
|
|
1112
|
+
hydrateSource: params.hydrateSource,
|
|
1113
|
+
merge: params.merge
|
|
1114
|
+
});
|
|
1083
1115
|
} finally {
|
|
1084
1116
|
this.salesDetailLoadInFlightCount = Math.max(0, this.salesDetailLoadInFlightCount - 1);
|
|
1085
1117
|
if (this.salesDetailLoadInFlightCount === 0) {
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { OrderProduct } from '../../../modules/Order/types';
|
|
2
|
+
/**
|
|
3
|
+
* 运行态商品行标记:该行由“不合并商品”加车策略创建,促销重算时必须保持独立。
|
|
4
|
+
* `normalizeSubmitProduct` 会按白名单裁剪 metadata,不会把此字段提交到后端。
|
|
5
|
+
*/
|
|
6
|
+
export declare const PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY = "_productLineMergeDisabled";
|
|
2
7
|
/**
|
|
3
8
|
* Cart promotion 工具集(OS 内部纯函数)
|
|
4
9
|
*
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY = void 0;
|
|
6
7
|
exports.appendPromotionTags = appendPromotionTags;
|
|
7
8
|
exports.buildConsolidateKeyForPromotion = buildConsolidateKeyForPromotion;
|
|
8
9
|
exports.calculateUnfulfilledPromotions = calculateUnfulfilledPromotions;
|
|
@@ -19,6 +20,12 @@ var _lodashEs = require("lodash-es");
|
|
|
19
20
|
var _utils = require("../../../modules/Order/utils");
|
|
20
21
|
var _utils2 = require("../../ScanOrder/utils");
|
|
21
22
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
+
/**
|
|
24
|
+
* 运行态商品行标记:该行由“不合并商品”加车策略创建,促销重算时必须保持独立。
|
|
25
|
+
* `normalizeSubmitProduct` 会按白名单裁剪 metadata,不会把此字段提交到后端。
|
|
26
|
+
*/
|
|
27
|
+
const PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY = exports.PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY = '_productLineMergeDisabled';
|
|
28
|
+
|
|
22
29
|
/**
|
|
23
30
|
* Cart promotion 工具集(OS 内部纯函数)
|
|
24
31
|
*
|
|
@@ -396,9 +403,12 @@ function hasGoodPassDiscount(product) {
|
|
|
396
403
|
}
|
|
397
404
|
|
|
398
405
|
/**
|
|
399
|
-
*
|
|
406
|
+
* 不合并商品、商品券、自定义商品、称重行以及编辑订单历史行都有各自的促销合并边界。
|
|
400
407
|
*/
|
|
401
408
|
function getPromotionLineMergeBoundary(product) {
|
|
409
|
+
if (product?.metadata?.[PRODUCT_LINE_MERGE_DISABLED_METADATA_KEY] === true) {
|
|
410
|
+
return `separate:${getOrderProductUid(product)}`;
|
|
411
|
+
}
|
|
402
412
|
if (product?.product_id === undefined || product?.product_id === null) {
|
|
403
413
|
return `custom:${getOrderProductUid(product)}`;
|
|
404
414
|
}
|