@pisell/pisellos 0.0.508 → 0.0.510
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.js +47 -36
- package/dist/modules/Order/utils.d.ts +2 -0
- package/dist/modules/Order/utils.js +12 -2
- package/dist/solution/ScanOrder/index.js +34 -21
- package/dist/solution/ScanOrder/types.d.ts +3 -0
- package/dist/solution/ScanOrder/utils.d.ts +24 -2
- package/dist/solution/ScanOrder/utils.js +142 -9
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/modules/Order/index.js +15 -10
- package/lib/modules/Order/utils.d.ts +2 -0
- package/lib/modules/Order/utils.js +14 -1
- package/lib/solution/ScanOrder/index.js +30 -12
- package/lib/solution/ScanOrder/types.d.ts +3 -0
- package/lib/solution/ScanOrder/utils.d.ts +24 -2
- package/lib/solution/ScanOrder/utils.js +124 -2
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
-
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
3
1
|
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
4
2
|
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
5
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
6
3
|
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
7
4
|
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
5
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
6
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
7
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
8
8
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
9
9
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
10
10
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -25,7 +25,7 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
|
|
|
25
25
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
26
26
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
27
27
|
import { BaseModule } from "../BaseModule";
|
|
28
|
-
import { generateDuration, getAllDiscountList, mergeRelationForms, buildSubmitPayload, createDefaultTempOrder, createDefaultOrderRulesHooks, createEmptySummary, formatDateTime, formatV1Product, isTempOrder } from "./utils";
|
|
28
|
+
import { generateDuration, getAllDiscountList, mergeRelationForms, buildSubmitPayload, createDefaultTempOrder, createDefaultOrderRulesHooks, createEmptySummary, formatDateTime, filterProductsForScanOrderMore, formatV1Product, isTempOrder } from "./utils";
|
|
29
29
|
import { isNormalProduct } from "../Product/utils";
|
|
30
30
|
import dayjs from 'dayjs';
|
|
31
31
|
import { getProductIdentityIndex, getSafeProductNum, isIdentityMatch, normalizeOrderProduct } from "../../solution/ScanOrder/utils";
|
|
@@ -387,6 +387,26 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
387
387
|
this.window.localStorage.removeItem(key);
|
|
388
388
|
return;
|
|
389
389
|
}
|
|
390
|
+
if (Array.isArray(parsedData.products)) {
|
|
391
|
+
var _iterator = _createForOfIteratorHelper(parsedData.products),
|
|
392
|
+
_step;
|
|
393
|
+
try {
|
|
394
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
395
|
+
var p = _step.value;
|
|
396
|
+
if (!p || _typeof(p) !== 'object') continue;
|
|
397
|
+
if (!Array.isArray(p.product_option_item)) {
|
|
398
|
+
p.product_option_item = [];
|
|
399
|
+
}
|
|
400
|
+
if (!Array.isArray(p.product_bundle)) {
|
|
401
|
+
p.product_bundle = [];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
} catch (err) {
|
|
405
|
+
_iterator.e(err);
|
|
406
|
+
} finally {
|
|
407
|
+
_iterator.f();
|
|
408
|
+
}
|
|
409
|
+
}
|
|
390
410
|
this.store.tempOrder = parsedData;
|
|
391
411
|
} catch (_unused2) {
|
|
392
412
|
var _this$window;
|
|
@@ -676,32 +696,23 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
676
696
|
key: "removeProductFromOrder",
|
|
677
697
|
value: function () {
|
|
678
698
|
var _removeProductFromOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee9(identity) {
|
|
679
|
-
var tempOrder
|
|
699
|
+
var tempOrder;
|
|
680
700
|
return _regeneratorRuntime().wrap(function _callee9$(_context9) {
|
|
681
701
|
while (1) switch (_context9.prev = _context9.next) {
|
|
682
702
|
case 0:
|
|
683
703
|
tempOrder = this.ensureTempOrder();
|
|
684
|
-
beforeProducts = tempOrder.products;
|
|
685
704
|
tempOrder.products = tempOrder.products.filter(function (item) {
|
|
686
705
|
return !isIdentityMatch(item, identity);
|
|
687
706
|
});
|
|
688
|
-
removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
|
|
689
|
-
if (removedByStrictIdentity === 0 && identity.identity_key) {
|
|
690
|
-
tempOrder.products = tempOrder.products.filter(function (item) {
|
|
691
|
-
var isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
|
|
692
|
-
var hasNoIdentityKey = !item.identity_key;
|
|
693
|
-
return !(isSameProduct && hasNoIdentityKey);
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
707
|
this.applyDiscount();
|
|
697
|
-
_context9.next =
|
|
708
|
+
_context9.next = 5;
|
|
698
709
|
return this.recalculateSummary({
|
|
699
710
|
createIfMissing: true
|
|
700
711
|
});
|
|
701
|
-
case
|
|
712
|
+
case 5:
|
|
702
713
|
this.persistTempOrder();
|
|
703
714
|
return _context9.abrupt("return", tempOrder.products);
|
|
704
|
-
case
|
|
715
|
+
case 7:
|
|
705
716
|
case "end":
|
|
706
717
|
return _context9.stop();
|
|
707
718
|
}
|
|
@@ -737,7 +748,7 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
737
748
|
_context10.next = 12;
|
|
738
749
|
break;
|
|
739
750
|
}
|
|
740
|
-
products = formatV1Product(payload.products);
|
|
751
|
+
products = formatV1Product(filterProductsForScanOrderMore(payload.products));
|
|
741
752
|
_context10.next = 8;
|
|
742
753
|
return this.scanOrderMore({
|
|
743
754
|
query: {
|
|
@@ -1135,46 +1146,46 @@ export var OrderModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
1135
1146
|
*/
|
|
1136
1147
|
function populateSavedAmounts(productList, discountList) {
|
|
1137
1148
|
var savedMap = new Map();
|
|
1138
|
-
var
|
|
1139
|
-
|
|
1149
|
+
var _iterator2 = _createForOfIteratorHelper(productList),
|
|
1150
|
+
_step2;
|
|
1140
1151
|
try {
|
|
1141
|
-
for (
|
|
1142
|
-
var product =
|
|
1152
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
1153
|
+
var product = _step2.value;
|
|
1143
1154
|
var qty = product.num || 1;
|
|
1144
|
-
var
|
|
1145
|
-
|
|
1155
|
+
var _iterator4 = _createForOfIteratorHelper(product.discount_list || []),
|
|
1156
|
+
_step4;
|
|
1146
1157
|
try {
|
|
1147
|
-
for (
|
|
1158
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
1148
1159
|
var _pd$discount, _pd$metadata;
|
|
1149
|
-
var pd =
|
|
1160
|
+
var pd = _step4.value;
|
|
1150
1161
|
var discountKey = ((_pd$discount = pd.discount) === null || _pd$discount === void 0 ? void 0 : _pd$discount.resource_id) || pd.id;
|
|
1151
1162
|
if (discountKey == null) continue;
|
|
1152
1163
|
var amount = new Decimal(pd.amount || 0).times(qty).plus(((_pd$metadata = pd.metadata) === null || _pd$metadata === void 0 ? void 0 : _pd$metadata.product_discount_difference) || 0);
|
|
1153
1164
|
savedMap.set(discountKey, (savedMap.get(discountKey) || new Decimal(0)).plus(amount));
|
|
1154
1165
|
}
|
|
1155
1166
|
} catch (err) {
|
|
1156
|
-
|
|
1167
|
+
_iterator4.e(err);
|
|
1157
1168
|
} finally {
|
|
1158
|
-
|
|
1169
|
+
_iterator4.f();
|
|
1159
1170
|
}
|
|
1160
1171
|
}
|
|
1161
1172
|
} catch (err) {
|
|
1162
|
-
|
|
1173
|
+
_iterator2.e(err);
|
|
1163
1174
|
} finally {
|
|
1164
|
-
|
|
1175
|
+
_iterator2.f();
|
|
1165
1176
|
}
|
|
1166
|
-
var
|
|
1167
|
-
|
|
1177
|
+
var _iterator3 = _createForOfIteratorHelper(discountList),
|
|
1178
|
+
_step3;
|
|
1168
1179
|
try {
|
|
1169
|
-
for (
|
|
1170
|
-
var d =
|
|
1180
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
1181
|
+
var d = _step3.value;
|
|
1171
1182
|
var key = d.id;
|
|
1172
1183
|
d.savedAmount = d.isSelected && key != null && savedMap.has(key) ? savedMap.get(key).toNumber() : 0;
|
|
1173
1184
|
}
|
|
1174
1185
|
} catch (err) {
|
|
1175
|
-
|
|
1186
|
+
_iterator3.e(err);
|
|
1176
1187
|
} finally {
|
|
1177
|
-
|
|
1188
|
+
_iterator3.f();
|
|
1178
1189
|
}
|
|
1179
1190
|
}
|
|
1180
1191
|
}]);
|
|
@@ -72,6 +72,8 @@ export declare function buildSubmitPayload(params: {
|
|
|
72
72
|
type?: string;
|
|
73
73
|
enhance?: SubmitPayloadEnhancer;
|
|
74
74
|
}): ScanOrderSubmitPayload;
|
|
75
|
+
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
76
|
+
export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
|
|
75
77
|
export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
|
|
76
78
|
bundle: any[];
|
|
77
79
|
key: number | null;
|
|
@@ -18,7 +18,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
|
|
|
18
18
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
19
19
|
import dayjs from "dayjs";
|
|
20
20
|
import Decimal from 'decimal.js';
|
|
21
|
-
import { createEmptySummary } from "../../solution/ScanOrder/utils";
|
|
21
|
+
import { buildProductLineFingerprint, createEmptySummary } from "../../solution/ScanOrder/utils";
|
|
22
22
|
/**
|
|
23
23
|
* OrderModule 默认 Rules 钩子工厂。
|
|
24
24
|
*
|
|
@@ -47,7 +47,9 @@ export function createDefaultOrderRulesHooks() {
|
|
|
47
47
|
var _product$_origin, _product$_origin2, _product$_origin3, _product$_origin4;
|
|
48
48
|
return {
|
|
49
49
|
id: product.product_id,
|
|
50
|
-
|
|
50
|
+
// Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
|
|
51
|
+
// 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
|
|
52
|
+
_id: product.identity_key ? "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(product.identity_key) : "".concat(product.product_id, "_").concat(product.product_variant_id, "_").concat(buildProductLineFingerprint(product.product_option_item, product.product_bundle)),
|
|
51
53
|
price: product.selling_price,
|
|
52
54
|
total: new Decimal(product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
53
55
|
origin_total: new Decimal(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
@@ -390,6 +392,14 @@ export function buildSubmitPayload(params) {
|
|
|
390
392
|
now: now
|
|
391
393
|
}) : payload;
|
|
392
394
|
}
|
|
395
|
+
|
|
396
|
+
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
397
|
+
export function filterProductsForScanOrderMore(products) {
|
|
398
|
+
return (products || []).filter(function (p) {
|
|
399
|
+
var _p$metadata;
|
|
400
|
+
return ((_p$metadata = p.metadata) === null || _p$metadata === void 0 ? void 0 : _p$metadata.is_rule) !== true;
|
|
401
|
+
});
|
|
402
|
+
}
|
|
393
403
|
export function formatV1Product(products) {
|
|
394
404
|
return products.map(function (product) {
|
|
395
405
|
return {
|
|
@@ -30,7 +30,7 @@ import { OrderModule } from "../../modules/Order";
|
|
|
30
30
|
import { AccountHooks } from "../../modules/Account/types";
|
|
31
31
|
import { RegisterAndLoginHooks } from "../RegisterAndLogin/types";
|
|
32
32
|
import Decimal from 'decimal.js';
|
|
33
|
-
import { attachItemRuleLimitsToTopLevelProducts, buildProductKey, buildItemRuleBusinessData, collectLinkProductIdsFromReservationRules, computeResourceIsFull, createEmptySummary, getProductIdentityIndex, getSafeProductNum, hasCustomCapacityProduct, pickFirstCustomCapacityPaxBounds, normalizeEnabledItemRuleIds, normalizeOrderProduct, normalizeItemRuleStrategies, pickFirstDurationMinutesFromProducts, toNonNegativeInt, toPriceString, toBoolean, toPositiveString } from "./utils";
|
|
33
|
+
import { attachItemRuleLimitsToTopLevelProducts, buildProductKey, buildItemRuleBusinessData, collectLinkProductIdsFromReservationRules, computeResourceIsFull, createEmptySummary, getProductIdentityIndex, getSafeProductNum, hasCustomCapacityProduct, pickFirstCustomCapacityDimensionId, pickFirstCustomCapacityPaxBounds, normalizeEnabledItemRuleIds, normalizeOrderProduct, normalizeItemRuleStrategies, pickFirstDurationMinutesFromProducts, toNonNegativeInt, toPriceString, toBoolean, toPositiveString } from "./utils";
|
|
34
34
|
import { createModule } from "../BookingByStep/types";
|
|
35
35
|
import { ProductList } from "../../modules/ProductList";
|
|
36
36
|
import { ScheduleModule } from "../../modules/Schedule";
|
|
@@ -1195,6 +1195,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1195
1195
|
}, {
|
|
1196
1196
|
key: "buildSubmitPayloadEnhancer",
|
|
1197
1197
|
value: function buildSubmitPayloadEnhancer() {
|
|
1198
|
+
var _this5 = this;
|
|
1198
1199
|
var ruleProduct = this.enabledReservationRuleProducts[0];
|
|
1199
1200
|
var resourceState = this.store.resource;
|
|
1200
1201
|
var resourceSelectType = resourceState === null || resourceState === void 0 ? void 0 : resourceState.resourceSelectType;
|
|
@@ -1211,7 +1212,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1211
1212
|
return 1;
|
|
1212
1213
|
};
|
|
1213
1214
|
return function (payload, _ref3) {
|
|
1214
|
-
var _tempOrder$resource_i, _ref4, _pickOriginal, _resourceState$table_2, _resourceState$relati;
|
|
1215
|
+
var _tempOrder$resource_i, _ref4, _pickOriginal, _resourceState$table_2, _resourceState$relati, _tempOrder$metadata, _pickFirstCustomCapac;
|
|
1215
1216
|
var bookingUuid = _ref3.bookingUuid,
|
|
1216
1217
|
tempOrder = _ref3.tempOrder;
|
|
1217
1218
|
var resourceId = (_tempOrder$resource_i = tempOrder.resource_id) !== null && _tempOrder$resource_i !== void 0 ? _tempOrder$resource_i : resourceState === null || resourceState === void 0 ? void 0 : resourceState.relationId;
|
|
@@ -1234,7 +1235,11 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1234
1235
|
metadata: {}
|
|
1235
1236
|
} : undefined;
|
|
1236
1237
|
var ruleProductUid = ruleProduct ? createUuidV4() : undefined;
|
|
1237
|
-
|
|
1238
|
+
// 默认 resolveResourceCapacity(single 为桌台容量,其余多为 1);有 collect_pax 时 value 优先用人数
|
|
1239
|
+
var rawCollectPax = (_tempOrder$metadata = tempOrder.metadata) === null || _tempOrder$metadata === void 0 ? void 0 : _tempOrder$metadata.collect_pax;
|
|
1240
|
+
var hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== undefined && rawCollectPax !== '';
|
|
1241
|
+
var bookingCapacityValue = hasCollectPaxForCapacity ? normalizeSubmitCollectPaxValue(rawCollectPax) : resolveResourceCapacity();
|
|
1242
|
+
var bookingCapacityDimensionId = (_pickFirstCustomCapac = pickFirstCustomCapacityDimensionId(_this5.enabledReservationRuleProducts)) !== null && _pickFirstCustomCapac !== void 0 ? _pickFirstCustomCapac : 0;
|
|
1238
1243
|
var nextBookings = (payload.bookings || []).map(function (booking, idx) {
|
|
1239
1244
|
return _objectSpread(_objectSpread(_objectSpread({}, booking), {}, {
|
|
1240
1245
|
appointment_status: 'started',
|
|
@@ -1242,7 +1247,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1242
1247
|
resource_select_type: resourceSelectType
|
|
1243
1248
|
} : {}), resourceSelectType ? {
|
|
1244
1249
|
capacity: [{
|
|
1245
|
-
id:
|
|
1250
|
+
id: bookingCapacityDimensionId,
|
|
1246
1251
|
value: bookingCapacityValue,
|
|
1247
1252
|
name: ''
|
|
1248
1253
|
}]
|
|
@@ -1254,7 +1259,8 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1254
1259
|
} : {});
|
|
1255
1260
|
});
|
|
1256
1261
|
var nextProducts = _toConsumableArray(payload.products || []);
|
|
1257
|
-
|
|
1262
|
+
// 加餐(已有 order_id)走 scanOrderMore,原单已含 booking 规则行,勿再追加虚拟规则商品
|
|
1263
|
+
if (ruleProduct && ruleProductUid && !tempOrder.order_id) {
|
|
1258
1264
|
var _ruleProduct$price, _ref5, _ruleProduct$original, _ruleProduct$is_gst;
|
|
1259
1265
|
var sellingPrice = String((_ruleProduct$price = ruleProduct.price) !== null && _ruleProduct$price !== void 0 ? _ruleProduct$price : '0.00');
|
|
1260
1266
|
var originalPrice = String((_ref5 = (_ruleProduct$original = ruleProduct.original_price) !== null && _ruleProduct$original !== void 0 ? _ruleProduct$original : ruleProduct.price) !== null && _ref5 !== void 0 ? _ref5 : '0.00');
|
|
@@ -1719,7 +1725,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1719
1725
|
key: "ensureItemRuleConfigsLoaded",
|
|
1720
1726
|
value: function () {
|
|
1721
1727
|
var _ensureItemRuleConfigsLoaded = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25() {
|
|
1722
|
-
var
|
|
1728
|
+
var _this6 = this;
|
|
1723
1729
|
var loadedConfigs;
|
|
1724
1730
|
return _regeneratorRuntime().wrap(function _callee25$(_context25) {
|
|
1725
1731
|
while (1) switch (_context25.prev = _context25.next) {
|
|
@@ -1741,19 +1747,19 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
1741
1747
|
return _regeneratorRuntime().wrap(function _callee24$(_context24) {
|
|
1742
1748
|
while (1) switch (_context24.prev = _context24.next) {
|
|
1743
1749
|
case 0:
|
|
1744
|
-
runtimeConfig =
|
|
1750
|
+
runtimeConfig = _this6.getItemRuleRuntimeConfig();
|
|
1745
1751
|
staticConfigs = normalizeItemRuleStrategies(runtimeConfig.strategyConfigs);
|
|
1746
1752
|
if (!(staticConfigs.length > 0)) {
|
|
1747
1753
|
_context24.next = 6;
|
|
1748
1754
|
break;
|
|
1749
1755
|
}
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
return _context24.abrupt("return",
|
|
1756
|
+
_this6.itemRuleConfigs = staticConfigs;
|
|
1757
|
+
_this6.itemRuleEvaluator.setStrategyConfigs(staticConfigs);
|
|
1758
|
+
return _context24.abrupt("return", _this6.itemRuleConfigs);
|
|
1753
1759
|
case 6:
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
return _context24.abrupt("return",
|
|
1760
|
+
_this6.itemRuleConfigs = [];
|
|
1761
|
+
_this6.itemRuleEvaluator.setStrategyConfigs([]);
|
|
1762
|
+
return _context24.abrupt("return", _this6.itemRuleConfigs);
|
|
1757
1763
|
case 9:
|
|
1758
1764
|
case "end":
|
|
1759
1765
|
return _context24.stop();
|
|
@@ -2207,7 +2213,7 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2207
2213
|
var tableFormId = toPositiveString(detail === null || detail === void 0 ? void 0 : detail.form_id);
|
|
2208
2214
|
var formRecord = (_detail$form_record = detail === null || detail === void 0 ? void 0 : detail.form_record) !== null && _detail$form_record !== void 0 ? _detail$form_record : null;
|
|
2209
2215
|
// 是否允许加餐
|
|
2210
|
-
var allowSnack = ((_this$otherParams8 = this.otherParams) === null || _this$otherParams8 === void 0 || (_this$otherParams8 = _this$otherParams8.dineInConfig) === null || _this$otherParams8 === void 0 ? void 0 : _this$otherParams8['
|
|
2216
|
+
var allowSnack = ((_this$otherParams8 = this.otherParams) === null || _this$otherParams8 === void 0 || (_this$otherParams8 = _this$otherParams8.dineInConfig) === null || _this$otherParams8 === void 0 ? void 0 : _this$otherParams8['sale.allow_add_items']) || false;
|
|
2211
2217
|
// 开启同桌验证 - 本期没有这个配置,默认关掉
|
|
2212
2218
|
var deskmateValid = false;
|
|
2213
2219
|
var isExclusive = resourceSelectType === 'single';
|
|
@@ -2723,11 +2729,18 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2723
2729
|
return _setOtherParams.apply(this, arguments);
|
|
2724
2730
|
}
|
|
2725
2731
|
return setOtherParams;
|
|
2726
|
-
}() // ─── UI 状态缓存(按 cacheId 分桶,
|
|
2732
|
+
}() // ─── UI 状态缓存(按 cacheId 分桶,localStorage) ───
|
|
2727
2733
|
//
|
|
2728
2734
|
// 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
|
|
2729
2735
|
// 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
|
|
2730
2736
|
// 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
|
|
2737
|
+
//
|
|
2738
|
+
// 之所以用 localStorage 而不是 sessionStorage:
|
|
2739
|
+
// 1. 与 Order 模块 openCache 下的 tempOrder 同栈,购物车在 / UIState 在,行为对齐;
|
|
2740
|
+
// 2. pisell1.login 整页 OAuth 跳转在 H5 壳 / iOS Safari 场景下可能丢 sessionStorage,
|
|
2741
|
+
// 导致登录回跳后 gate 标记失效、pax 弹窗重开、落点错误;localStorage 稳定不受影响。
|
|
2742
|
+
// 3. 失效由上层显式控制:提交成功 clearStepCache / entryContext 不一致 clearUIState /
|
|
2743
|
+
// pendingStep 登录回调 deleteUIState,足够约束生命周期。
|
|
2731
2744
|
}, {
|
|
2732
2745
|
key: "getUIStateBucketKey",
|
|
2733
2746
|
value: function getUIStateBucketKey() {
|
|
@@ -2739,9 +2752,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2739
2752
|
value: function readUIStateBucket() {
|
|
2740
2753
|
var _this$window;
|
|
2741
2754
|
var key = this.getUIStateBucketKey();
|
|
2742
|
-
if (!key || !((_this$window = this.window) !== null && _this$window !== void 0 && _this$window.
|
|
2755
|
+
if (!key || !((_this$window = this.window) !== null && _this$window !== void 0 && _this$window.localStorage)) return {};
|
|
2743
2756
|
try {
|
|
2744
|
-
var raw = this.window.
|
|
2757
|
+
var raw = this.window.localStorage.getItem(key) || '{}';
|
|
2745
2758
|
var parsed = JSON.parse(raw);
|
|
2746
2759
|
return parsed && _typeof(parsed) === 'object' ? parsed : {};
|
|
2747
2760
|
} catch (_unused) {
|
|
@@ -2753,9 +2766,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2753
2766
|
value: function writeUIStateBucket(bucket) {
|
|
2754
2767
|
var _this$window2;
|
|
2755
2768
|
var key = this.getUIStateBucketKey();
|
|
2756
|
-
if (!key || !((_this$window2 = this.window) !== null && _this$window2 !== void 0 && _this$window2.
|
|
2769
|
+
if (!key || !((_this$window2 = this.window) !== null && _this$window2 !== void 0 && _this$window2.localStorage)) return;
|
|
2757
2770
|
try {
|
|
2758
|
-
this.window.
|
|
2771
|
+
this.window.localStorage.setItem(key, JSON.stringify(bucket));
|
|
2759
2772
|
} catch (error) {
|
|
2760
2773
|
console.warn('[ScanOrder] writeUIStateBucket failed', error);
|
|
2761
2774
|
}
|
|
@@ -2792,9 +2805,9 @@ export var ScanOrderImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2792
2805
|
value: function clearUIState() {
|
|
2793
2806
|
var _this$window3;
|
|
2794
2807
|
var key = this.getUIStateBucketKey();
|
|
2795
|
-
if (!key || !((_this$window3 = this.window) !== null && _this$window3 !== void 0 && _this$window3.
|
|
2808
|
+
if (!key || !((_this$window3 = this.window) !== null && _this$window3 !== void 0 && _this$window3.localStorage)) return;
|
|
2796
2809
|
try {
|
|
2797
|
-
this.window.
|
|
2810
|
+
this.window.localStorage.removeItem(key);
|
|
2798
2811
|
} catch (error) {
|
|
2799
2812
|
console.warn('[ScanOrder] clearUIState failed', error);
|
|
2800
2813
|
}
|
|
@@ -31,6 +31,9 @@ export interface ScanOrderOrderProductIdentity {
|
|
|
31
31
|
product_id: number | null;
|
|
32
32
|
product_variant_id: number;
|
|
33
33
|
identity_key?: string;
|
|
34
|
+
/** 参与合并/匹配;与 remove 通配语义见 isSkuOnlyDeleteIdentity */
|
|
35
|
+
product_option_item?: any[];
|
|
36
|
+
product_bundle?: any[];
|
|
34
37
|
}
|
|
35
38
|
export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
36
39
|
order_detail_id: number | null;
|
|
@@ -81,10 +81,27 @@ export declare function buildItemRuleBusinessData(params: {
|
|
|
81
81
|
itemRuleConfigs: StrategyConfig[];
|
|
82
82
|
}): ItemRuleBusinessData;
|
|
83
83
|
export declare function attachItemRuleLimitsToTopLevelProducts<T>(productList: T, limits: QuantityLimitResult[]): T;
|
|
84
|
+
/**
|
|
85
|
+
* 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
|
|
86
|
+
* 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildProductLineFingerprint(productOptionItem?: unknown, productBundle?: unknown): string;
|
|
89
|
+
/**
|
|
90
|
+
* removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
|
|
91
|
+
* 与显式 `product_option_item: []` 区分:后者只匹配「无选项」行。
|
|
92
|
+
*/
|
|
93
|
+
export declare function isSkuOnlyDeleteIdentity(x: ScanOrderOrderProductIdentity): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* 与常见 UI 约定一致:仅当存在**一条** `product_option_item` 时,
|
|
96
|
+
* `${product_id}_${option_group_id}_${product_option_item_id}_${num}` 可作为删除用 `identity_key`。
|
|
97
|
+
* 多小料行请使用加购时的 `identity_key` / `metadata.unique_identification_number` 或按 `product_option_item` 指纹删除。
|
|
98
|
+
*/
|
|
99
|
+
export declare function buildSyntheticSingleOptionIdentityKey(productId: number | null, productOptionItem: unknown): string | undefined;
|
|
84
100
|
/**
|
|
85
101
|
* 判断两个商品 identity 是否匹配。
|
|
86
|
-
*
|
|
87
|
-
*
|
|
102
|
+
* - 任一方带 `identity_key`:两侧都有则比字符串相等;仅一侧有则比「另一侧有效 key 集合」是否含该 key(见 collectLineIdentityKeyCandidates)。
|
|
103
|
+
* - 否则若任一方为「仅 SKU」删除通配(未声明 product_option_item / product_bundle 键),只比 SKU。
|
|
104
|
+
* - 否则比较选项 + 套餐指纹(同 SKU 且指纹相同才合并数量)。
|
|
88
105
|
*/
|
|
89
106
|
export declare function isIdentityMatch(a: ScanOrderOrderProductIdentity, b: ScanOrderOrderProductIdentity): boolean;
|
|
90
107
|
/**
|
|
@@ -129,3 +146,8 @@ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]
|
|
|
129
146
|
min?: number;
|
|
130
147
|
max?: number;
|
|
131
148
|
} | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
151
|
+
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
152
|
+
*/
|
|
153
|
+
export declare function pickFirstCustomCapacityDimensionId(products: ProductData[]): string | number | undefined;
|
|
@@ -366,15 +366,116 @@ export function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
|
|
|
366
366
|
return productList;
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
+
/**
|
|
370
|
+
* 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
|
|
371
|
+
* 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
|
|
372
|
+
*/
|
|
373
|
+
export function buildProductLineFingerprint(productOptionItem, productBundle) {
|
|
374
|
+
var optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
|
|
375
|
+
var normalizedOpts = optArr.map(function (item) {
|
|
376
|
+
var _item$price;
|
|
377
|
+
return {
|
|
378
|
+
product_option_item_id: Number(item === null || item === void 0 ? void 0 : item.product_option_item_id) || 0,
|
|
379
|
+
option_group_id: Number(item === null || item === void 0 ? void 0 : item.option_group_id) || 0,
|
|
380
|
+
num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
|
|
381
|
+
price: String((_item$price = item === null || item === void 0 ? void 0 : item.price) !== null && _item$price !== void 0 ? _item$price : '')
|
|
382
|
+
};
|
|
383
|
+
}).sort(function (p, q) {
|
|
384
|
+
if (p.product_option_item_id !== q.product_option_item_id) {
|
|
385
|
+
return p.product_option_item_id - q.product_option_item_id;
|
|
386
|
+
}
|
|
387
|
+
if (p.option_group_id !== q.option_group_id) return p.option_group_id - q.option_group_id;
|
|
388
|
+
if (p.num !== q.num) return p.num - q.num;
|
|
389
|
+
return p.price.localeCompare(q.price);
|
|
390
|
+
});
|
|
391
|
+
var bundleArr = Array.isArray(productBundle) ? productBundle : [];
|
|
392
|
+
var normalizedBundles = bundleArr.map(function (item) {
|
|
393
|
+
var _ref, _item$bundle_id;
|
|
394
|
+
return {
|
|
395
|
+
bundle_id: Number((_ref = (_item$bundle_id = item === null || item === void 0 ? void 0 : item.bundle_id) !== null && _item$bundle_id !== void 0 ? _item$bundle_id : item === null || item === void 0 ? void 0 : item.id) !== null && _ref !== void 0 ? _ref : 0) || 0,
|
|
396
|
+
product_id: Number(item === null || item === void 0 ? void 0 : item.product_id) || 0,
|
|
397
|
+
num: typeof (item === null || item === void 0 ? void 0 : item.num) === 'number' && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
|
|
398
|
+
};
|
|
399
|
+
}).sort(function (p, q) {
|
|
400
|
+
if (p.bundle_id !== q.bundle_id) return p.bundle_id - q.bundle_id;
|
|
401
|
+
if (p.product_id !== q.product_id) return p.product_id - q.product_id;
|
|
402
|
+
return p.num - q.num;
|
|
403
|
+
});
|
|
404
|
+
return JSON.stringify([normalizedOpts, normalizedBundles]);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
|
|
409
|
+
* 与显式 `product_option_item: []` 区分:后者只匹配「无选项」行。
|
|
410
|
+
*/
|
|
411
|
+
export function isSkuOnlyDeleteIdentity(x) {
|
|
412
|
+
if (x.identity_key) return false;
|
|
413
|
+
return !('product_option_item' in x) && !('product_bundle' in x);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* 与常见 UI 约定一致:仅当存在**一条** `product_option_item` 时,
|
|
418
|
+
* `${product_id}_${option_group_id}_${product_option_item_id}_${num}` 可作为删除用 `identity_key`。
|
|
419
|
+
* 多小料行请使用加购时的 `identity_key` / `metadata.unique_identification_number` 或按 `product_option_item` 指纹删除。
|
|
420
|
+
*/
|
|
421
|
+
export function buildSyntheticSingleOptionIdentityKey(productId, productOptionItem) {
|
|
422
|
+
if (productId == null || !Number.isFinite(Number(productId))) return undefined;
|
|
423
|
+
var opts = Array.isArray(productOptionItem) ? productOptionItem : [];
|
|
424
|
+
if (opts.length !== 1) return undefined;
|
|
425
|
+
var o = opts[0];
|
|
426
|
+
var gid = Number(o === null || o === void 0 ? void 0 : o.option_group_id) || 0;
|
|
427
|
+
var oid = Number(o === null || o === void 0 ? void 0 : o.product_option_item_id) || 0;
|
|
428
|
+
var rawNum = o === null || o === void 0 ? void 0 : o.num;
|
|
429
|
+
var n = typeof rawNum === 'number' && !Number.isNaN(rawNum) ? Math.max(1, Math.floor(rawNum)) : 1;
|
|
430
|
+
return "".concat(productId, "_").concat(gid, "_").concat(oid, "_").concat(n);
|
|
431
|
+
}
|
|
432
|
+
function collectLineIdentityKeyCandidates(x) {
|
|
433
|
+
var _row$metadata;
|
|
434
|
+
var out = new Set();
|
|
435
|
+
var row = x;
|
|
436
|
+
if (typeof row.identity_key === 'string' && row.identity_key.length > 0) {
|
|
437
|
+
out.add(row.identity_key);
|
|
438
|
+
}
|
|
439
|
+
var uid = (_row$metadata = row.metadata) === null || _row$metadata === void 0 ? void 0 : _row$metadata.unique_identification_number;
|
|
440
|
+
if (typeof uid === 'string' && uid.length > 0) out.add(uid);
|
|
441
|
+
var synthetic = buildSyntheticSingleOptionIdentityKey(row.product_id, row.product_option_item);
|
|
442
|
+
if (synthetic) out.add(synthetic);
|
|
443
|
+
var opts = 'product_option_item' in row && Array.isArray(row.product_option_item) ? row.product_option_item : [];
|
|
444
|
+
var bundles = 'product_bundle' in row && Array.isArray(row.product_bundle) ? row.product_bundle : [];
|
|
445
|
+
// 无小料且无套餐时,与常见 UI 约定对齐:`${product_id}_${product_variant_id}_0`
|
|
446
|
+
if (opts.length === 0 && bundles.length === 0 && row.product_id != null && Number.isFinite(Number(row.product_id))) {
|
|
447
|
+
var vid = Number(row.product_variant_id) || 0;
|
|
448
|
+
out.add("".concat(row.product_id, "_").concat(vid, "_0"));
|
|
449
|
+
}
|
|
450
|
+
return out;
|
|
451
|
+
}
|
|
452
|
+
function fingerprintForIdentityWithOptionKeys(x) {
|
|
453
|
+
var row = x;
|
|
454
|
+
var opts = 'product_option_item' in row ? Array.isArray(row.product_option_item) ? row.product_option_item : [] : [];
|
|
455
|
+
var buds = 'product_bundle' in row ? Array.isArray(row.product_bundle) ? row.product_bundle : [] : [];
|
|
456
|
+
return buildProductLineFingerprint(opts, buds);
|
|
457
|
+
}
|
|
458
|
+
|
|
369
459
|
/**
|
|
370
460
|
* 判断两个商品 identity 是否匹配。
|
|
371
|
-
*
|
|
372
|
-
*
|
|
461
|
+
* - 任一方带 `identity_key`:两侧都有则比字符串相等;仅一侧有则比「另一侧有效 key 集合」是否含该 key(见 collectLineIdentityKeyCandidates)。
|
|
462
|
+
* - 否则若任一方为「仅 SKU」删除通配(未声明 product_option_item / product_bundle 键),只比 SKU。
|
|
463
|
+
* - 否则比较选项 + 套餐指纹(同 SKU 且指纹相同才合并数量)。
|
|
373
464
|
*/
|
|
374
465
|
export function isIdentityMatch(a, b) {
|
|
375
466
|
if (a.product_id !== b.product_id || a.product_variant_id !== b.product_variant_id) return false;
|
|
376
|
-
if (
|
|
377
|
-
|
|
467
|
+
if (a.identity_key || b.identity_key) {
|
|
468
|
+
if (a.identity_key && b.identity_key) return a.identity_key === b.identity_key;
|
|
469
|
+
if (a.identity_key && !b.identity_key) {
|
|
470
|
+
return collectLineIdentityKeyCandidates(b).has(a.identity_key);
|
|
471
|
+
}
|
|
472
|
+
if (!a.identity_key && b.identity_key) {
|
|
473
|
+
return collectLineIdentityKeyCandidates(a).has(b.identity_key);
|
|
474
|
+
}
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
if (isSkuOnlyDeleteIdentity(a) || isSkuOnlyDeleteIdentity(b)) return true;
|
|
478
|
+
return fingerprintForIdentityWithOptionKeys(a) === fingerprintForIdentityWithOptionKeys(b);
|
|
378
479
|
}
|
|
379
480
|
|
|
380
481
|
/**
|
|
@@ -414,14 +515,14 @@ export function normalizeOrderProduct(product) {
|
|
|
414
515
|
metadata.main_product_selling_price = resolvedSellingPrice;
|
|
415
516
|
}
|
|
416
517
|
if (metadata.source_product_price === undefined) {
|
|
417
|
-
var
|
|
418
|
-
metadata.source_product_price = (
|
|
518
|
+
var _ref2, _product$_origin$pric, _product$_origin, _product$_origin2;
|
|
519
|
+
metadata.source_product_price = (_ref2 = (_product$_origin$pric = (_product$_origin = product._origin) === null || _product$_origin === void 0 ? void 0 : _product$_origin.price) !== null && _product$_origin$pric !== void 0 ? _product$_origin$pric : (_product$_origin2 = product._origin) === null || _product$_origin2 === void 0 ? void 0 : _product$_origin2.base_price) !== null && _ref2 !== void 0 ? _ref2 : resolvedSellingPrice;
|
|
419
520
|
}
|
|
420
521
|
var normalizedBundle = (product.product_bundle || []).map(function (item) {
|
|
421
|
-
var
|
|
522
|
+
var _ref3, _item$bundle_selling_, _ref4, _ref5, _item$custom_price;
|
|
422
523
|
return _objectSpread(_objectSpread({}, item), {}, {
|
|
423
|
-
bundle_selling_price: (
|
|
424
|
-
custom_price: (
|
|
524
|
+
bundle_selling_price: (_ref3 = (_item$bundle_selling_ = item.bundle_selling_price) !== null && _item$bundle_selling_ !== void 0 ? _item$bundle_selling_ : item.price) !== null && _ref3 !== void 0 ? _ref3 : '0.00',
|
|
525
|
+
custom_price: (_ref4 = (_ref5 = (_item$custom_price = item.custom_price) !== null && _item$custom_price !== void 0 ? _item$custom_price : item.bundle_selling_price) !== null && _ref5 !== void 0 ? _ref5 : item.price) !== null && _ref4 !== void 0 ? _ref4 : '0.00'
|
|
425
526
|
});
|
|
426
527
|
});
|
|
427
528
|
return {
|
|
@@ -580,4 +681,36 @@ export function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
580
681
|
_iterator9.f();
|
|
581
682
|
}
|
|
582
683
|
return undefined;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
688
|
+
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
689
|
+
*/
|
|
690
|
+
export function pickFirstCustomCapacityDimensionId(products) {
|
|
691
|
+
var _iterator10 = _createForOfIteratorHelper(products),
|
|
692
|
+
_step10;
|
|
693
|
+
try {
|
|
694
|
+
for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
|
|
695
|
+
var p = _step10.value;
|
|
696
|
+
var cap = p === null || p === void 0 ? void 0 : p.capacity;
|
|
697
|
+
if (!cap || cap.type !== 'custom') continue;
|
|
698
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0) continue;
|
|
699
|
+
var row = cap.custom[0];
|
|
700
|
+
if (!row || _typeof(row) !== 'object') continue;
|
|
701
|
+
var id = row.id;
|
|
702
|
+
if (id === null || id === undefined || id === '') continue;
|
|
703
|
+
if (typeof id === 'number' && Number.isFinite(id)) return id;
|
|
704
|
+
if (typeof id === 'string') {
|
|
705
|
+
var trimmed = id.trim();
|
|
706
|
+
if (!trimmed) continue;
|
|
707
|
+
return trimmed;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
} catch (err) {
|
|
711
|
+
_iterator10.e(err);
|
|
712
|
+
} finally {
|
|
713
|
+
_iterator10.f();
|
|
714
|
+
}
|
|
715
|
+
return undefined;
|
|
583
716
|
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
-
mod
|
|
26
|
-
));
|
|
27
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
-
|
|
29
|
-
// src/model/strategy/adapter/promotion/index.ts
|
|
30
|
-
var promotion_exports = {};
|
|
31
|
-
__export(promotion_exports, {
|
|
32
|
-
BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
|
|
33
|
-
PromotionAdapter: () => import_adapter.PromotionAdapter,
|
|
34
|
-
PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
|
|
35
|
-
X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
|
|
36
|
-
default: () => import_adapter2.default
|
|
37
|
-
});
|
|
38
|
-
module.exports = __toCommonJS(promotion_exports);
|
|
39
|
-
var import_evaluator = require("./evaluator");
|
|
40
|
-
var import_adapter = require("./adapter");
|
|
41
|
-
var import_adapter2 = __toESM(require("./adapter"));
|
|
42
|
-
var import_examples = require("./examples");
|
|
43
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
44
|
-
0 && (module.exports = {
|
|
45
|
-
BUY_X_GET_Y_FREE_STRATEGY,
|
|
46
|
-
PromotionAdapter,
|
|
47
|
-
PromotionEvaluator,
|
|
48
|
-
X_ITEMS_FOR_Y_PRICE_STRATEGY
|
|
49
|
-
});
|
|
@@ -288,6 +288,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
288
288
|
this.window.localStorage.removeItem(key);
|
|
289
289
|
return;
|
|
290
290
|
}
|
|
291
|
+
if (Array.isArray(parsedData.products)) {
|
|
292
|
+
for (const p of parsedData.products) {
|
|
293
|
+
if (!p || typeof p !== "object")
|
|
294
|
+
continue;
|
|
295
|
+
if (!Array.isArray(p.product_option_item)) {
|
|
296
|
+
p.product_option_item = [];
|
|
297
|
+
}
|
|
298
|
+
if (!Array.isArray(p.product_bundle)) {
|
|
299
|
+
p.product_bundle = [];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
291
303
|
this.store.tempOrder = parsedData;
|
|
292
304
|
} catch {
|
|
293
305
|
(_b = (_a = this.window) == null ? void 0 : _a.localStorage) == null ? void 0 : _b.removeItem(key);
|
|
@@ -444,18 +456,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
444
456
|
}
|
|
445
457
|
async removeProductFromOrder(identity) {
|
|
446
458
|
const tempOrder = this.ensureTempOrder();
|
|
447
|
-
const beforeProducts = tempOrder.products;
|
|
448
459
|
tempOrder.products = tempOrder.products.filter(
|
|
449
460
|
(item) => !(0, import_utils3.isIdentityMatch)(item, identity)
|
|
450
461
|
);
|
|
451
|
-
const removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
|
|
452
|
-
if (removedByStrictIdentity === 0 && identity.identity_key) {
|
|
453
|
-
tempOrder.products = tempOrder.products.filter((item) => {
|
|
454
|
-
const isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
|
|
455
|
-
const hasNoIdentityKey = !item.identity_key;
|
|
456
|
-
return !(isSameProduct && hasNoIdentityKey);
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
462
|
this.applyDiscount();
|
|
460
463
|
await this.recalculateSummary({ createIfMissing: true });
|
|
461
464
|
this.persistTempOrder();
|
|
@@ -477,7 +480,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
477
480
|
});
|
|
478
481
|
let result;
|
|
479
482
|
if (tempOrder.order_id) {
|
|
480
|
-
|
|
483
|
+
let products = (0, import_utils.formatV1Product)(
|
|
484
|
+
(0, import_utils.filterProductsForScanOrderMore)(payload.products)
|
|
485
|
+
);
|
|
481
486
|
const moreResult = await this.scanOrderMore({
|
|
482
487
|
query: {
|
|
483
488
|
order_id: tempOrder.order_id,
|
|
@@ -72,6 +72,8 @@ export declare function buildSubmitPayload(params: {
|
|
|
72
72
|
type?: string;
|
|
73
73
|
enhance?: SubmitPayloadEnhancer;
|
|
74
74
|
}): ScanOrderSubmitPayload;
|
|
75
|
+
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
76
|
+
export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
|
|
75
77
|
export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
|
|
76
78
|
bundle: any[];
|
|
77
79
|
key: number | null;
|
|
@@ -34,6 +34,7 @@ __export(utils_exports, {
|
|
|
34
34
|
createDefaultTempOrder: () => createDefaultTempOrder,
|
|
35
35
|
createEmptySummary: () => import_utils2.createEmptySummary,
|
|
36
36
|
createUuidV4: () => createUuidV4,
|
|
37
|
+
filterProductsForScanOrderMore: () => filterProductsForScanOrderMore,
|
|
37
38
|
formatDateTime: () => formatDateTime,
|
|
38
39
|
formatV1Product: () => formatV1Product,
|
|
39
40
|
generateDuration: () => generateDuration,
|
|
@@ -59,7 +60,12 @@ function createDefaultOrderRulesHooks() {
|
|
|
59
60
|
var _a, _b, _c, _d;
|
|
60
61
|
return {
|
|
61
62
|
id: product.product_id,
|
|
62
|
-
_id
|
|
63
|
+
// Rules 引擎用 _id 作为 processedProductsMap 键;必须与购物车行级 identity 一致,
|
|
64
|
+
// 否则同 SKU 不同小料会在 calcDiscount 重组时互相覆盖。
|
|
65
|
+
_id: product.identity_key ? `${product.product_id}_${product.product_variant_id}_${product.identity_key}` : `${product.product_id}_${product.product_variant_id}_${(0, import_utils.buildProductLineFingerprint)(
|
|
66
|
+
product.product_option_item,
|
|
67
|
+
product.product_bundle
|
|
68
|
+
)}`,
|
|
63
69
|
price: product.selling_price,
|
|
64
70
|
total: new import_decimal.default(product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
65
71
|
origin_total: new import_decimal.default(product.original_price || product.selling_price || 0).times(product.num || 1).toNumber(),
|
|
@@ -366,6 +372,12 @@ function buildSubmitPayload(params) {
|
|
|
366
372
|
};
|
|
367
373
|
return enhance ? enhance(payload, { tempOrder, bookingUuid, now }) : payload;
|
|
368
374
|
}
|
|
375
|
+
function filterProductsForScanOrderMore(products) {
|
|
376
|
+
return (products || []).filter((p) => {
|
|
377
|
+
var _a;
|
|
378
|
+
return ((_a = p.metadata) == null ? void 0 : _a.is_rule) !== true;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
369
381
|
function formatV1Product(products) {
|
|
370
382
|
return products.map((product) => {
|
|
371
383
|
return {
|
|
@@ -388,6 +400,7 @@ function formatV1Product(products) {
|
|
|
388
400
|
createDefaultTempOrder,
|
|
389
401
|
createEmptySummary,
|
|
390
402
|
createUuidV4,
|
|
403
|
+
filterProductsForScanOrderMore,
|
|
391
404
|
formatDateTime,
|
|
392
405
|
formatV1Product,
|
|
393
406
|
generateDuration,
|
|
@@ -741,7 +741,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
741
741
|
return 1;
|
|
742
742
|
};
|
|
743
743
|
return (payload, { bookingUuid, tempOrder }) => {
|
|
744
|
-
var _a;
|
|
744
|
+
var _a, _b;
|
|
745
745
|
const resourceId = tempOrder.resource_id ?? (resourceState == null ? void 0 : resourceState.relationId);
|
|
746
746
|
const pickOriginal = (value) => {
|
|
747
747
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
@@ -762,20 +762,31 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
762
762
|
metadata: {}
|
|
763
763
|
} : void 0;
|
|
764
764
|
const ruleProductUid = ruleProduct ? (0, import_utils2.createUuidV4)() : void 0;
|
|
765
|
-
const
|
|
765
|
+
const rawCollectPax = (_b = tempOrder.metadata) == null ? void 0 : _b.collect_pax;
|
|
766
|
+
const hasCollectPaxForCapacity = rawCollectPax !== null && rawCollectPax !== void 0 && rawCollectPax !== "";
|
|
767
|
+
const bookingCapacityValue = hasCollectPaxForCapacity ? (0, import_utils2.normalizeSubmitCollectPaxValue)(rawCollectPax) : resolveResourceCapacity();
|
|
768
|
+
const bookingCapacityDimensionId = (0, import_utils.pickFirstCustomCapacityDimensionId)(this.enabledReservationRuleProducts) ?? 0;
|
|
766
769
|
const nextBookings = (payload.bookings || []).map((booking, idx) => ({
|
|
767
770
|
...booking,
|
|
768
771
|
appointment_status: "started",
|
|
769
772
|
metadata: {
|
|
770
773
|
...booking.metadata || {},
|
|
771
774
|
...resourceSelectType ? { resource_select_type: resourceSelectType } : {},
|
|
772
|
-
...resourceSelectType ? {
|
|
775
|
+
...resourceSelectType ? {
|
|
776
|
+
capacity: [
|
|
777
|
+
{
|
|
778
|
+
id: bookingCapacityDimensionId,
|
|
779
|
+
value: bookingCapacityValue,
|
|
780
|
+
name: ""
|
|
781
|
+
}
|
|
782
|
+
]
|
|
783
|
+
} : {}
|
|
773
784
|
},
|
|
774
785
|
...idx === 0 && resourceEntry ? { resources: [resourceEntry] } : {},
|
|
775
786
|
...idx === 0 && ruleProductUid ? { product_uid: ruleProductUid } : {}
|
|
776
787
|
}));
|
|
777
788
|
const nextProducts = [...payload.products || []];
|
|
778
|
-
if (ruleProduct && ruleProductUid) {
|
|
789
|
+
if (ruleProduct && ruleProductUid && !tempOrder.order_id) {
|
|
779
790
|
const sellingPrice = String(ruleProduct.price ?? "0.00");
|
|
780
791
|
const originalPrice = String(
|
|
781
792
|
ruleProduct.original_price ?? ruleProduct.price ?? "0.00"
|
|
@@ -1261,7 +1272,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1261
1272
|
const relationId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_record_id);
|
|
1262
1273
|
const tableFormId = (0, import_utils.toPositiveString)(detail == null ? void 0 : detail.form_id);
|
|
1263
1274
|
const formRecord = (detail == null ? void 0 : detail.form_record) ?? null;
|
|
1264
|
-
const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["
|
|
1275
|
+
const allowSnack = ((_b = (_a = this.otherParams) == null ? void 0 : _a.dineInConfig) == null ? void 0 : _b["sale.allow_add_items"]) || false;
|
|
1265
1276
|
const deskmateValid = false;
|
|
1266
1277
|
const isExclusive = resourceSelectType === "single";
|
|
1267
1278
|
const isFull = (0, import_utils.computeResourceIsFull)({
|
|
@@ -1620,10 +1631,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1620
1631
|
readUIStateBucket() {
|
|
1621
1632
|
var _a;
|
|
1622
1633
|
const key = this.getUIStateBucketKey();
|
|
1623
|
-
if (!key || !((_a = this.window) == null ? void 0 : _a.
|
|
1634
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
|
|
1624
1635
|
return {};
|
|
1625
1636
|
try {
|
|
1626
|
-
const raw = this.window.
|
|
1637
|
+
const raw = this.window.localStorage.getItem(key) || "{}";
|
|
1627
1638
|
const parsed = JSON.parse(raw);
|
|
1628
1639
|
return parsed && typeof parsed === "object" ? parsed : {};
|
|
1629
1640
|
} catch {
|
|
@@ -1633,10 +1644,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1633
1644
|
writeUIStateBucket(bucket) {
|
|
1634
1645
|
var _a;
|
|
1635
1646
|
const key = this.getUIStateBucketKey();
|
|
1636
|
-
if (!key || !((_a = this.window) == null ? void 0 : _a.
|
|
1647
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
|
|
1637
1648
|
return;
|
|
1638
1649
|
try {
|
|
1639
|
-
this.window.
|
|
1650
|
+
this.window.localStorage.setItem(key, JSON.stringify(bucket));
|
|
1640
1651
|
} catch (error) {
|
|
1641
1652
|
console.warn("[ScanOrder] writeUIStateBucket failed", error);
|
|
1642
1653
|
}
|
|
@@ -1667,10 +1678,10 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1667
1678
|
clearUIState() {
|
|
1668
1679
|
var _a;
|
|
1669
1680
|
const key = this.getUIStateBucketKey();
|
|
1670
|
-
if (!key || !((_a = this.window) == null ? void 0 : _a.
|
|
1681
|
+
if (!key || !((_a = this.window) == null ? void 0 : _a.localStorage))
|
|
1671
1682
|
return;
|
|
1672
1683
|
try {
|
|
1673
|
-
this.window.
|
|
1684
|
+
this.window.localStorage.removeItem(key);
|
|
1674
1685
|
} catch (error) {
|
|
1675
1686
|
console.warn("[ScanOrder] clearUIState failed", error);
|
|
1676
1687
|
}
|
|
@@ -1726,11 +1737,18 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
|
|
|
1726
1737
|
};
|
|
1727
1738
|
var ScanOrderImpl = _ScanOrderImpl;
|
|
1728
1739
|
ScanOrderImpl.PISELL1_LOGIN_SUCCESS = "pisell1.login.success";
|
|
1729
|
-
// ─── UI 状态缓存(按 cacheId 分桶,
|
|
1740
|
+
// ─── UI 状态缓存(按 cacheId 分桶,localStorage) ───
|
|
1730
1741
|
//
|
|
1731
1742
|
// 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
|
|
1732
1743
|
// 桶键:pisell.scanOrder.uiState:<cacheId>;内部以 JSON object 形式存储多个字段。
|
|
1733
1744
|
// 无 cacheId 时所有方法自动降级为 no-op,上层不用判空。
|
|
1745
|
+
//
|
|
1746
|
+
// 之所以用 localStorage 而不是 sessionStorage:
|
|
1747
|
+
// 1. 与 Order 模块 openCache 下的 tempOrder 同栈,购物车在 / UIState 在,行为对齐;
|
|
1748
|
+
// 2. pisell1.login 整页 OAuth 跳转在 H5 壳 / iOS Safari 场景下可能丢 sessionStorage,
|
|
1749
|
+
// 导致登录回跳后 gate 标记失效、pax 弹窗重开、落点错误;localStorage 稳定不受影响。
|
|
1750
|
+
// 3. 失效由上层显式控制:提交成功 clearStepCache / entryContext 不一致 clearUIState /
|
|
1751
|
+
// pendingStep 登录回调 deleteUIState,足够约束生命周期。
|
|
1734
1752
|
ScanOrderImpl.UI_STATE_KEY_PREFIX = "pisell.scanOrder.uiState:";
|
|
1735
1753
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1736
1754
|
0 && (module.exports = {
|
|
@@ -31,6 +31,9 @@ export interface ScanOrderOrderProductIdentity {
|
|
|
31
31
|
product_id: number | null;
|
|
32
32
|
product_variant_id: number;
|
|
33
33
|
identity_key?: string;
|
|
34
|
+
/** 参与合并/匹配;与 remove 通配语义见 isSkuOnlyDeleteIdentity */
|
|
35
|
+
product_option_item?: any[];
|
|
36
|
+
product_bundle?: any[];
|
|
34
37
|
}
|
|
35
38
|
export interface ScanOrderOrderProduct extends ScanOrderOrderProductIdentity {
|
|
36
39
|
order_detail_id: number | null;
|
|
@@ -81,10 +81,27 @@ export declare function buildItemRuleBusinessData(params: {
|
|
|
81
81
|
itemRuleConfigs: StrategyConfig[];
|
|
82
82
|
}): ItemRuleBusinessData;
|
|
83
83
|
export declare function attachItemRuleLimitsToTopLevelProducts<T>(productList: T, limits: QuantityLimitResult[]): T;
|
|
84
|
+
/**
|
|
85
|
+
* 将选项行 / 套餐行归一成稳定 JSON,用于「同 SKU 是否合并」判断。
|
|
86
|
+
* 数组元素先按主键排序再序列化,避免顺序差异导致误判为不同行。
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildProductLineFingerprint(productOptionItem?: unknown, productBundle?: unknown): string;
|
|
89
|
+
/**
|
|
90
|
+
* removeProductFromOrder 仅传 SKU 时的通配 identity(对象上未声明选项键)。
|
|
91
|
+
* 与显式 `product_option_item: []` 区分:后者只匹配「无选项」行。
|
|
92
|
+
*/
|
|
93
|
+
export declare function isSkuOnlyDeleteIdentity(x: ScanOrderOrderProductIdentity): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* 与常见 UI 约定一致:仅当存在**一条** `product_option_item` 时,
|
|
96
|
+
* `${product_id}_${option_group_id}_${product_option_item_id}_${num}` 可作为删除用 `identity_key`。
|
|
97
|
+
* 多小料行请使用加购时的 `identity_key` / `metadata.unique_identification_number` 或按 `product_option_item` 指纹删除。
|
|
98
|
+
*/
|
|
99
|
+
export declare function buildSyntheticSingleOptionIdentityKey(productId: number | null, productOptionItem: unknown): string | undefined;
|
|
84
100
|
/**
|
|
85
101
|
* 判断两个商品 identity 是否匹配。
|
|
86
|
-
*
|
|
87
|
-
*
|
|
102
|
+
* - 任一方带 `identity_key`:两侧都有则比字符串相等;仅一侧有则比「另一侧有效 key 集合」是否含该 key(见 collectLineIdentityKeyCandidates)。
|
|
103
|
+
* - 否则若任一方为「仅 SKU」删除通配(未声明 product_option_item / product_bundle 键),只比 SKU。
|
|
104
|
+
* - 否则比较选项 + 套餐指纹(同 SKU 且指纹相同才合并数量)。
|
|
88
105
|
*/
|
|
89
106
|
export declare function isIdentityMatch(a: ScanOrderOrderProductIdentity, b: ScanOrderOrderProductIdentity): boolean;
|
|
90
107
|
/**
|
|
@@ -129,3 +146,8 @@ export declare function pickFirstCustomCapacityPaxBounds(products: ProductData[]
|
|
|
129
146
|
min?: number;
|
|
130
147
|
max?: number;
|
|
131
148
|
} | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* 第一个 `capacity.type === 'custom'` 的商品,取其 `custom[0].id`(提交 booking metadata.capacity 维度 id)。
|
|
151
|
+
* 无匹配时返回 `undefined`,调用方应回退为 `0`。
|
|
152
|
+
*/
|
|
153
|
+
export declare function pickFirstCustomCapacityDimensionId(products: ProductData[]): string | number | undefined;
|
|
@@ -33,7 +33,9 @@ __export(utils_exports, {
|
|
|
33
33
|
attachItemRuleLimitsToTopLevelProducts: () => attachItemRuleLimitsToTopLevelProducts,
|
|
34
34
|
buildItemRuleBusinessData: () => buildItemRuleBusinessData,
|
|
35
35
|
buildProductKey: () => buildProductKey,
|
|
36
|
+
buildProductLineFingerprint: () => buildProductLineFingerprint,
|
|
36
37
|
buildQuantityLimitIndex: () => buildQuantityLimitIndex,
|
|
38
|
+
buildSyntheticSingleOptionIdentityKey: () => buildSyntheticSingleOptionIdentityKey,
|
|
37
39
|
collectLinkProductIdsFromReservationRules: () => collectLinkProductIdsFromReservationRules,
|
|
38
40
|
computeResourceIsFull: () => computeResourceIsFull,
|
|
39
41
|
createEmptySummary: () => createEmptySummary,
|
|
@@ -44,9 +46,11 @@ __export(utils_exports, {
|
|
|
44
46
|
getTopLevelVariantId: () => getTopLevelVariantId,
|
|
45
47
|
hasCustomCapacityProduct: () => hasCustomCapacityProduct,
|
|
46
48
|
isIdentityMatch: () => isIdentityMatch,
|
|
49
|
+
isSkuOnlyDeleteIdentity: () => isSkuOnlyDeleteIdentity,
|
|
47
50
|
normalizeEnabledItemRuleIds: () => normalizeEnabledItemRuleIds,
|
|
48
51
|
normalizeItemRuleStrategies: () => normalizeItemRuleStrategies,
|
|
49
52
|
normalizeOrderProduct: () => normalizeOrderProduct,
|
|
53
|
+
pickFirstCustomCapacityDimensionId: () => pickFirstCustomCapacityDimensionId,
|
|
50
54
|
pickFirstCustomCapacityPaxBounds: () => pickFirstCustomCapacityPaxBounds,
|
|
51
55
|
pickFirstDurationMinutesFromProducts: () => pickFirstDurationMinutesFromProducts,
|
|
52
56
|
resolveSkuMatchedQuantityLimits: () => resolveSkuMatchedQuantityLimits,
|
|
@@ -338,12 +342,102 @@ function attachItemRuleLimitsToTopLevelProducts(productList, limits) {
|
|
|
338
342
|
}
|
|
339
343
|
return productList;
|
|
340
344
|
}
|
|
345
|
+
function buildProductLineFingerprint(productOptionItem, productBundle) {
|
|
346
|
+
const optArr = Array.isArray(productOptionItem) ? productOptionItem : [];
|
|
347
|
+
const normalizedOpts = optArr.map((item) => ({
|
|
348
|
+
product_option_item_id: Number(item == null ? void 0 : item.product_option_item_id) || 0,
|
|
349
|
+
option_group_id: Number(item == null ? void 0 : item.option_group_id) || 0,
|
|
350
|
+
num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1,
|
|
351
|
+
price: String((item == null ? void 0 : item.price) ?? "")
|
|
352
|
+
})).sort((p, q) => {
|
|
353
|
+
if (p.product_option_item_id !== q.product_option_item_id) {
|
|
354
|
+
return p.product_option_item_id - q.product_option_item_id;
|
|
355
|
+
}
|
|
356
|
+
if (p.option_group_id !== q.option_group_id)
|
|
357
|
+
return p.option_group_id - q.option_group_id;
|
|
358
|
+
if (p.num !== q.num)
|
|
359
|
+
return p.num - q.num;
|
|
360
|
+
return p.price.localeCompare(q.price);
|
|
361
|
+
});
|
|
362
|
+
const bundleArr = Array.isArray(productBundle) ? productBundle : [];
|
|
363
|
+
const normalizedBundles = bundleArr.map((item) => ({
|
|
364
|
+
bundle_id: Number((item == null ? void 0 : item.bundle_id) ?? (item == null ? void 0 : item.id) ?? 0) || 0,
|
|
365
|
+
product_id: Number(item == null ? void 0 : item.product_id) || 0,
|
|
366
|
+
num: typeof (item == null ? void 0 : item.num) === "number" && !Number.isNaN(item.num) ? Math.max(1, Math.floor(item.num)) : 1
|
|
367
|
+
})).sort((p, q) => {
|
|
368
|
+
if (p.bundle_id !== q.bundle_id)
|
|
369
|
+
return p.bundle_id - q.bundle_id;
|
|
370
|
+
if (p.product_id !== q.product_id)
|
|
371
|
+
return p.product_id - q.product_id;
|
|
372
|
+
return p.num - q.num;
|
|
373
|
+
});
|
|
374
|
+
return JSON.stringify([normalizedOpts, normalizedBundles]);
|
|
375
|
+
}
|
|
376
|
+
function isSkuOnlyDeleteIdentity(x) {
|
|
377
|
+
if (x.identity_key)
|
|
378
|
+
return false;
|
|
379
|
+
return !("product_option_item" in x) && !("product_bundle" in x);
|
|
380
|
+
}
|
|
381
|
+
function buildSyntheticSingleOptionIdentityKey(productId, productOptionItem) {
|
|
382
|
+
if (productId == null || !Number.isFinite(Number(productId)))
|
|
383
|
+
return void 0;
|
|
384
|
+
const opts = Array.isArray(productOptionItem) ? productOptionItem : [];
|
|
385
|
+
if (opts.length !== 1)
|
|
386
|
+
return void 0;
|
|
387
|
+
const o = opts[0];
|
|
388
|
+
const gid = Number(o == null ? void 0 : o.option_group_id) || 0;
|
|
389
|
+
const oid = Number(o == null ? void 0 : o.product_option_item_id) || 0;
|
|
390
|
+
const rawNum = o == null ? void 0 : o.num;
|
|
391
|
+
const n = typeof rawNum === "number" && !Number.isNaN(rawNum) ? Math.max(1, Math.floor(rawNum)) : 1;
|
|
392
|
+
return `${productId}_${gid}_${oid}_${n}`;
|
|
393
|
+
}
|
|
394
|
+
function collectLineIdentityKeyCandidates(x) {
|
|
395
|
+
var _a;
|
|
396
|
+
const out = /* @__PURE__ */ new Set();
|
|
397
|
+
const row = x;
|
|
398
|
+
if (typeof row.identity_key === "string" && row.identity_key.length > 0) {
|
|
399
|
+
out.add(row.identity_key);
|
|
400
|
+
}
|
|
401
|
+
const uid = (_a = row.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
402
|
+
if (typeof uid === "string" && uid.length > 0)
|
|
403
|
+
out.add(uid);
|
|
404
|
+
const synthetic = buildSyntheticSingleOptionIdentityKey(
|
|
405
|
+
row.product_id,
|
|
406
|
+
row.product_option_item
|
|
407
|
+
);
|
|
408
|
+
if (synthetic)
|
|
409
|
+
out.add(synthetic);
|
|
410
|
+
const opts = "product_option_item" in row && Array.isArray(row.product_option_item) ? row.product_option_item : [];
|
|
411
|
+
const bundles = "product_bundle" in row && Array.isArray(row.product_bundle) ? row.product_bundle : [];
|
|
412
|
+
if (opts.length === 0 && bundles.length === 0 && row.product_id != null && Number.isFinite(Number(row.product_id))) {
|
|
413
|
+
const vid = Number(row.product_variant_id) || 0;
|
|
414
|
+
out.add(`${row.product_id}_${vid}_0`);
|
|
415
|
+
}
|
|
416
|
+
return out;
|
|
417
|
+
}
|
|
418
|
+
function fingerprintForIdentityWithOptionKeys(x) {
|
|
419
|
+
const row = x;
|
|
420
|
+
const opts = "product_option_item" in row ? Array.isArray(row.product_option_item) ? row.product_option_item : [] : [];
|
|
421
|
+
const buds = "product_bundle" in row ? Array.isArray(row.product_bundle) ? row.product_bundle : [] : [];
|
|
422
|
+
return buildProductLineFingerprint(opts, buds);
|
|
423
|
+
}
|
|
341
424
|
function isIdentityMatch(a, b) {
|
|
342
425
|
if (a.product_id !== b.product_id || a.product_variant_id !== b.product_variant_id)
|
|
343
426
|
return false;
|
|
344
|
-
if (
|
|
427
|
+
if (a.identity_key || b.identity_key) {
|
|
428
|
+
if (a.identity_key && b.identity_key)
|
|
429
|
+
return a.identity_key === b.identity_key;
|
|
430
|
+
if (a.identity_key && !b.identity_key) {
|
|
431
|
+
return collectLineIdentityKeyCandidates(b).has(a.identity_key);
|
|
432
|
+
}
|
|
433
|
+
if (!a.identity_key && b.identity_key) {
|
|
434
|
+
return collectLineIdentityKeyCandidates(a).has(b.identity_key);
|
|
435
|
+
}
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
if (isSkuOnlyDeleteIdentity(a) || isSkuOnlyDeleteIdentity(b))
|
|
345
439
|
return true;
|
|
346
|
-
return a
|
|
440
|
+
return fingerprintForIdentityWithOptionKeys(a) === fingerprintForIdentityWithOptionKeys(b);
|
|
347
441
|
}
|
|
348
442
|
function getProductIdentityIndex(products, identity) {
|
|
349
443
|
return products.findIndex((item) => isIdentityMatch(item, identity));
|
|
@@ -474,13 +568,39 @@ function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
474
568
|
}
|
|
475
569
|
return void 0;
|
|
476
570
|
}
|
|
571
|
+
function pickFirstCustomCapacityDimensionId(products) {
|
|
572
|
+
for (const p of products) {
|
|
573
|
+
const cap = p == null ? void 0 : p.capacity;
|
|
574
|
+
if (!cap || cap.type !== "custom")
|
|
575
|
+
continue;
|
|
576
|
+
if (!Array.isArray(cap.custom) || cap.custom.length === 0)
|
|
577
|
+
continue;
|
|
578
|
+
const row = cap.custom[0];
|
|
579
|
+
if (!row || typeof row !== "object")
|
|
580
|
+
continue;
|
|
581
|
+
const id = row.id;
|
|
582
|
+
if (id === null || id === void 0 || id === "")
|
|
583
|
+
continue;
|
|
584
|
+
if (typeof id === "number" && Number.isFinite(id))
|
|
585
|
+
return id;
|
|
586
|
+
if (typeof id === "string") {
|
|
587
|
+
const trimmed = id.trim();
|
|
588
|
+
if (!trimmed)
|
|
589
|
+
continue;
|
|
590
|
+
return trimmed;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return void 0;
|
|
594
|
+
}
|
|
477
595
|
// Annotate the CommonJS export names for ESM import in node:
|
|
478
596
|
0 && (module.exports = {
|
|
479
597
|
aggregateItemRuleLimit,
|
|
480
598
|
attachItemRuleLimitsToTopLevelProducts,
|
|
481
599
|
buildItemRuleBusinessData,
|
|
482
600
|
buildProductKey,
|
|
601
|
+
buildProductLineFingerprint,
|
|
483
602
|
buildQuantityLimitIndex,
|
|
603
|
+
buildSyntheticSingleOptionIdentityKey,
|
|
484
604
|
collectLinkProductIdsFromReservationRules,
|
|
485
605
|
computeResourceIsFull,
|
|
486
606
|
createEmptySummary,
|
|
@@ -491,9 +611,11 @@ function pickFirstCustomCapacityPaxBounds(products) {
|
|
|
491
611
|
getTopLevelVariantId,
|
|
492
612
|
hasCustomCapacityProduct,
|
|
493
613
|
isIdentityMatch,
|
|
614
|
+
isSkuOnlyDeleteIdentity,
|
|
494
615
|
normalizeEnabledItemRuleIds,
|
|
495
616
|
normalizeItemRuleStrategies,
|
|
496
617
|
normalizeOrderProduct,
|
|
618
|
+
pickFirstCustomCapacityDimensionId,
|
|
497
619
|
pickFirstCustomCapacityPaxBounds,
|
|
498
620
|
pickFirstDurationMinutesFromProducts,
|
|
499
621
|
resolveSkuMatchedQuantityLimits,
|