@pisell/pisellos 2.1.130 → 2.1.131
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/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/Order/index.d.ts +3 -6
- package/dist/modules/Order/index.js +119 -41
- package/dist/modules/Order/types.d.ts +23 -5
- package/dist/modules/Order/types.js +2 -0
- package/dist/modules/Order/utils.d.ts +66 -11
- package/dist/modules/Order/utils.js +281 -45
- package/dist/modules/SalesSummary/utils.js +33 -68
- package/dist/modules/ScanOrderLogger/providers/feishu.js +168 -60
- package/dist/modules/ScanOrderLogger/types.d.ts +6 -0
- package/dist/modules/Summary/utils.js +6 -21
- package/dist/solution/ScanOrder/index.d.ts +31 -6
- package/dist/solution/ScanOrder/index.js +1062 -498
- package/dist/solution/ScanOrder/types.d.ts +52 -2
- package/dist/solution/ScanOrder/types.js +16 -1
- package/dist/solution/ScanOrder/utils.d.ts +41 -5
- package/dist/solution/ScanOrder/utils.js +214 -33
- package/dist/solution/VenueBooking/index.d.ts +2 -5
- package/dist/solution/VenueBooking/index.js +35 -27
- package/lib/modules/Order/index.d.ts +3 -6
- package/lib/modules/Order/index.js +109 -30
- package/lib/modules/Order/types.d.ts +23 -5
- package/lib/modules/Order/utils.d.ts +66 -11
- package/lib/modules/Order/utils.js +181 -16
- package/lib/modules/SalesSummary/utils.js +13 -47
- package/lib/modules/ScanOrderLogger/providers/feishu.js +100 -34
- package/lib/modules/ScanOrderLogger/types.d.ts +6 -0
- package/lib/modules/Summary/utils.js +4 -18
- package/lib/solution/ScanOrder/index.d.ts +31 -6
- package/lib/solution/ScanOrder/index.js +315 -14
- package/lib/solution/ScanOrder/types.d.ts +52 -2
- package/lib/solution/ScanOrder/utils.d.ts +41 -5
- package/lib/solution/ScanOrder/utils.js +150 -20
- package/lib/solution/VenueBooking/index.d.ts +2 -5
- package/lib/solution/VenueBooking/index.js +13 -6
- package/package.json +1 -1
|
@@ -45,7 +45,7 @@ import { extractResourceIds, buildResourceProductMap } from "./utils/resource";
|
|
|
45
45
|
import { buildTimeSlotGrid, isBusinessHoursCrossDay, generateTimeLabels } from "./utils/timeSlot";
|
|
46
46
|
import { buildDateRangeSummary } from "./utils/dateSummary";
|
|
47
47
|
import { mergeConsecutiveSlots, expandMergedSlotToIndividual, buildVenueIdentityKey, buildVenueBookingEntry, buildPriceBreakdown } from "./utils/slotMerge";
|
|
48
|
-
import { createUuidV4 } from "../../modules/Order/utils";
|
|
48
|
+
import { composeLinePrice, createUuidV4, sumOptionUnitPrice } from "../../modules/Order/utils";
|
|
49
49
|
import { OrderModule } from "../../modules/Order";
|
|
50
50
|
import { RegisterAndLoginHooks } from "../RegisterAndLogin/types";
|
|
51
51
|
import Decimal from 'decimal.js';
|
|
@@ -2027,7 +2027,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2027
2027
|
key: "setDiscountSelected",
|
|
2028
2028
|
value: (function () {
|
|
2029
2029
|
var _setDiscountSelected = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee21(params) {
|
|
2030
|
-
var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator13, _step13, d, selectedResourceIds, _iterator14, _step14, _product$_origin, product, totalPerUnitDiscount,
|
|
2030
|
+
var _tempOrder$holder, _this$store$order$get, _this$store$order$get2, list, beforeTarget, updated, updatedTarget, tempOrder, orderStore, discountModule, rulesModule, holders, nextDiscountList, _tempOrder$holder2, result, beforeSelectedIds, _iterator13, _step13, d, selectedResourceIds, _iterator14, _step14, _product$_origin, _product$metadata$sou, _product$metadata3, _product$metadata4, _product$original_pri, product, totalPerUnitDiscount, optionSum, sourcePrice, newSourceSellingPrice, newMainSellingPrice, afterApplyTarget, finalSummary, finalProduct, finalTarget;
|
|
2031
2031
|
return _regeneratorRuntime().wrap(function _callee21$(_context21) {
|
|
2032
2032
|
while (1) switch (_context21.prev = _context21.next) {
|
|
2033
2033
|
case 0:
|
|
@@ -2116,7 +2116,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2116
2116
|
_iterator14.s();
|
|
2117
2117
|
case 21:
|
|
2118
2118
|
if ((_step14 = _iterator14.n()).done) {
|
|
2119
|
-
_context21.next =
|
|
2119
|
+
_context21.next = 35;
|
|
2120
2120
|
break;
|
|
2121
2121
|
}
|
|
2122
2122
|
product = _step14.value;
|
|
@@ -2124,7 +2124,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2124
2124
|
_context21.next = 25;
|
|
2125
2125
|
break;
|
|
2126
2126
|
}
|
|
2127
|
-
return _context21.abrupt("continue",
|
|
2127
|
+
return _context21.abrupt("continue", 33);
|
|
2128
2128
|
case 25:
|
|
2129
2129
|
// 1. 把 product.discount_list 和当前选中的 discount 对齐(剔除已取消的券)
|
|
2130
2130
|
product.discount_list = (product.discount_list || []).filter(function (pd) {
|
|
@@ -2133,45 +2133,53 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2133
2133
|
return rid != null && selectedResourceIds.has(rid);
|
|
2134
2134
|
});
|
|
2135
2135
|
|
|
2136
|
-
// 2. 以
|
|
2136
|
+
// 2. 以 source_product_price 为券作用基准:券作用于 source(不含 option),
|
|
2137
|
+
// 再把 option 加回得到含 option 的 main_product_selling_price,最后合成 composite。
|
|
2137
2138
|
totalPerUnitDiscount = (product.discount_list || []).reduce(function (sum, pd) {
|
|
2138
2139
|
return sum + (pd.amount || 0);
|
|
2139
2140
|
}, 0);
|
|
2140
|
-
|
|
2141
|
-
product.
|
|
2141
|
+
optionSum = sumOptionUnitPrice(product.product_option_item);
|
|
2142
|
+
sourcePrice = (_product$metadata$sou = (_product$metadata3 = product.metadata) === null || _product$metadata3 === void 0 ? void 0 : _product$metadata3.source_product_price) !== null && _product$metadata$sou !== void 0 ? _product$metadata$sou : ((_product$metadata4 = product.metadata) === null || _product$metadata4 === void 0 ? void 0 : _product$metadata4.main_product_original_price) != null ? new Decimal(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : (_product$original_pri = product.original_price) !== null && _product$original_pri !== void 0 ? _product$original_pri : '0';
|
|
2143
|
+
newSourceSellingPrice = new Decimal(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
|
|
2144
|
+
newMainSellingPrice = new Decimal(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
2142
2145
|
if (product.metadata) {
|
|
2143
|
-
product.metadata.main_product_selling_price =
|
|
2146
|
+
product.metadata.main_product_selling_price = newMainSellingPrice;
|
|
2147
|
+
product.metadata.price_schema_version = 2;
|
|
2144
2148
|
}
|
|
2145
|
-
|
|
2149
|
+
product.selling_price = composeLinePrice({
|
|
2150
|
+
mainPrice: newMainSellingPrice,
|
|
2151
|
+
bundle: product.product_bundle
|
|
2152
|
+
});
|
|
2153
|
+
case 33:
|
|
2146
2154
|
_context21.next = 21;
|
|
2147
2155
|
break;
|
|
2148
|
-
case
|
|
2149
|
-
_context21.next =
|
|
2156
|
+
case 35:
|
|
2157
|
+
_context21.next = 40;
|
|
2150
2158
|
break;
|
|
2151
|
-
case 34:
|
|
2152
|
-
_context21.prev = 34;
|
|
2153
|
-
_context21.t0 = _context21["catch"](19);
|
|
2154
|
-
_iterator14.e(_context21.t0);
|
|
2155
2159
|
case 37:
|
|
2156
2160
|
_context21.prev = 37;
|
|
2157
|
-
|
|
2158
|
-
|
|
2161
|
+
_context21.t0 = _context21["catch"](19);
|
|
2162
|
+
_iterator14.e(_context21.t0);
|
|
2159
2163
|
case 40:
|
|
2164
|
+
_context21.prev = 40;
|
|
2165
|
+
_iterator14.f();
|
|
2166
|
+
return _context21.finish(40);
|
|
2167
|
+
case 43:
|
|
2160
2168
|
OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
|
|
2161
|
-
_context21.next =
|
|
2169
|
+
_context21.next = 46;
|
|
2162
2170
|
return discountModule === null || discountModule === void 0 ? void 0 : discountModule.setDiscountList(nextDiscountList);
|
|
2163
|
-
case
|
|
2171
|
+
case 46:
|
|
2164
2172
|
tempOrder.discount_list = (nextDiscountList || []).filter(function (d) {
|
|
2165
2173
|
return d.isSelected;
|
|
2166
2174
|
});
|
|
2167
2175
|
afterApplyTarget = this.store.order.getDiscountList().find(function (d) {
|
|
2168
2176
|
return d.id === params.discountId;
|
|
2169
2177
|
}) || null;
|
|
2170
|
-
_context21.next =
|
|
2178
|
+
_context21.next = 50;
|
|
2171
2179
|
return this.store.order.recalculateSummary({
|
|
2172
2180
|
createIfMissing: true
|
|
2173
2181
|
});
|
|
2174
|
-
case
|
|
2182
|
+
case 50:
|
|
2175
2183
|
this.store.order.persistTempOrder();
|
|
2176
2184
|
finalSummary = ((_this$store$order$get = this.store.order.getTempOrder()) === null || _this$store$order$get === void 0 ? void 0 : _this$store$order$get.summary) || null;
|
|
2177
2185
|
finalProduct = ((_this$store$order$get2 = this.store.order.getTempOrder()) === null || _this$store$order$get2 === void 0 || (_this$store$order$get2 = _this$store$order$get2.products) === null || _this$store$order$get2 === void 0 ? void 0 : _this$store$order$get2[0]) || null;
|
|
@@ -2180,16 +2188,16 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2180
2188
|
return d.id === params.discountId;
|
|
2181
2189
|
}) || null;
|
|
2182
2190
|
return _context21.abrupt("return", this.store.order.getDiscountList());
|
|
2183
|
-
case
|
|
2184
|
-
_context21.prev =
|
|
2191
|
+
case 58:
|
|
2192
|
+
_context21.prev = 58;
|
|
2185
2193
|
_context21.t1 = _context21["catch"](1);
|
|
2186
2194
|
this.logMethodError('setDiscountSelected', _context21.t1);
|
|
2187
2195
|
throw _context21.t1;
|
|
2188
|
-
case
|
|
2196
|
+
case 62:
|
|
2189
2197
|
case "end":
|
|
2190
2198
|
return _context21.stop();
|
|
2191
2199
|
}
|
|
2192
|
-
}, _callee21, this, [[1,
|
|
2200
|
+
}, _callee21, this, [[1, 58], [19, 37, 40, 43]]);
|
|
2193
2201
|
}));
|
|
2194
2202
|
function setDiscountSelected(_x15) {
|
|
2195
2203
|
return _setDiscountSelected.apply(this, arguments);
|
|
@@ -2336,7 +2344,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2336
2344
|
key: "addProductToOrder",
|
|
2337
2345
|
value: function () {
|
|
2338
2346
|
var _addProductToOrder = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee25(product) {
|
|
2339
|
-
var _product$
|
|
2347
|
+
var _product$metadata5, _product$product_vari2, quotationPrice, products;
|
|
2340
2348
|
return _regeneratorRuntime().wrap(function _callee25$(_context25) {
|
|
2341
2349
|
while (1) switch (_context25.prev = _context25.next) {
|
|
2342
2350
|
case 0:
|
|
@@ -2351,7 +2359,7 @@ export var VenueBookingImpl = /*#__PURE__*/function (_BaseModule) {
|
|
|
2351
2359
|
}
|
|
2352
2360
|
throw new Error('order 模块未初始化');
|
|
2353
2361
|
case 4:
|
|
2354
|
-
if (!((_product$
|
|
2362
|
+
if (!((_product$metadata5 = product.metadata) !== null && _product$metadata5 !== void 0 && _product$metadata5.venue_booking) && this.store.quotation && product.product_id != null) {
|
|
2355
2363
|
quotationPrice = this.store.quotation.getPriceForProduct({
|
|
2356
2364
|
productId: product.product_id,
|
|
2357
2365
|
variantId: (_product$product_vari2 = product.product_variant_id) !== null && _product$product_vari2 !== void 0 ? _product$product_vari2 : undefined,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Module, PisellCore, ModuleOptions } from '../../types';
|
|
2
2
|
import { BaseModule } from '../BaseModule';
|
|
3
|
-
import { OrderModuleAPI, CommitOrderParams, SubmitScanOrderParams, ScanOrderMoreParams, CheckoutOrderParams } from './types';
|
|
3
|
+
import { OrderModuleAPI, CommitOrderParams, SubmitScanOrderParams, ScanOrderMoreParams, CheckoutOrderParams, UpdateProductInOrderParams } from './types';
|
|
4
4
|
import { CartItem } from '../Cart/types';
|
|
5
5
|
import { type SubmitPayloadEnhancer } from './utils';
|
|
6
6
|
import type { ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderSummary, ScanOrderTempOrder } from '../../solution/ScanOrder/types';
|
|
@@ -71,11 +71,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
71
71
|
updateTempOrderBuzzer(buzzer: string): string;
|
|
72
72
|
updateTempOrderContactsInfo(contactsInfo: any[]): any[];
|
|
73
73
|
addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
74
|
-
updateProductInOrder(params:
|
|
75
|
-
product_id: number | null;
|
|
76
|
-
product_variant_id: number;
|
|
77
|
-
updates: Partial<ScanOrderOrderProduct>;
|
|
78
|
-
}): Promise<ScanOrderOrderProduct[]>;
|
|
74
|
+
updateProductInOrder(params: UpdateProductInOrderParams): Promise<ScanOrderOrderProduct[]>;
|
|
79
75
|
removeProductFromOrder(identity: ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
|
|
80
76
|
submitTempOrder<T = any>(params?: {
|
|
81
77
|
cacheId?: string;
|
|
@@ -119,3 +115,4 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
119
115
|
getOrderInfoByRemote(order_id: number): Promise<any>;
|
|
120
116
|
getLastOrderInfo(): Record<string, any> | undefined;
|
|
121
117
|
}
|
|
118
|
+
export type { UpdateProductInOrderParams } from './types';
|
|
@@ -285,6 +285,31 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
285
285
|
this.window.localStorage.removeItem(key);
|
|
286
286
|
return;
|
|
287
287
|
}
|
|
288
|
+
if (Array.isArray(parsedData.products)) {
|
|
289
|
+
for (let i = 0; i < parsedData.products.length; i++) {
|
|
290
|
+
const p = parsedData.products[i];
|
|
291
|
+
if (!p || typeof p !== "object")
|
|
292
|
+
continue;
|
|
293
|
+
if (!Array.isArray(p.product_option_item)) {
|
|
294
|
+
p.product_option_item = [];
|
|
295
|
+
}
|
|
296
|
+
if (!Array.isArray(p.product_bundle)) {
|
|
297
|
+
p.product_bundle = [];
|
|
298
|
+
}
|
|
299
|
+
const row = p;
|
|
300
|
+
if (typeof row.identity_key !== "string" || row.identity_key.length === 0) {
|
|
301
|
+
const newKey = (0, import_utils.createUuidV4)();
|
|
302
|
+
row.identity_key = newKey;
|
|
303
|
+
if (!row.metadata || typeof row.metadata !== "object") {
|
|
304
|
+
row.metadata = {};
|
|
305
|
+
}
|
|
306
|
+
if (!row.metadata.unique_identification_number) {
|
|
307
|
+
row.metadata.unique_identification_number = newKey;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
parsedData.products[i] = (0, import_utils3.normalizeOrderProduct)(row);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
288
313
|
this.store.tempOrder = parsedData;
|
|
289
314
|
} catch {
|
|
290
315
|
(_b = (_a = this.window) == null ? void 0 : _a.localStorage) == null ? void 0 : _b.removeItem(key);
|
|
@@ -394,21 +419,57 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
394
419
|
// ─── TempOrder: 商品 CRUD ───
|
|
395
420
|
async addProductToOrder(product) {
|
|
396
421
|
const tempOrder = this.ensureTempOrder();
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
422
|
+
const hasExplicitIdentityKey = typeof product.identity_key === "string" && product.identity_key.length > 0;
|
|
423
|
+
if (hasExplicitIdentityKey) {
|
|
424
|
+
const normalizedProduct = (0, import_utils3.normalizeOrderProduct)(product);
|
|
425
|
+
const productIndex = (0, import_utils3.getProductIdentityIndex)(
|
|
426
|
+
tempOrder.products,
|
|
427
|
+
normalizedProduct
|
|
428
|
+
);
|
|
429
|
+
if (productIndex === -1) {
|
|
430
|
+
tempOrder.products.push(normalizedProduct);
|
|
431
|
+
} else {
|
|
432
|
+
const targetProduct = tempOrder.products[productIndex];
|
|
433
|
+
tempOrder.products[productIndex] = {
|
|
434
|
+
...targetProduct,
|
|
435
|
+
...normalizedProduct,
|
|
436
|
+
num: (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num),
|
|
437
|
+
_origin: normalizedProduct._origin || targetProduct._origin
|
|
438
|
+
};
|
|
439
|
+
}
|
|
404
440
|
} else {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
441
|
+
const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
|
|
442
|
+
product.product_option_item,
|
|
443
|
+
product.product_bundle
|
|
444
|
+
);
|
|
445
|
+
const matchedIndex = tempOrder.products.findIndex((item) => {
|
|
446
|
+
if (item.product_id !== product.product_id)
|
|
447
|
+
return false;
|
|
448
|
+
if (item.product_variant_id !== product.product_variant_id)
|
|
449
|
+
return false;
|
|
450
|
+
const existedFingerprint = (0, import_utils3.buildProductLineFingerprint)(
|
|
451
|
+
item.product_option_item,
|
|
452
|
+
item.product_bundle
|
|
453
|
+
);
|
|
454
|
+
return existedFingerprint === incomingFingerprint;
|
|
455
|
+
});
|
|
456
|
+
if (matchedIndex === -1) {
|
|
457
|
+
const normalizedProduct = (0, import_utils3.normalizeOrderProduct)(product);
|
|
458
|
+
tempOrder.products.push(normalizedProduct);
|
|
459
|
+
} else {
|
|
460
|
+
const targetProduct = tempOrder.products[matchedIndex];
|
|
461
|
+
const normalizedProduct = (0, import_utils3.normalizeOrderProduct)({
|
|
462
|
+
...product,
|
|
463
|
+
identity_key: targetProduct.identity_key
|
|
464
|
+
});
|
|
465
|
+
tempOrder.products[matchedIndex] = {
|
|
466
|
+
...targetProduct,
|
|
467
|
+
...normalizedProduct,
|
|
468
|
+
identity_key: targetProduct.identity_key,
|
|
469
|
+
num: (0, import_utils3.getSafeProductNum)(targetProduct.num + normalizedProduct.num),
|
|
470
|
+
_origin: normalizedProduct._origin || targetProduct._origin
|
|
471
|
+
};
|
|
472
|
+
}
|
|
412
473
|
}
|
|
413
474
|
this.applyDiscount();
|
|
414
475
|
await this.recalculateSummary({ createIfMissing: true });
|
|
@@ -416,12 +477,27 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
416
477
|
return tempOrder.products;
|
|
417
478
|
}
|
|
418
479
|
async updateProductInOrder(params) {
|
|
419
|
-
|
|
480
|
+
var _a, _b, _c;
|
|
481
|
+
const {
|
|
482
|
+
product_id,
|
|
483
|
+
product_variant_id,
|
|
484
|
+
updates,
|
|
485
|
+
identity_key,
|
|
486
|
+
product_option_item,
|
|
487
|
+
product_bundle
|
|
488
|
+
} = params;
|
|
420
489
|
const tempOrder = this.ensureTempOrder();
|
|
421
|
-
const
|
|
490
|
+
const identityLookup = {
|
|
422
491
|
product_id,
|
|
423
492
|
product_variant_id
|
|
424
|
-
}
|
|
493
|
+
};
|
|
494
|
+
if (identity_key !== void 0)
|
|
495
|
+
identityLookup.identity_key = identity_key;
|
|
496
|
+
if (product_option_item !== void 0)
|
|
497
|
+
identityLookup.product_option_item = product_option_item;
|
|
498
|
+
if (product_bundle !== void 0)
|
|
499
|
+
identityLookup.product_bundle = product_bundle;
|
|
500
|
+
const productIndex = (0, import_utils3.getProductIdentityIndex)(tempOrder.products, identityLookup);
|
|
425
501
|
if (productIndex === -1) {
|
|
426
502
|
throw new Error("[Order] 目标商品不存在,无法更新");
|
|
427
503
|
}
|
|
@@ -433,7 +509,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
433
509
|
product_variant_id
|
|
434
510
|
};
|
|
435
511
|
nextProduct.num = (0, import_utils3.getSafeProductNum)(nextProduct.num);
|
|
436
|
-
|
|
512
|
+
const callerUpdatesTopPrice = Object.prototype.hasOwnProperty.call(updates || {}, "selling_price") || Object.prototype.hasOwnProperty.call(updates || {}, "original_price");
|
|
513
|
+
const callerUpdatesMainMeta = ((_a = updates == null ? void 0 : updates.metadata) == null ? void 0 : _a.main_product_selling_price) !== void 0 || ((_b = updates == null ? void 0 : updates.metadata) == null ? void 0 : _b.main_product_original_price) !== void 0 || ((_c = updates == null ? void 0 : updates.metadata) == null ? void 0 : _c.source_product_price) !== void 0;
|
|
514
|
+
if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
|
|
515
|
+
const existedMeta = nextProduct.metadata || {};
|
|
516
|
+
nextProduct.metadata = { ...existedMeta };
|
|
517
|
+
delete nextProduct.metadata.source_product_price;
|
|
518
|
+
delete nextProduct.metadata.main_product_selling_price;
|
|
519
|
+
delete nextProduct.metadata.main_product_original_price;
|
|
520
|
+
delete nextProduct.metadata.price_schema_version;
|
|
521
|
+
}
|
|
522
|
+
tempOrder.products[productIndex] = (0, import_utils3.normalizeOrderProduct)(nextProduct);
|
|
437
523
|
this.applyDiscount();
|
|
438
524
|
await this.recalculateSummary({ createIfMissing: true });
|
|
439
525
|
this.persistTempOrder();
|
|
@@ -441,18 +527,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
441
527
|
}
|
|
442
528
|
async removeProductFromOrder(identity) {
|
|
443
529
|
const tempOrder = this.ensureTempOrder();
|
|
444
|
-
const beforeProducts = tempOrder.products;
|
|
445
530
|
tempOrder.products = tempOrder.products.filter(
|
|
446
531
|
(item) => !(0, import_utils3.isIdentityMatch)(item, identity)
|
|
447
532
|
);
|
|
448
|
-
const removedByStrictIdentity = beforeProducts.length - tempOrder.products.length;
|
|
449
|
-
if (removedByStrictIdentity === 0 && identity.identity_key) {
|
|
450
|
-
tempOrder.products = tempOrder.products.filter((item) => {
|
|
451
|
-
const isSameProduct = String(item.product_id) === String(identity.product_id) && String(item.product_variant_id) === String(identity.product_variant_id);
|
|
452
|
-
const hasNoIdentityKey = !item.identity_key;
|
|
453
|
-
return !(isSameProduct && hasNoIdentityKey);
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
533
|
this.applyDiscount();
|
|
457
534
|
await this.recalculateSummary({ createIfMissing: true });
|
|
458
535
|
this.persistTempOrder();
|
|
@@ -474,7 +551,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
474
551
|
});
|
|
475
552
|
let result;
|
|
476
553
|
if (tempOrder.order_id) {
|
|
477
|
-
const products = (0, import_utils.
|
|
554
|
+
const products = (0, import_utils.filterProductsForScanOrderMore)(payload.products);
|
|
478
555
|
const moreResult = await this.scanOrderMore({
|
|
479
556
|
query: {
|
|
480
557
|
order_id: tempOrder.order_id,
|
|
@@ -700,7 +777,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
700
777
|
async submitScanOrder(params) {
|
|
701
778
|
const { url, query } = params;
|
|
702
779
|
const fetchUrl = url || "/order/sales/checkout";
|
|
703
|
-
return this.request.post(fetchUrl, query)
|
|
780
|
+
return this.request.post(fetchUrl, query, { customToast: () => {
|
|
781
|
+
} });
|
|
704
782
|
}
|
|
705
783
|
async scanOrderMore(params) {
|
|
706
784
|
const { url, query } = params;
|
|
@@ -709,7 +787,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
709
787
|
products: query.products,
|
|
710
788
|
request_unique_idempotency_token: query.request_unique_idempotency_token
|
|
711
789
|
};
|
|
712
|
-
return this.request.put(fetchUrl, requestBody)
|
|
790
|
+
return this.request.put(fetchUrl, requestBody, { customToast: () => {
|
|
791
|
+
} });
|
|
713
792
|
}
|
|
714
793
|
// TODO 获取详情的接口
|
|
715
794
|
async getOrderInfoByRemote(order_id) {
|
|
@@ -16,6 +16,15 @@ export interface OrderState {
|
|
|
16
16
|
discount: DiscountModule | null;
|
|
17
17
|
rules: RulesModule | null;
|
|
18
18
|
}
|
|
19
|
+
/** 更新购物车行:仅传 SKU 时命中同 SKU 第一行;多行同 SKU 须传 identity_key / 选项指纹等 */
|
|
20
|
+
export interface UpdateProductInOrderParams {
|
|
21
|
+
product_id: number | null;
|
|
22
|
+
product_variant_id: number;
|
|
23
|
+
updates: Partial<ScanOrderOrderProduct>;
|
|
24
|
+
identity_key?: string;
|
|
25
|
+
product_option_item?: any[];
|
|
26
|
+
product_bundle?: any[];
|
|
27
|
+
}
|
|
19
28
|
/**
|
|
20
29
|
* 订单信息
|
|
21
30
|
*/
|
|
@@ -35,14 +44,27 @@ export interface SubmitScanOrderProduct {
|
|
|
35
44
|
num: number;
|
|
36
45
|
product_variant_id: number;
|
|
37
46
|
product_option_item: any[];
|
|
47
|
+
/**
|
|
48
|
+
* 行 composite 券后单价。
|
|
49
|
+
* 公式:`metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
|
|
50
|
+
* 主商品(含 option、含主商品折扣)的单价存在 `metadata.main_product_selling_price`。
|
|
51
|
+
*/
|
|
38
52
|
selling_price: string;
|
|
53
|
+
/**
|
|
54
|
+
* 行 composite 券前单价。
|
|
55
|
+
* 公式:`metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
56
|
+
* 主商品(含 option、不含折扣)的单价存在 `metadata.main_product_original_price`。
|
|
57
|
+
*/
|
|
39
58
|
original_price: string;
|
|
59
|
+
/** 出站兼容字段,直接由 `selling_price` 派生,语义同 composite。 */
|
|
40
60
|
payment_price: string;
|
|
41
61
|
tax_fee: string;
|
|
42
62
|
is_charge_tax: number;
|
|
43
63
|
discount_list: any[];
|
|
44
64
|
product_bundle: any[];
|
|
45
65
|
metadata: Record<string, any>;
|
|
66
|
+
/** 商品行备注 */
|
|
67
|
+
note?: string;
|
|
46
68
|
}
|
|
47
69
|
export interface SubmitScanOrderSummary {
|
|
48
70
|
product_quantity: number;
|
|
@@ -210,11 +232,7 @@ export interface OrderModuleAPI {
|
|
|
210
232
|
updateTempOrderBuzzer: (buzzer: string) => string;
|
|
211
233
|
updateTempOrderContactsInfo: (contactsInfo: any[]) => any[];
|
|
212
234
|
addProductToOrder: (product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity) => Promise<ScanOrderOrderProduct[]>;
|
|
213
|
-
updateProductInOrder: (params:
|
|
214
|
-
product_id: number | null;
|
|
215
|
-
product_variant_id: number;
|
|
216
|
-
updates: Partial<ScanOrderOrderProduct>;
|
|
217
|
-
}) => Promise<ScanOrderOrderProduct[]>;
|
|
235
|
+
updateProductInOrder: (params: UpdateProductInOrderParams) => Promise<ScanOrderOrderProduct[]>;
|
|
218
236
|
removeProductFromOrder: (identity: ScanOrderOrderProductIdentity) => Promise<ScanOrderOrderProduct[]>;
|
|
219
237
|
persistTempOrder: () => void;
|
|
220
238
|
submitTempOrder: <T = any>(params?: {
|
|
@@ -1,21 +1,66 @@
|
|
|
1
|
+
import Decimal from 'decimal.js';
|
|
1
2
|
import { CartItem } from "../Cart";
|
|
2
3
|
import type { ScanOrderSubmitPayload, ScanOrderSubmitProduct, ScanOrderSummary, ScanOrderTempOrder } from '../../solution/ScanOrder/types';
|
|
3
4
|
import type { RulesParamsHooks } from '../Rules/types';
|
|
5
|
+
/**
|
|
6
|
+
* 把"含 option 的主商品单价"与 bundle 合成"单行 composite 单价"。
|
|
7
|
+
*
|
|
8
|
+
* 新语义 v2 约定:
|
|
9
|
+
* - `mainPrice` 必须是**已经包含 option 的主商品单价**(即 `metadata.main_product_selling_price`
|
|
10
|
+
* 或 `metadata.main_product_original_price`),option 价格不由本函数叠加。
|
|
11
|
+
* - 套餐价:Σ((bundle.bundle_selling_price ?? bundle.price) × (bundle.num ?? bundle.quantity ?? 1))
|
|
12
|
+
* 当 `useOriginalBundle=true` 时,改用 `bundle.original_price ?? bundle.product_price ?? bundle.price`。
|
|
13
|
+
* - 返回值:保留 2 位小数的字符串,方便直接写回 `selling_price` / `original_price` 字段。
|
|
14
|
+
*
|
|
15
|
+
* 被 `normalizeOrderProduct`、Rules setProduct 钩子、各 Solution 的 setDiscountSelected 共用,
|
|
16
|
+
* 保证合成逻辑单点来源。
|
|
17
|
+
*/
|
|
18
|
+
export declare function composeLinePrice(params: {
|
|
19
|
+
mainPrice: string | number | null | undefined;
|
|
20
|
+
bundle?: Array<{
|
|
21
|
+
bundle_selling_price?: any;
|
|
22
|
+
price?: any;
|
|
23
|
+
num?: any;
|
|
24
|
+
quantity?: any;
|
|
25
|
+
original_price?: any;
|
|
26
|
+
product_price?: any;
|
|
27
|
+
}> | null;
|
|
28
|
+
useOriginalBundle?: boolean;
|
|
29
|
+
}): string;
|
|
30
|
+
/**
|
|
31
|
+
* 计算 option 单价合计:Σ(option.price × option.num)。
|
|
32
|
+
* 在新语义 v2 下,main_product_original_price = source_product_price + 本函数结果。
|
|
33
|
+
*/
|
|
34
|
+
export declare function sumOptionUnitPrice(options?: Array<{
|
|
35
|
+
price?: any;
|
|
36
|
+
num?: any;
|
|
37
|
+
}> | null): Decimal;
|
|
4
38
|
/**
|
|
5
39
|
* OrderModule 默认 Rules 钩子工厂。
|
|
6
40
|
*
|
|
7
|
-
*
|
|
8
|
-
* - `selling_price
|
|
9
|
-
*
|
|
10
|
-
* - `
|
|
41
|
+
* 价格语义约定(订单域,v2 composite 口径):
|
|
42
|
+
* - `selling_price`:券后 **行 composite 单价**
|
|
43
|
+
* = `metadata.main_product_selling_price` + Σ(bundle_selling_price × num)。
|
|
44
|
+
* - `original_price`:券前 **行 composite 单价**
|
|
45
|
+
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
46
|
+
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
47
|
+
* 不含折扣。**权威源**。
|
|
48
|
+
* - `metadata.main_product_original_price` = source + Σ(option.price × option.num)(含 option、不含折扣)。
|
|
49
|
+
* - `metadata.main_product_selling_price` = main_original − 主商品券 per-unit amount(含 option、含折扣)。
|
|
50
|
+
* - `payment_price`:出站 payload 中由 `selling_price` 派生以兼容后端(composite)。
|
|
11
51
|
*
|
|
12
|
-
* Rules
|
|
13
|
-
* - `getProduct.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
52
|
+
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
53
|
+
* - `getProduct.price` / `getProduct.original_price` 回传 **source-level 主价**
|
|
54
|
+
* (`metadata.source_product_price`)。Rules 内部 `getProductTotalPrice` /
|
|
55
|
+
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
56
|
+
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
57
|
+
* total(source + option + bundle)对齐。
|
|
58
|
+
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
59
|
+
* 加回 Σoptions,重新合成含 option 的 main_product_* 并派生 composite。
|
|
60
|
+
* 优先级:
|
|
61
|
+
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
62
|
+
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
63
|
+
* 3. `values.total / num`(仅当 Rules 只给出总价时的兜底)
|
|
19
64
|
*
|
|
20
65
|
* 导出为纯函数方便单测直接驱动钩子,不依赖 OrderModule 实例。
|
|
21
66
|
*/
|
|
@@ -72,6 +117,15 @@ export declare function buildSubmitPayload(params: {
|
|
|
72
117
|
type?: string;
|
|
73
118
|
enhance?: SubmitPayloadEnhancer;
|
|
74
119
|
}): ScanOrderSubmitPayload;
|
|
120
|
+
/** 加单(scanOrderMore)不应提交 booking 关联的虚拟规则商品行 */
|
|
121
|
+
export declare function filterProductsForScanOrderMore(products: ScanOrderSubmitProduct[]): ScanOrderSubmitProduct[];
|
|
122
|
+
/**
|
|
123
|
+
* 历史 V1 加餐结构映射器。
|
|
124
|
+
*
|
|
125
|
+
* @deprecated 加餐(`PUT /order/order/product/:id`)已改为与正常 checkout 共用
|
|
126
|
+
* `ScanOrderSubmitProduct` 新结构(见 `OrderModule.submitTempOrder` 的加餐分支)。
|
|
127
|
+
* 本函数仅保留以兼容历史接入方,未来会移除。新代码请勿再调用。
|
|
128
|
+
*/
|
|
75
129
|
export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
|
|
76
130
|
bundle: any[];
|
|
77
131
|
key: number | null;
|
|
@@ -79,6 +133,7 @@ export declare function formatV1Product(products: ScanOrderSubmitProduct[]): {
|
|
|
79
133
|
product_id: number | null;
|
|
80
134
|
product_variant_id: number;
|
|
81
135
|
num: number;
|
|
136
|
+
note: string;
|
|
82
137
|
rowKey: number | null;
|
|
83
138
|
session: null;
|
|
84
139
|
unique: string;
|