@pisell/pisellos 2.2.264 → 2.2.265
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/dataVariant/adapter.d.ts +50 -0
- package/dist/model/strategy/adapter/dataVariant/adapter.js +167 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +780 -0
- package/dist/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
- package/dist/model/strategy/adapter/dataVariant/examples.js +277 -0
- package/dist/model/strategy/adapter/dataVariant/index.d.ts +4 -0
- package/dist/model/strategy/adapter/dataVariant/index.js +4 -0
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +148 -0
- package/dist/model/strategy/adapter/dataVariant/type.js +54 -0
- package/dist/model/strategy/adapter/index.d.ts +4 -0
- package/dist/model/strategy/adapter/index.js +5 -1
- package/dist/model/strategy/adapter/promotion/adapter.d.ts +0 -4
- package/dist/model/strategy/adapter/promotion/adapter.js +0 -23
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts +0 -17
- package/dist/model/strategy/adapter/promotion/evaluator.js +6 -279
- package/dist/model/strategy/adapter/promotion/examples.d.ts +0 -86
- package/dist/model/strategy/adapter/promotion/examples.js +0 -99
- package/dist/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/model/strategy/adapter/promotion/type.d.ts +2 -90
- package/dist/model/strategy/adapter/promotion/type.js +0 -45
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -10
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
- package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +32 -1
- package/dist/modules/Discount/index.d.ts +5 -2
- package/dist/modules/Discount/index.js +30 -7
- package/dist/modules/Discount/types.d.ts +4 -0
- package/dist/modules/Order/index.d.ts +41 -10
- package/dist/modules/Order/index.js +1370 -808
- package/dist/modules/Order/payment-utils.d.ts +26 -0
- package/dist/modules/Order/payment-utils.js +225 -0
- package/dist/modules/Order/types.d.ts +49 -1
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +410 -0
- package/dist/modules/Order/utils.d.ts +4 -3
- package/dist/modules/Order/utils.js +62 -66
- package/dist/modules/Payment/index.d.ts +2 -0
- package/dist/modules/Payment/index.js +78 -49
- package/dist/modules/Payment/types.d.ts +26 -24
- package/dist/modules/Payment/types.js +2 -0
- package/dist/modules/Product/types.d.ts +22 -0
- package/dist/modules/ProductList/index.d.ts +1 -1
- package/dist/modules/ProductList/index.js +4 -2
- package/dist/modules/ProductList/types.d.ts +2 -0
- package/dist/modules/Rules/index.d.ts +2 -9
- package/dist/modules/Rules/index.js +69 -43
- package/dist/modules/Rules/types.d.ts +10 -1
- package/dist/server/index.d.ts +71 -0
- package/dist/server/index.js +2504 -1187
- package/dist/server/modules/order/index.d.ts +56 -5
- package/dist/server/modules/order/index.js +1718 -834
- package/dist/server/modules/order/types.d.ts +15 -3
- package/dist/server/modules/order/types.js +1 -1
- package/dist/server/modules/products/index.d.ts +31 -8
- package/dist/server/modules/products/index.js +549 -390
- package/dist/server/modules/products/types.d.ts +18 -0
- package/dist/solution/BaseSales/index.d.ts +54 -4
- package/dist/solution/BaseSales/index.js +1448 -788
- package/dist/solution/BaseSales/types.d.ts +6 -1
- package/dist/solution/BaseSales/types.js +1 -1
- package/dist/solution/BaseSales/utils/cartPromotion.d.ts +1 -3
- package/dist/solution/BaseSales/utils/cartPromotion.js +50 -97
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +9 -4
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -1
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +61 -26
- package/dist/solution/BookingTicket/types.d.ts +2 -0
- package/dist/solution/Sales/index.d.ts +1 -0
- package/dist/solution/Sales/index.js +10 -2
- package/dist/solution/ScanOrder/index.js +20 -31
- package/dist/solution/ShopDiscount/index.js +15 -14
- package/dist/solution/VenueBooking/index.js +19 -30
- package/dist/utils/payment-number.d.ts +9 -0
- package/dist/utils/payment-number.js +69 -0
- package/lib/model/strategy/adapter/dataVariant/adapter.d.ts +50 -0
- package/lib/model/strategy/adapter/dataVariant/adapter.js +149 -0
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +89 -0
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +583 -0
- package/lib/model/strategy/adapter/dataVariant/examples.d.ts +39 -0
- package/lib/model/strategy/adapter/dataVariant/examples.js +293 -0
- package/lib/model/strategy/adapter/dataVariant/index.d.ts +4 -0
- package/lib/model/strategy/adapter/dataVariant/index.js +38 -0
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +148 -0
- package/lib/model/strategy/adapter/dataVariant/type.js +31 -0
- package/lib/model/strategy/adapter/index.d.ts +4 -0
- package/lib/model/strategy/adapter/index.js +13 -2
- package/lib/model/strategy/adapter/promotion/adapter.d.ts +0 -4
- package/lib/model/strategy/adapter/promotion/adapter.js +0 -20
- package/lib/model/strategy/adapter/promotion/evaluator.d.ts +0 -17
- package/lib/model/strategy/adapter/promotion/evaluator.js +0 -235
- package/lib/model/strategy/adapter/promotion/examples.d.ts +0 -86
- package/lib/model/strategy/adapter/promotion/examples.js +0 -91
- package/lib/model/strategy/adapter/promotion/index.d.ts +1 -1
- package/lib/model/strategy/adapter/promotion/index.js +0 -2
- package/lib/model/strategy/adapter/promotion/type.d.ts +2 -90
- package/lib/model/strategy/adapter/promotion/type.js +0 -2
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +5 -0
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +23 -2
- package/lib/modules/Discount/index.d.ts +5 -2
- package/lib/modules/Discount/index.js +23 -3
- package/lib/modules/Discount/types.d.ts +4 -0
- package/lib/modules/Order/index.d.ts +41 -10
- package/lib/modules/Order/index.js +505 -119
- package/lib/modules/Order/payment-utils.d.ts +26 -0
- package/lib/modules/Order/payment-utils.js +224 -0
- package/lib/modules/Order/types.d.ts +49 -1
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +418 -0
- package/lib/modules/Order/utils.d.ts +4 -3
- package/lib/modules/Order/utils.js +27 -26
- package/lib/modules/Payment/index.d.ts +2 -0
- package/lib/modules/Payment/index.js +33 -12
- package/lib/modules/Payment/types.d.ts +26 -24
- package/lib/modules/Product/types.d.ts +22 -0
- package/lib/modules/ProductList/index.d.ts +1 -1
- package/lib/modules/ProductList/index.js +4 -2
- package/lib/modules/ProductList/types.d.ts +2 -0
- package/lib/modules/Rules/index.d.ts +2 -9
- package/lib/modules/Rules/index.js +61 -29
- package/lib/modules/Rules/types.d.ts +10 -1
- package/lib/server/index.d.ts +71 -0
- package/lib/server/index.js +1002 -52
- package/lib/server/modules/order/index.d.ts +56 -5
- package/lib/server/modules/order/index.js +798 -148
- package/lib/server/modules/order/types.d.ts +15 -3
- package/lib/server/modules/products/index.d.ts +31 -8
- package/lib/server/modules/products/index.js +134 -35
- package/lib/server/modules/products/types.d.ts +18 -0
- package/lib/solution/BaseSales/index.d.ts +54 -4
- package/lib/solution/BaseSales/index.js +475 -50
- package/lib/solution/BaseSales/types.d.ts +6 -1
- package/lib/solution/BaseSales/utils/cartPromotion.d.ts +1 -3
- package/lib/solution/BaseSales/utils/cartPromotion.js +25 -64
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +9 -4
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +8 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +35 -9
- package/lib/solution/BookingTicket/types.d.ts +2 -0
- package/lib/solution/Sales/index.d.ts +1 -0
- package/lib/solution/Sales/index.js +5 -3
- package/lib/solution/ScanOrder/index.js +0 -8
- package/lib/solution/ShopDiscount/index.js +2 -1
- package/lib/solution/VenueBooking/index.js +0 -8
- package/lib/utils/payment-number.d.ts +9 -0
- package/lib/utils/payment-number.js +64 -0
- package/package.json +1 -1
package/lib/server/index.js
CHANGED
|
@@ -34,6 +34,8 @@ __export(server_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(server_exports);
|
|
36
36
|
var import_dayjs = __toESM(require("dayjs"));
|
|
37
|
+
var import_decimal = __toESM(require("decimal.js"));
|
|
38
|
+
var import_lodash_es = require("lodash-es");
|
|
37
39
|
var import_products = require("./modules/products");
|
|
38
40
|
var import_menu = require("./modules/menu");
|
|
39
41
|
var import_quotation = require("./modules/quotation");
|
|
@@ -50,6 +52,8 @@ var import_types3 = require("./modules/order/types");
|
|
|
50
52
|
var import_filterOrders = require("./modules/order/utils/filterOrders");
|
|
51
53
|
var import_filterBookings = require("./modules/order/utils/filterBookings");
|
|
52
54
|
var import_small_ticket = require("./utils/small-ticket");
|
|
55
|
+
var import_BaseSales = require("../solution/BaseSales");
|
|
56
|
+
var import_payment_utils = require("../modules/Order/payment-utils");
|
|
53
57
|
__reExport(server_exports, require("./modules"), module.exports);
|
|
54
58
|
var PRODUCT_TITLE_SNAPSHOT_KEYS = [
|
|
55
59
|
"en",
|
|
@@ -76,6 +80,8 @@ var Server = class {
|
|
|
76
80
|
};
|
|
77
81
|
// ---- 商品查询订阅者 ----
|
|
78
82
|
this.productQuerySubscribers = /* @__PURE__ */ new Map();
|
|
83
|
+
/** subscriberId → 智能定价变价时间点定时器句柄(与 subscriber 分离存储,便于 clear) */
|
|
84
|
+
this.productQueryScheduleTimers = /* @__PURE__ */ new Map();
|
|
79
85
|
// ---- 订单 / 预约列表查询订阅者 ----
|
|
80
86
|
this.orderQuerySubscribers = /* @__PURE__ */ new Map();
|
|
81
87
|
this.bookingQuerySubscribers = /* @__PURE__ */ new Map();
|
|
@@ -85,6 +91,7 @@ var Server = class {
|
|
|
85
91
|
this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
|
|
86
92
|
this.salesSearchSubscribers = /* @__PURE__ */ new Map();
|
|
87
93
|
this.deviceTaskActionsRegistered = false;
|
|
94
|
+
this.localPaymentUpdateQueues = /* @__PURE__ */ new Map();
|
|
88
95
|
this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
|
|
89
96
|
// 模块注册表 - 定义所有可用的模块配置
|
|
90
97
|
this.moduleRegistry = {
|
|
@@ -208,7 +215,7 @@ var Server = class {
|
|
|
208
215
|
*/
|
|
209
216
|
this.handleProductQuery = async ({ url, method, data, config }) => {
|
|
210
217
|
console.log("[Server] handleProductQuery:", url, method, data, config);
|
|
211
|
-
const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type } = data;
|
|
218
|
+
const { menu_list_ids, schedule_datetime, schedule_date, customer_id, ids, extension_type, strategy_context } = data;
|
|
212
219
|
const { callback, subscriberId } = config || {};
|
|
213
220
|
this.logInfo("handleProductQuery: 开始处理商品查询请求", {
|
|
214
221
|
menu_list_ids,
|
|
@@ -216,19 +223,32 @@ var Server = class {
|
|
|
216
223
|
schedule_datetime,
|
|
217
224
|
schedule_date,
|
|
218
225
|
customer_id,
|
|
219
|
-
extension_type
|
|
226
|
+
extension_type,
|
|
227
|
+
strategyContextKeys: strategy_context ? Object.keys(strategy_context) : []
|
|
220
228
|
});
|
|
221
229
|
if (subscriberId && typeof callback === "function") {
|
|
222
230
|
this.productQuerySubscribers.set(subscriberId, {
|
|
223
231
|
callback,
|
|
224
|
-
context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type }
|
|
232
|
+
context: { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, strategy_context }
|
|
225
233
|
});
|
|
226
234
|
this.logInfo("handleProductQuery: 已注册订阅者", {
|
|
227
235
|
subscriberId,
|
|
228
236
|
totalSubscribers: this.productQuerySubscribers.size
|
|
229
237
|
});
|
|
230
238
|
}
|
|
231
|
-
|
|
239
|
+
const result = await this.computeProductQueryResult({
|
|
240
|
+
menu_list_ids,
|
|
241
|
+
ids,
|
|
242
|
+
schedule_date,
|
|
243
|
+
schedule_datetime,
|
|
244
|
+
customer_id,
|
|
245
|
+
extension_type,
|
|
246
|
+
strategy_context
|
|
247
|
+
});
|
|
248
|
+
if (subscriberId && typeof callback === "function") {
|
|
249
|
+
this.syncProductQueryScheduleTimers(subscriberId, strategy_context);
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
232
252
|
};
|
|
233
253
|
/**
|
|
234
254
|
* 按商品 id 查询单条(GET /shop/product/query/:productId)
|
|
@@ -560,6 +580,128 @@ var Server = class {
|
|
|
560
580
|
title: "handleOrderSalesCheckout"
|
|
561
581
|
});
|
|
562
582
|
};
|
|
583
|
+
this.handleOrderSalesDraft = async ({ data }) => {
|
|
584
|
+
return this.handleOrderDraftSubmit({
|
|
585
|
+
data,
|
|
586
|
+
title: "handleOrderSalesDraft"
|
|
587
|
+
});
|
|
588
|
+
};
|
|
589
|
+
this.handleGetLocalPayment = async ({ data }) => {
|
|
590
|
+
const saleId = data == null ? void 0 : data.sale_id;
|
|
591
|
+
const paymentNumber = data == null ? void 0 : data.payment_number;
|
|
592
|
+
const operationId = this.createLocalPaymentOperationId("get");
|
|
593
|
+
const requestContext = {
|
|
594
|
+
operation_id: operationId,
|
|
595
|
+
sale_id: saleId ?? null,
|
|
596
|
+
payment_number: paymentNumber ?? null
|
|
597
|
+
};
|
|
598
|
+
this.logInfo("handleGetLocalPayment: 请求进入", requestContext);
|
|
599
|
+
if (saleId === void 0 || saleId === null || saleId === "" || paymentNumber === void 0 || paymentNumber === null || paymentNumber === "") {
|
|
600
|
+
this.logWarning("handleGetLocalPayment: 参数校验失败", {
|
|
601
|
+
...requestContext,
|
|
602
|
+
missing_fields: [
|
|
603
|
+
...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
|
|
604
|
+
...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : []
|
|
605
|
+
]
|
|
606
|
+
});
|
|
607
|
+
return {
|
|
608
|
+
code: 400,
|
|
609
|
+
status: false,
|
|
610
|
+
message: "sale_id 和 payment_number 必填",
|
|
611
|
+
data: null
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
if (!this.order) {
|
|
615
|
+
this.logError("handleGetLocalPayment: Order 模块未注册", requestContext);
|
|
616
|
+
return { code: 500, status: false, message: "Order 模块未注册", data: null };
|
|
617
|
+
}
|
|
618
|
+
const startedAt = Date.now();
|
|
619
|
+
try {
|
|
620
|
+
this.logInfo("handleGetLocalPayment: 开始查询本地支付项", requestContext);
|
|
621
|
+
const found = await this.order.getLocalPayment({
|
|
622
|
+
saleId,
|
|
623
|
+
paymentNumber,
|
|
624
|
+
operationId
|
|
625
|
+
});
|
|
626
|
+
if (!found) {
|
|
627
|
+
this.logWarning("handleGetLocalPayment: 本地支付项不存在", {
|
|
628
|
+
...requestContext,
|
|
629
|
+
duration_ms: Date.now() - startedAt
|
|
630
|
+
});
|
|
631
|
+
return { code: 404, status: false, message: "本地支付项不存在", data: null };
|
|
632
|
+
}
|
|
633
|
+
this.logInfo("handleGetLocalPayment: 查询命中", {
|
|
634
|
+
...requestContext,
|
|
635
|
+
duration_ms: Date.now() - startedAt,
|
|
636
|
+
matched_by: found.matchedBy,
|
|
637
|
+
payment_index: found.paymentIndex,
|
|
638
|
+
...this.buildLocalPaymentOrderLogContext(found.order),
|
|
639
|
+
payment: found.payment
|
|
640
|
+
});
|
|
641
|
+
return { code: 200, status: true, message: "", data: found.payment };
|
|
642
|
+
} catch (error) {
|
|
643
|
+
this.logError("handleGetLocalPayment: 查询异常", {
|
|
644
|
+
...requestContext,
|
|
645
|
+
duration_ms: Date.now() - startedAt,
|
|
646
|
+
error: error instanceof Error ? error.message : String(error),
|
|
647
|
+
error_detail: this.normalizeUnknownError(error)
|
|
648
|
+
});
|
|
649
|
+
throw error;
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
this.handleUpdateLocalPayment = async ({ data }) => {
|
|
653
|
+
const saleId = data == null ? void 0 : data.sale_id;
|
|
654
|
+
const paymentNumber = data == null ? void 0 : data.payment_number;
|
|
655
|
+
const number = data == null ? void 0 : data.number;
|
|
656
|
+
const status = data == null ? void 0 : data.status;
|
|
657
|
+
const serviceCharge = data == null ? void 0 : data.service_charge;
|
|
658
|
+
const cardReaderSurcharge = data == null ? void 0 : data.card_reader_surcharge;
|
|
659
|
+
const hasSurchargeInput = serviceCharge !== void 0 || cardReaderSurcharge !== void 0;
|
|
660
|
+
const invalidSurchargeFields = this.getInvalidLocalPaymentSurchargeFields(
|
|
661
|
+
serviceCharge,
|
|
662
|
+
cardReaderSurcharge
|
|
663
|
+
);
|
|
664
|
+
const operationId = this.createLocalPaymentOperationId("update");
|
|
665
|
+
const requestContext = {
|
|
666
|
+
operation_id: operationId,
|
|
667
|
+
sale_id: saleId ?? null,
|
|
668
|
+
payment_number: paymentNumber ?? null,
|
|
669
|
+
transaction_number: number ?? null,
|
|
670
|
+
requested_status: status ?? null,
|
|
671
|
+
service_charge: serviceCharge ?? null,
|
|
672
|
+
card_reader_surcharge: cardReaderSurcharge ?? null
|
|
673
|
+
};
|
|
674
|
+
this.logInfo("handleUpdateLocalPayment: 请求进入", requestContext);
|
|
675
|
+
if (saleId === void 0 || saleId === null || saleId === "" || paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" || number === void 0 || number === null || number === "" || status !== "success" && status !== "fail" || invalidSurchargeFields.length > 0) {
|
|
676
|
+
this.logWarning("handleUpdateLocalPayment: 参数校验失败", {
|
|
677
|
+
...requestContext,
|
|
678
|
+
missing_or_invalid_fields: [
|
|
679
|
+
...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
|
|
680
|
+
...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : [],
|
|
681
|
+
...number === void 0 || number === null || number === "" ? ["number"] : [],
|
|
682
|
+
...status !== "success" && status !== "fail" ? ["status"] : [],
|
|
683
|
+
...invalidSurchargeFields
|
|
684
|
+
]
|
|
685
|
+
});
|
|
686
|
+
return {
|
|
687
|
+
code: 400,
|
|
688
|
+
status: false,
|
|
689
|
+
message: invalidSurchargeFields.length > 0 ? `手续费参数非法: ${invalidSurchargeFields.join(", ")}` : "sale_id、payment_number、number 必填,status 仅支持 success/fail",
|
|
690
|
+
data: null
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
const queueKey = `${String(saleId)}:${String(paymentNumber)}`;
|
|
694
|
+
return this.runLocalPaymentUpdateInQueue(queueKey, () => this.processLocalPaymentUpdate({
|
|
695
|
+
operationId,
|
|
696
|
+
saleId,
|
|
697
|
+
paymentNumber,
|
|
698
|
+
number: String(number),
|
|
699
|
+
status,
|
|
700
|
+
serviceCharge,
|
|
701
|
+
cardReaderSurcharge,
|
|
702
|
+
hasSurchargeInput
|
|
703
|
+
}), requestContext);
|
|
704
|
+
};
|
|
563
705
|
this.handleOrderCheckout = async ({ data }) => {
|
|
564
706
|
return this.handleOrderCheckoutSubmit({
|
|
565
707
|
backendPath: "/order/checkout",
|
|
@@ -769,12 +911,13 @@ var Server = class {
|
|
|
769
911
|
if (!this.shouldForceRemoteSalesDetail(data)) {
|
|
770
912
|
const localOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
771
913
|
if (localOrder) {
|
|
914
|
+
const enrichedOrder = await this.withSalesDetailProductSnapshots(localOrder);
|
|
772
915
|
this.logInfo("handleOrderSalesDetail: 命中本地订单", { lookup });
|
|
773
916
|
return {
|
|
774
917
|
code: 200,
|
|
775
918
|
status: true,
|
|
776
919
|
message: "",
|
|
777
|
-
data:
|
|
920
|
+
data: enrichedOrder
|
|
778
921
|
};
|
|
779
922
|
}
|
|
780
923
|
}
|
|
@@ -821,11 +964,12 @@ var Server = class {
|
|
|
821
964
|
};
|
|
822
965
|
}
|
|
823
966
|
this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { lookup });
|
|
967
|
+
const enrichedOrder = await this.withSalesDetailProductSnapshots(savedOrder);
|
|
824
968
|
return {
|
|
825
969
|
code: 200,
|
|
826
970
|
status: true,
|
|
827
971
|
message: "",
|
|
828
|
-
data:
|
|
972
|
+
data: enrichedOrder
|
|
829
973
|
};
|
|
830
974
|
} catch (error) {
|
|
831
975
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1339,7 +1483,7 @@ var Server = class {
|
|
|
1339
1483
|
const { backendPath, title } = params;
|
|
1340
1484
|
const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
|
|
1341
1485
|
const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
1342
|
-
const remoteCheckoutData = this.
|
|
1486
|
+
const remoteCheckoutData = this.buildRemoteCheckoutData(checkoutData, title);
|
|
1343
1487
|
if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
|
|
1344
1488
|
throw new Error("app.request 不可用");
|
|
1345
1489
|
}
|
|
@@ -1355,20 +1499,20 @@ var Server = class {
|
|
|
1355
1499
|
errorResponse: response,
|
|
1356
1500
|
response,
|
|
1357
1501
|
normalizedResponse: this.normalizeCheckoutResponse(response),
|
|
1358
|
-
checkoutData
|
|
1502
|
+
checkoutData
|
|
1359
1503
|
};
|
|
1360
1504
|
}
|
|
1361
1505
|
const fresh = this.extractOrderDataFromCheckoutResponse(response);
|
|
1362
1506
|
const externalSaleNumber = this.getCheckoutExternalSaleNumber(
|
|
1363
|
-
|
|
1507
|
+
checkoutData,
|
|
1364
1508
|
{
|
|
1365
1509
|
external_sale_number: params.externalSaleNumber,
|
|
1366
|
-
data:
|
|
1510
|
+
data: checkoutData
|
|
1367
1511
|
}
|
|
1368
1512
|
);
|
|
1369
1513
|
const syncedOrder = await this.persistSyncedCheckoutOrder({
|
|
1370
1514
|
backendPath,
|
|
1371
|
-
checkoutData
|
|
1515
|
+
checkoutData,
|
|
1372
1516
|
externalSaleNumber,
|
|
1373
1517
|
fresh,
|
|
1374
1518
|
title,
|
|
@@ -1379,11 +1523,11 @@ var Server = class {
|
|
|
1379
1523
|
checkoutResponseOrder: fresh
|
|
1380
1524
|
}) : void 0;
|
|
1381
1525
|
if (printableSyncedOrder && this.shouldPrintSyncedOrder({
|
|
1382
|
-
checkoutData
|
|
1526
|
+
checkoutData,
|
|
1383
1527
|
syncedOrder: printableSyncedOrder
|
|
1384
1528
|
})) {
|
|
1385
1529
|
await this.dispatchPrintOtherReceiptTask({
|
|
1386
|
-
checkoutData
|
|
1530
|
+
checkoutData,
|
|
1387
1531
|
syncedOrder: printableSyncedOrder,
|
|
1388
1532
|
response,
|
|
1389
1533
|
deviceId: params.deviceId
|
|
@@ -1393,7 +1537,7 @@ var Server = class {
|
|
|
1393
1537
|
rejected: false,
|
|
1394
1538
|
response,
|
|
1395
1539
|
normalizedResponse: this.normalizeCheckoutResponse(response),
|
|
1396
|
-
checkoutData
|
|
1540
|
+
checkoutData,
|
|
1397
1541
|
syncedOrder,
|
|
1398
1542
|
fresh
|
|
1399
1543
|
};
|
|
@@ -1406,6 +1550,54 @@ var Server = class {
|
|
|
1406
1550
|
delete next.syncMode;
|
|
1407
1551
|
return next;
|
|
1408
1552
|
}
|
|
1553
|
+
buildRemoteCheckoutData(data, title) {
|
|
1554
|
+
const next = (0, import_lodash_es.cloneDeep)(this.omitCheckoutSyncMode(data));
|
|
1555
|
+
if (!next || typeof next !== "object")
|
|
1556
|
+
return next;
|
|
1557
|
+
const record = next;
|
|
1558
|
+
if (!Array.isArray(record.payments))
|
|
1559
|
+
return next;
|
|
1560
|
+
const originalPayments = record.payments;
|
|
1561
|
+
const filteredPayments = originalPayments.filter((payment) => !(0, import_payment_utils.isPendingOrderPayment)(payment));
|
|
1562
|
+
const removedPayments = originalPayments.filter((payment) => (0, import_payment_utils.isPendingOrderPayment)(payment));
|
|
1563
|
+
record.payments = filteredPayments;
|
|
1564
|
+
this.logInfo(`${title}: checkout 云端支付项已过滤`, {
|
|
1565
|
+
external_sale_number: record.external_sale_number,
|
|
1566
|
+
original_payment_count: originalPayments.length,
|
|
1567
|
+
remote_payment_count: filteredPayments.length,
|
|
1568
|
+
filtered_pending_count: removedPayments.length,
|
|
1569
|
+
filtered_payment_identities: removedPayments.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
1570
|
+
});
|
|
1571
|
+
return next;
|
|
1572
|
+
}
|
|
1573
|
+
mergeCheckoutSyncPayments(checkoutData, fresh, title) {
|
|
1574
|
+
const localPayments = Array.isArray(checkoutData == null ? void 0 : checkoutData.payments) ? checkoutData.payments : [];
|
|
1575
|
+
const freshRecord = fresh;
|
|
1576
|
+
if (!Array.isArray(freshRecord.payments)) {
|
|
1577
|
+
return localPayments.length > 0 ? { ...freshRecord, payments: (0, import_lodash_es.cloneDeep)(localPayments) } : freshRecord;
|
|
1578
|
+
}
|
|
1579
|
+
const freshPayments = freshRecord.payments;
|
|
1580
|
+
const mergedPayments = (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
|
|
1581
|
+
localPayments,
|
|
1582
|
+
freshPayments,
|
|
1583
|
+
{ preserveUnmatchedExistingWhen: import_payment_utils.isIdentifiedPendingOrderPayment }
|
|
1584
|
+
);
|
|
1585
|
+
const remoteIdentityKeys = new Set(
|
|
1586
|
+
freshPayments.flatMap((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
1587
|
+
);
|
|
1588
|
+
const preservedPending = localPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => remoteIdentityKeys.has(key)));
|
|
1589
|
+
if (preservedPending.length > 0) {
|
|
1590
|
+
this.logInfo(`${title}: checkout 响应合并保留本地 pending 支付项`, {
|
|
1591
|
+
external_sale_number: checkoutData == null ? void 0 : checkoutData.external_sale_number,
|
|
1592
|
+
preserved_pending_count: preservedPending.length,
|
|
1593
|
+
preserved_payment_identities: preservedPending.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
return {
|
|
1597
|
+
...freshRecord,
|
|
1598
|
+
payments: mergedPayments
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1409
1601
|
async persistSyncedCheckoutOrder(params) {
|
|
1410
1602
|
const {
|
|
1411
1603
|
backendPath,
|
|
@@ -1420,15 +1612,17 @@ var Server = class {
|
|
|
1420
1612
|
if (this.order && fresh && (shouldMergeRemoteOrder || persistCheckoutDataWithResponse)) {
|
|
1421
1613
|
syncedOrder = persistCheckoutDataWithResponse ? {
|
|
1422
1614
|
...checkoutData,
|
|
1423
|
-
...fresh,
|
|
1615
|
+
...this.mergeCheckoutSyncPayments(checkoutData, fresh, title),
|
|
1424
1616
|
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1425
|
-
need_sync: 0
|
|
1617
|
+
need_sync: 0,
|
|
1618
|
+
is_draft_order: 0
|
|
1426
1619
|
} : {
|
|
1427
|
-
...fresh,
|
|
1620
|
+
...this.mergeCheckoutSyncPayments(checkoutData, fresh, title),
|
|
1428
1621
|
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1429
|
-
need_sync: 0
|
|
1622
|
+
need_sync: 0,
|
|
1623
|
+
is_draft_order: 0
|
|
1430
1624
|
};
|
|
1431
|
-
await this.order.upsertOrdersFromRemote([syncedOrder]);
|
|
1625
|
+
await this.order.upsertOrdersFromRemote([syncedOrder], "checkoutSync");
|
|
1432
1626
|
this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
|
|
1433
1627
|
order_id: fresh.order_id,
|
|
1434
1628
|
external_sale_number: syncedOrder.external_sale_number,
|
|
@@ -1446,7 +1640,8 @@ var Server = class {
|
|
|
1446
1640
|
...checkoutData,
|
|
1447
1641
|
...patch,
|
|
1448
1642
|
external_sale_number: externalSaleNumber,
|
|
1449
|
-
need_sync: 0
|
|
1643
|
+
need_sync: 0,
|
|
1644
|
+
is_draft_order: 0
|
|
1450
1645
|
};
|
|
1451
1646
|
this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
|
|
1452
1647
|
order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
|
|
@@ -1826,6 +2021,11 @@ var Server = class {
|
|
|
1826
2021
|
path: "/shop/order/sales/checkout",
|
|
1827
2022
|
handler: this.handleOrderSalesCheckout.bind(this)
|
|
1828
2023
|
},
|
|
2024
|
+
{
|
|
2025
|
+
method: "post",
|
|
2026
|
+
path: "/shop/order/sales/draft",
|
|
2027
|
+
handler: this.handleOrderSalesDraft.bind(this)
|
|
2028
|
+
},
|
|
1829
2029
|
{
|
|
1830
2030
|
method: "post",
|
|
1831
2031
|
path: "/order/checkout",
|
|
@@ -1836,6 +2036,16 @@ var Server = class {
|
|
|
1836
2036
|
path: "/shop/local/print-order",
|
|
1837
2037
|
handler: this.handleLocalPrintOrder.bind(this)
|
|
1838
2038
|
},
|
|
2039
|
+
{
|
|
2040
|
+
method: "post",
|
|
2041
|
+
path: "/shop/local/getLocalPayment",
|
|
2042
|
+
handler: this.handleGetLocalPayment.bind(this)
|
|
2043
|
+
},
|
|
2044
|
+
{
|
|
2045
|
+
method: "post",
|
|
2046
|
+
path: "/shop/local/updateLocalPayment",
|
|
2047
|
+
handler: this.handleUpdateLocalPayment.bind(this)
|
|
2048
|
+
},
|
|
1839
2049
|
{
|
|
1840
2050
|
method: "post",
|
|
1841
2051
|
path: "/shop/machinecode/batch",
|
|
@@ -1909,6 +2119,7 @@ var Server = class {
|
|
|
1909
2119
|
*/
|
|
1910
2120
|
removeProductQuerySubscriber(subscriberId) {
|
|
1911
2121
|
if (subscriberId) {
|
|
2122
|
+
this.clearSubscriberScheduleTimers(subscriberId);
|
|
1912
2123
|
this.productQuerySubscribers.delete(subscriberId);
|
|
1913
2124
|
this.logInfo("removeProductQuerySubscriber: 已移除订阅者", {
|
|
1914
2125
|
subscriberId,
|
|
@@ -1916,6 +2127,156 @@ var Server = class {
|
|
|
1916
2127
|
});
|
|
1917
2128
|
}
|
|
1918
2129
|
}
|
|
2130
|
+
/**
|
|
2131
|
+
* 构建商品 query 响应 data 段,附带智能定价 schedule_time_points 元数据。
|
|
2132
|
+
*/
|
|
2133
|
+
buildProductQueryResultPayload(list, count) {
|
|
2134
|
+
var _a, _b;
|
|
2135
|
+
return {
|
|
2136
|
+
list,
|
|
2137
|
+
count: count ?? list.length,
|
|
2138
|
+
schedule_time_points: ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? []
|
|
2139
|
+
};
|
|
2140
|
+
}
|
|
2141
|
+
/**
|
|
2142
|
+
* 是否启用商品 query 订阅的 schedule 时间点定时重算。
|
|
2143
|
+
* strategy_context.enable_schedule_reload === false 时关闭。
|
|
2144
|
+
*/
|
|
2145
|
+
shouldScheduleProductQueryReload(strategy_context) {
|
|
2146
|
+
return (strategy_context == null ? void 0 : strategy_context.enable_schedule_reload) !== false;
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* 清除指定 subscriber 的全部 schedule 定时器,防止重复 query 或 unsubscribe 后泄漏。
|
|
2150
|
+
*/
|
|
2151
|
+
clearSubscriberScheduleTimers(subscriberId) {
|
|
2152
|
+
const timers = this.productQueryScheduleTimers.get(subscriberId);
|
|
2153
|
+
if (timers == null ? void 0 : timers.length) {
|
|
2154
|
+
timers.forEach((timerId) => clearTimeout(timerId));
|
|
2155
|
+
}
|
|
2156
|
+
this.productQueryScheduleTimers.delete(subscriberId);
|
|
2157
|
+
const subscriber = this.productQuerySubscribers.get(subscriberId);
|
|
2158
|
+
if (subscriber) {
|
|
2159
|
+
subscriber.scheduleTimerIds = [];
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
/**
|
|
2163
|
+
* 从 productQueryScheduleTimers 移除已触发的 timer 引用。
|
|
2164
|
+
*/
|
|
2165
|
+
removeScheduleTimerRef(subscriberId, timerId) {
|
|
2166
|
+
const timers = this.productQueryScheduleTimers.get(subscriberId);
|
|
2167
|
+
if (!(timers == null ? void 0 : timers.length))
|
|
2168
|
+
return;
|
|
2169
|
+
const next = timers.filter((id) => id !== timerId);
|
|
2170
|
+
if (next.length === 0) {
|
|
2171
|
+
this.productQueryScheduleTimers.delete(subscriberId);
|
|
2172
|
+
} else {
|
|
2173
|
+
this.productQueryScheduleTimers.set(subscriberId, next);
|
|
2174
|
+
}
|
|
2175
|
+
const subscriber = this.productQuerySubscribers.get(subscriberId);
|
|
2176
|
+
if (subscriber) {
|
|
2177
|
+
subscriber.scheduleTimerIds = next;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
/**
|
|
2181
|
+
* 计算 schedule 变价时间点到当前时刻的延迟(ms)。已过期返回 -1。
|
|
2182
|
+
*/
|
|
2183
|
+
computeScheduleTimePointDelayMs(scheduleDate, timePoint) {
|
|
2184
|
+
const parts = timePoint.split(":");
|
|
2185
|
+
if (parts.length < 2)
|
|
2186
|
+
return -1;
|
|
2187
|
+
const hours = parseInt(parts[0], 10);
|
|
2188
|
+
const minutes = parseInt(parts[1], 10);
|
|
2189
|
+
if (!Number.isFinite(hours) || !Number.isFinite(minutes))
|
|
2190
|
+
return -1;
|
|
2191
|
+
const target = (0, import_dayjs.default)(scheduleDate).hour(hours).minute(minutes).second(4).millisecond(0);
|
|
2192
|
+
const delayMs = target.diff((0, import_dayjs.default)());
|
|
2193
|
+
return delayMs >= 0 ? delayMs : -1;
|
|
2194
|
+
}
|
|
2195
|
+
/**
|
|
2196
|
+
* 定时重算前刷新 subscriber schedule 上下文:使用执行瞬间时间,禁止沿用首次 query 的 schedule_datetime。
|
|
2197
|
+
*/
|
|
2198
|
+
refreshSubscriberScheduleAtExecution(subscriber) {
|
|
2199
|
+
const executedAt = (0, import_dayjs.default)();
|
|
2200
|
+
const bookingDate = subscriber.context.schedule_date || executedAt.format("YYYY-MM-DD");
|
|
2201
|
+
subscriber.context.schedule_date = bookingDate;
|
|
2202
|
+
subscriber.context.schedule_datetime = `${bookingDate} ${executedAt.format("HH:mm:ss")}`;
|
|
2203
|
+
}
|
|
2204
|
+
/**
|
|
2205
|
+
* 为 subscriber 注册智能定价 scheduleTimePoints 定时重算。
|
|
2206
|
+
* 必须先 clearSubscriberScheduleTimers,再调用本方法。
|
|
2207
|
+
*/
|
|
2208
|
+
scheduleSubscriberTimePointReloads(subscriberId, timePoints) {
|
|
2209
|
+
const subscriber = this.productQuerySubscribers.get(subscriberId);
|
|
2210
|
+
if (!subscriber || !timePoints.length)
|
|
2211
|
+
return;
|
|
2212
|
+
const scheduleDate = subscriber.context.schedule_date || (0, import_dayjs.default)().format("YYYY-MM-DD");
|
|
2213
|
+
const timerIds = [];
|
|
2214
|
+
for (const timePoint of timePoints) {
|
|
2215
|
+
const delayMs = this.computeScheduleTimePointDelayMs(scheduleDate, timePoint);
|
|
2216
|
+
if (delayMs < 0)
|
|
2217
|
+
continue;
|
|
2218
|
+
const timerId = setTimeout(() => {
|
|
2219
|
+
void this.onScheduleTimePointTimerFire(subscriberId, timerId);
|
|
2220
|
+
}, delayMs);
|
|
2221
|
+
timerIds.push(timerId);
|
|
2222
|
+
}
|
|
2223
|
+
if (timerIds.length > 0) {
|
|
2224
|
+
this.productQueryScheduleTimers.set(subscriberId, timerIds);
|
|
2225
|
+
subscriber.scheduleTimerIds = timerIds;
|
|
2226
|
+
this.logInfo("scheduleSubscriberTimePointReloads: 已注册定时器", {
|
|
2227
|
+
subscriberId,
|
|
2228
|
+
timerCount: timerIds.length,
|
|
2229
|
+
timePoints
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
/**
|
|
2234
|
+
* schedule 变价时间点定时器触发:刷新 schedule_datetime 后重算并 callback。
|
|
2235
|
+
*/
|
|
2236
|
+
async onScheduleTimePointTimerFire(subscriberId, timerId) {
|
|
2237
|
+
this.removeScheduleTimerRef(subscriberId, timerId);
|
|
2238
|
+
if (!this.productQuerySubscribers.has(subscriberId))
|
|
2239
|
+
return;
|
|
2240
|
+
const subscriber = this.productQuerySubscribers.get(subscriberId);
|
|
2241
|
+
this.refreshSubscriberScheduleAtExecution(subscriber);
|
|
2242
|
+
await this.recomputeAndNotifySubscriber(subscriberId);
|
|
2243
|
+
}
|
|
2244
|
+
/**
|
|
2245
|
+
* 对单个商品 query 订阅者重算并推送(定时路径;不新建 schedule timer)。
|
|
2246
|
+
*/
|
|
2247
|
+
async recomputeAndNotifySubscriber(subscriberId) {
|
|
2248
|
+
const subscriber = this.productQuerySubscribers.get(subscriberId);
|
|
2249
|
+
if (!subscriber)
|
|
2250
|
+
return;
|
|
2251
|
+
try {
|
|
2252
|
+
const result = await this.computeProductQueryResult(subscriber.context);
|
|
2253
|
+
subscriber.callback(result);
|
|
2254
|
+
this.logInfo("recomputeAndNotifySubscriber: 已推送", {
|
|
2255
|
+
subscriberId,
|
|
2256
|
+
schedule_datetime: subscriber.context.schedule_datetime
|
|
2257
|
+
});
|
|
2258
|
+
} catch (error) {
|
|
2259
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2260
|
+
this.logError("recomputeAndNotifySubscriber: 推送失败", {
|
|
2261
|
+
subscriberId,
|
|
2262
|
+
error: errorMessage
|
|
2263
|
+
});
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
/**
|
|
2267
|
+
* query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
|
|
2268
|
+
*/
|
|
2269
|
+
syncProductQueryScheduleTimers(subscriberId, strategy_context) {
|
|
2270
|
+
var _a, _b;
|
|
2271
|
+
this.clearSubscriberScheduleTimers(subscriberId);
|
|
2272
|
+
if (!this.shouldScheduleProductQueryReload(strategy_context)) {
|
|
2273
|
+
return;
|
|
2274
|
+
}
|
|
2275
|
+
const timePoints = ((_b = (_a = this.products) == null ? void 0 : _a.getLastScheduleTimePoints) == null ? void 0 : _b.call(_a)) ?? [];
|
|
2276
|
+
if (timePoints.length > 0) {
|
|
2277
|
+
this.scheduleSubscriberTimePointReloads(subscriberId, timePoints);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
1919
2280
|
/**
|
|
1920
2281
|
* 执行 sales 搜索并登记可见订单号。
|
|
1921
2282
|
* 搜索参数完全透传后端,OS 不做过滤、筛选、排序。
|
|
@@ -2526,6 +2887,405 @@ var Server = class {
|
|
|
2526
2887
|
};
|
|
2527
2888
|
}
|
|
2528
2889
|
}
|
|
2890
|
+
createLocalPaymentOperationId(action) {
|
|
2891
|
+
return `local_payment_${action}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2892
|
+
}
|
|
2893
|
+
buildLocalPaymentOrderLogContext(order) {
|
|
2894
|
+
if (!order)
|
|
2895
|
+
return {};
|
|
2896
|
+
return {
|
|
2897
|
+
order_id: order.order_id ?? null,
|
|
2898
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
2899
|
+
order_number: order.order_number ?? null,
|
|
2900
|
+
shop_order_number: order.shop_order_number ?? null,
|
|
2901
|
+
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
2902
|
+
order_status: order.status ?? null,
|
|
2903
|
+
payment_status: order.payment_status ?? null,
|
|
2904
|
+
is_draft_order: Number(order.is_draft_order || 0),
|
|
2905
|
+
need_sync: Number(order.need_sync || 0),
|
|
2906
|
+
platform: order.platform ?? null,
|
|
2907
|
+
business_code: order.business_code ?? null,
|
|
2908
|
+
order_sales_channel: order.order_sales_channel ?? null,
|
|
2909
|
+
sales_channel: order.sales_channel ?? null,
|
|
2910
|
+
order_type: order.type ?? null,
|
|
2911
|
+
payments_count: Array.isArray(order.payments) ? order.payments.length : 0
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2914
|
+
isValidLocalPaymentDecimal(value) {
|
|
2915
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
2916
|
+
return false;
|
|
2917
|
+
if (typeof value === "string" && value.trim() === "")
|
|
2918
|
+
return false;
|
|
2919
|
+
try {
|
|
2920
|
+
return new import_decimal.default(value).isFinite();
|
|
2921
|
+
} catch {
|
|
2922
|
+
return false;
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
getInvalidLocalPaymentSurchargeFields(serviceCharge, cardReaderSurcharge) {
|
|
2926
|
+
const invalidFields = [];
|
|
2927
|
+
if (serviceCharge !== void 0) {
|
|
2928
|
+
if (serviceCharge === null || typeof serviceCharge !== "object" || Array.isArray(serviceCharge)) {
|
|
2929
|
+
invalidFields.push("service_charge");
|
|
2930
|
+
} else {
|
|
2931
|
+
const input = serviceCharge;
|
|
2932
|
+
if (input.fixed !== void 0 && !this.isValidLocalPaymentDecimal(input.fixed)) {
|
|
2933
|
+
invalidFields.push("service_charge.fixed");
|
|
2934
|
+
}
|
|
2935
|
+
if (input.percentage !== void 0 && !this.isValidLocalPaymentDecimal(input.percentage)) {
|
|
2936
|
+
invalidFields.push("service_charge.percentage");
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
if (cardReaderSurcharge !== void 0 && !this.isValidLocalPaymentDecimal(cardReaderSurcharge)) {
|
|
2941
|
+
invalidFields.push("card_reader_surcharge");
|
|
2942
|
+
}
|
|
2943
|
+
return invalidFields;
|
|
2944
|
+
}
|
|
2945
|
+
buildLocalPaymentSurchargeUpdate(params) {
|
|
2946
|
+
var _a, _b, _c;
|
|
2947
|
+
const amount = new import_decimal.default(((_a = params.serviceCharge) == null ? void 0 : _a.fixed) || 0).plus(params.cardReaderSurcharge || 0).toFixed(2);
|
|
2948
|
+
const serviceFee = new import_decimal.default(params.paymentAmount || 0).times(((_b = params.serviceCharge) == null ? void 0 : _b.percentage) || 0).plus(amount).toDecimalPlaces(2).toFixed(2);
|
|
2949
|
+
return {
|
|
2950
|
+
service_charge: {
|
|
2951
|
+
amount,
|
|
2952
|
+
...((_c = params.serviceCharge) == null ? void 0 : _c.percentage) !== void 0 ? { percentage: params.serviceCharge.percentage } : {}
|
|
2953
|
+
},
|
|
2954
|
+
service_fee: serviceFee
|
|
2955
|
+
};
|
|
2956
|
+
}
|
|
2957
|
+
async runLocalPaymentUpdateInQueue(key, task, context) {
|
|
2958
|
+
var _a;
|
|
2959
|
+
const queuedAt = Date.now();
|
|
2960
|
+
const hasPreviousTask = this.localPaymentUpdateQueues.has(key);
|
|
2961
|
+
const previous = this.localPaymentUpdateQueues.get(key) || Promise.resolve();
|
|
2962
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列入队", {
|
|
2963
|
+
...context,
|
|
2964
|
+
queue_key: key,
|
|
2965
|
+
waiting_for_previous: hasPreviousTask,
|
|
2966
|
+
active_queue_count: this.localPaymentUpdateQueues.size
|
|
2967
|
+
});
|
|
2968
|
+
const current = previous.catch(() => void 0).then(async () => {
|
|
2969
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列开始执行", {
|
|
2970
|
+
...context,
|
|
2971
|
+
queue_key: key,
|
|
2972
|
+
queue_wait_ms: Date.now() - queuedAt
|
|
2973
|
+
});
|
|
2974
|
+
return task();
|
|
2975
|
+
});
|
|
2976
|
+
const tail = current.then(() => void 0, () => void 0);
|
|
2977
|
+
this.localPaymentUpdateQueues.set(key, tail);
|
|
2978
|
+
try {
|
|
2979
|
+
const result = await current;
|
|
2980
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列执行完成", {
|
|
2981
|
+
...context,
|
|
2982
|
+
queue_key: key,
|
|
2983
|
+
total_duration_ms: Date.now() - queuedAt,
|
|
2984
|
+
result_code: result == null ? void 0 : result.code,
|
|
2985
|
+
result_status: result == null ? void 0 : result.status,
|
|
2986
|
+
payment: (_a = result == null ? void 0 : result.data) == null ? void 0 : _a.payment
|
|
2987
|
+
});
|
|
2988
|
+
return result;
|
|
2989
|
+
} catch (error) {
|
|
2990
|
+
this.logError("handleUpdateLocalPayment: 串行队列执行失败", {
|
|
2991
|
+
...context,
|
|
2992
|
+
queue_key: key,
|
|
2993
|
+
total_duration_ms: Date.now() - queuedAt,
|
|
2994
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2995
|
+
error_detail: this.normalizeUnknownError(error)
|
|
2996
|
+
});
|
|
2997
|
+
throw error;
|
|
2998
|
+
} finally {
|
|
2999
|
+
let released = false;
|
|
3000
|
+
if (this.localPaymentUpdateQueues.get(key) === tail) {
|
|
3001
|
+
this.localPaymentUpdateQueues.delete(key);
|
|
3002
|
+
released = true;
|
|
3003
|
+
}
|
|
3004
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列释放", {
|
|
3005
|
+
...context,
|
|
3006
|
+
queue_key: key,
|
|
3007
|
+
released,
|
|
3008
|
+
active_queue_count: this.localPaymentUpdateQueues.size
|
|
3009
|
+
});
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
async processLocalPaymentUpdate(params) {
|
|
3013
|
+
var _a, _b, _c;
|
|
3014
|
+
const requestContext = {
|
|
3015
|
+
operation_id: params.operationId,
|
|
3016
|
+
sale_id: params.saleId,
|
|
3017
|
+
payment_number: params.paymentNumber,
|
|
3018
|
+
transaction_number: params.number,
|
|
3019
|
+
requested_status: params.status,
|
|
3020
|
+
service_charge: params.serviceCharge ?? null,
|
|
3021
|
+
card_reader_surcharge: params.cardReaderSurcharge ?? null
|
|
3022
|
+
};
|
|
3023
|
+
this.logInfo("processLocalPaymentUpdate: 开始处理", requestContext);
|
|
3024
|
+
if (!this.order) {
|
|
3025
|
+
this.logError("processLocalPaymentUpdate: Order 模块未注册", requestContext);
|
|
3026
|
+
return { code: 500, status: false, message: "Order 模块未注册", data: null };
|
|
3027
|
+
}
|
|
3028
|
+
this.logInfo("processLocalPaymentUpdate: 开始查询本地支付项", requestContext);
|
|
3029
|
+
const found = await this.order.getLocalPayment({
|
|
3030
|
+
saleId: params.saleId,
|
|
3031
|
+
paymentNumber: params.paymentNumber,
|
|
3032
|
+
operationId: params.operationId
|
|
3033
|
+
});
|
|
3034
|
+
if (!found) {
|
|
3035
|
+
this.logWarning("processLocalPaymentUpdate: 本地支付项不存在", requestContext);
|
|
3036
|
+
return { code: 404, status: false, message: "本地支付项不存在", data: null };
|
|
3037
|
+
}
|
|
3038
|
+
const surchargeUpdate = params.status === "success" && params.hasSurchargeInput ? this.buildLocalPaymentSurchargeUpdate({
|
|
3039
|
+
paymentAmount: (_a = found.payment) == null ? void 0 : _a.amount,
|
|
3040
|
+
serviceCharge: params.serviceCharge,
|
|
3041
|
+
cardReaderSurcharge: params.cardReaderSurcharge
|
|
3042
|
+
}) : void 0;
|
|
3043
|
+
const incomingPaymentUpdate = params.status === "success" ? {
|
|
3044
|
+
status: "paid",
|
|
3045
|
+
...surchargeUpdate || {},
|
|
3046
|
+
metadata: {
|
|
3047
|
+
unique_payment_number: params.number,
|
|
3048
|
+
transactions: [{ number: params.number, status: "success" }]
|
|
3049
|
+
}
|
|
3050
|
+
} : {
|
|
3051
|
+
metadata: {
|
|
3052
|
+
transactions: [{ number: params.number, status: "fail" }]
|
|
3053
|
+
}
|
|
3054
|
+
};
|
|
3055
|
+
const transactions = Array.isArray((_c = (_b = found.payment) == null ? void 0 : _b.metadata) == null ? void 0 : _c.transactions) ? found.payment.metadata.transactions : [];
|
|
3056
|
+
const existingTransaction = transactions.find((item) => String((item == null ? void 0 : item.number) || "") === params.number);
|
|
3057
|
+
const hasRecordedSuccess = transactions.some((item) => (item == null ? void 0 : item.status) === "success");
|
|
3058
|
+
const orderIsDraft = Number(found.order.is_draft_order || 0) === 1;
|
|
3059
|
+
const foundContext = {
|
|
3060
|
+
...requestContext,
|
|
3061
|
+
matched_by: found.matchedBy,
|
|
3062
|
+
payment_index: found.paymentIndex,
|
|
3063
|
+
...this.buildLocalPaymentOrderLogContext(found.order),
|
|
3064
|
+
payment: found.payment,
|
|
3065
|
+
incoming_payment_update: incomingPaymentUpdate,
|
|
3066
|
+
existing_transaction: existingTransaction || null,
|
|
3067
|
+
has_recorded_success: hasRecordedSuccess
|
|
3068
|
+
};
|
|
3069
|
+
this.logInfo("processLocalPaymentUpdate: 查询命中", foundContext);
|
|
3070
|
+
if (params.status === "fail" && (found.payment.status === "paid" || hasRecordedSuccess)) {
|
|
3071
|
+
this.logInfo("processLocalPaymentUpdate: 幂等返回", {
|
|
3072
|
+
...foundContext,
|
|
3073
|
+
idempotent_reason: "ignore_failure_after_success"
|
|
3074
|
+
});
|
|
3075
|
+
return {
|
|
3076
|
+
code: 200,
|
|
3077
|
+
status: true,
|
|
3078
|
+
message: "",
|
|
3079
|
+
data: { payment: found.payment, order: found.order, idempotent: true }
|
|
3080
|
+
};
|
|
3081
|
+
}
|
|
3082
|
+
const alreadyRecordedFailure = params.status === "fail" && (existingTransaction == null ? void 0 : existingTransaction.status) === "fail";
|
|
3083
|
+
if (alreadyRecordedFailure) {
|
|
3084
|
+
this.logInfo("processLocalPaymentUpdate: 幂等返回", {
|
|
3085
|
+
...foundContext,
|
|
3086
|
+
idempotent_reason: "failure_already_recorded"
|
|
3087
|
+
});
|
|
3088
|
+
return {
|
|
3089
|
+
code: 200,
|
|
3090
|
+
status: true,
|
|
3091
|
+
message: "",
|
|
3092
|
+
data: { payment: found.payment, order: found.order, idempotent: true }
|
|
3093
|
+
};
|
|
3094
|
+
}
|
|
3095
|
+
if (params.status === "success" && (existingTransaction == null ? void 0 : existingTransaction.status) === "success" && found.payment.status === "paid" && !orderIsDraft) {
|
|
3096
|
+
this.logInfo("processLocalPaymentUpdate: 幂等返回", {
|
|
3097
|
+
...foundContext,
|
|
3098
|
+
idempotent_reason: "success_already_committed"
|
|
3099
|
+
});
|
|
3100
|
+
return {
|
|
3101
|
+
code: 200,
|
|
3102
|
+
status: true,
|
|
3103
|
+
message: "",
|
|
3104
|
+
data: { payment: found.payment, order: found.order, idempotent: true }
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3107
|
+
if (params.status === "success") {
|
|
3108
|
+
this.logInfo("processLocalPaymentUpdate: 进入 success 恢复分支", {
|
|
3109
|
+
...foundContext,
|
|
3110
|
+
force_submit_if_paid: found.payment.status === "paid" && orderIsDraft
|
|
3111
|
+
});
|
|
3112
|
+
return this.processSuccessfulLocalPayment({
|
|
3113
|
+
...params,
|
|
3114
|
+
order: found.order,
|
|
3115
|
+
payment: found.payment,
|
|
3116
|
+
matchBy: found.matchedBy === "payment_number" ? "payment_number" : "compat",
|
|
3117
|
+
forceSubmitIfPaid: found.payment.status === "paid" && orderIsDraft,
|
|
3118
|
+
paymentUpdate: incomingPaymentUpdate
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
this.logInfo("processLocalPaymentUpdate: 进入 fail 本地更新分支", {
|
|
3122
|
+
...foundContext,
|
|
3123
|
+
incoming_payment_update: incomingPaymentUpdate
|
|
3124
|
+
});
|
|
3125
|
+
let updated;
|
|
3126
|
+
try {
|
|
3127
|
+
updated = await this.order.updateLocalPayment({
|
|
3128
|
+
saleId: params.saleId,
|
|
3129
|
+
paymentNumber: params.paymentNumber,
|
|
3130
|
+
operationId: params.operationId,
|
|
3131
|
+
updates: incomingPaymentUpdate
|
|
3132
|
+
});
|
|
3133
|
+
} catch (error) {
|
|
3134
|
+
this.logError("processLocalPaymentUpdate: fail 本地更新失败", {
|
|
3135
|
+
...foundContext,
|
|
3136
|
+
incoming_payment_update: incomingPaymentUpdate,
|
|
3137
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3138
|
+
error_detail: this.normalizeUnknownError(error)
|
|
3139
|
+
});
|
|
3140
|
+
throw error;
|
|
3141
|
+
}
|
|
3142
|
+
if (!updated) {
|
|
3143
|
+
this.logWarning("processLocalPaymentUpdate: fail 本地更新未命中", foundContext);
|
|
3144
|
+
return { code: 404, status: false, message: "本地支付项不存在", data: null };
|
|
3145
|
+
}
|
|
3146
|
+
this.logInfo("processLocalPaymentUpdate: fail 本地更新完成", {
|
|
3147
|
+
...requestContext,
|
|
3148
|
+
...this.buildLocalPaymentOrderLogContext(updated.order),
|
|
3149
|
+
previous_payment: updated.previousPayment,
|
|
3150
|
+
payment: updated.payment
|
|
3151
|
+
});
|
|
3152
|
+
return {
|
|
3153
|
+
code: 200,
|
|
3154
|
+
status: true,
|
|
3155
|
+
message: "",
|
|
3156
|
+
data: {
|
|
3157
|
+
local_only: true,
|
|
3158
|
+
payment: updated.payment,
|
|
3159
|
+
order: updated.order
|
|
3160
|
+
}
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3163
|
+
async processSuccessfulLocalPayment(params) {
|
|
3164
|
+
var _a, _b, _c, _d, _e;
|
|
3165
|
+
const moduleName = `local_payment_recovery_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
3166
|
+
const baseSales = new import_BaseSales.BaseSalesImpl(moduleName);
|
|
3167
|
+
const startedAt = Date.now();
|
|
3168
|
+
const recoveryContext = {
|
|
3169
|
+
operation_id: params.operationId,
|
|
3170
|
+
sale_id: params.saleId,
|
|
3171
|
+
payment_number: params.paymentNumber,
|
|
3172
|
+
transaction_number: params.number,
|
|
3173
|
+
requested_status: "success",
|
|
3174
|
+
match_by: params.matchBy,
|
|
3175
|
+
force_submit_if_paid: params.forceSubmitIfPaid,
|
|
3176
|
+
incoming_payment_update: params.paymentUpdate,
|
|
3177
|
+
base_sales_module_name: moduleName,
|
|
3178
|
+
...this.buildLocalPaymentOrderLogContext(params.order),
|
|
3179
|
+
payment: params.payment
|
|
3180
|
+
};
|
|
3181
|
+
this.logInfo("processSuccessfulLocalPayment: 创建临时 BaseSales", recoveryContext);
|
|
3182
|
+
try {
|
|
3183
|
+
const order = this.sanitizeLocalRecoveryOrder(params.order);
|
|
3184
|
+
this.logInfo("processSuccessfulLocalPayment: 本地订单清洗完成", {
|
|
3185
|
+
...recoveryContext,
|
|
3186
|
+
sanitized_order_id: order.order_id ?? null,
|
|
3187
|
+
removed_synthetic_order_id: params.order.order_id != null && order.order_id == null
|
|
3188
|
+
});
|
|
3189
|
+
await baseSales.initialize(this.core, {
|
|
3190
|
+
otherParams: {
|
|
3191
|
+
platform: order.platform,
|
|
3192
|
+
businessCode: order.business_code,
|
|
3193
|
+
business_code: order.business_code,
|
|
3194
|
+
channel: order.order_sales_channel || order.sales_channel,
|
|
3195
|
+
type: order.type,
|
|
3196
|
+
enableTempOrderPersist: false
|
|
3197
|
+
}
|
|
3198
|
+
});
|
|
3199
|
+
this.logInfo("processSuccessfulLocalPayment: BaseSales 初始化完成", recoveryContext);
|
|
3200
|
+
await baseSales.replaceTempOrder(order);
|
|
3201
|
+
this.logInfo("processSuccessfulLocalPayment: 本地订单 tempOrder 恢复完成", recoveryContext);
|
|
3202
|
+
this.logInfo("processSuccessfulLocalPayment: 开始更新支付项并提交", {
|
|
3203
|
+
...recoveryContext,
|
|
3204
|
+
incoming_payment_update: params.paymentUpdate
|
|
3205
|
+
});
|
|
3206
|
+
const result = await baseSales.updateOrderPayment(
|
|
3207
|
+
params.paymentNumber,
|
|
3208
|
+
params.paymentUpdate,
|
|
3209
|
+
{
|
|
3210
|
+
submitWhenPaid: true,
|
|
3211
|
+
matchBy: params.matchBy,
|
|
3212
|
+
forceSubmitIfPaid: params.forceSubmitIfPaid,
|
|
3213
|
+
applyUpdatesWhenPaid: params.forceSubmitIfPaid,
|
|
3214
|
+
smallTicketDataFlag: 1
|
|
3215
|
+
}
|
|
3216
|
+
);
|
|
3217
|
+
this.logInfo("processSuccessfulLocalPayment: 支付恢复完成", {
|
|
3218
|
+
...recoveryContext,
|
|
3219
|
+
duration_ms: Date.now() - startedAt,
|
|
3220
|
+
payment: result.payment,
|
|
3221
|
+
payments_count: ((_a = result.payments) == null ? void 0 : _a.length) || 0,
|
|
3222
|
+
summary: result.summary,
|
|
3223
|
+
sync_result: result.syncResult ? {
|
|
3224
|
+
is_fully_paid: result.syncResult.isFullyPaid,
|
|
3225
|
+
is_order_fully_paid: result.syncResult.isOrderFullyPaid,
|
|
3226
|
+
is_deposit_fully_paid: result.syncResult.isDepositFullyPaid,
|
|
3227
|
+
payment_stage: result.syncResult.paymentStage,
|
|
3228
|
+
deposit_amount: result.syncResult.depositAmount,
|
|
3229
|
+
order_expected_amount: result.syncResult.orderExpectedAmount,
|
|
3230
|
+
submit_result_code: (_b = result.syncResult.submitResult) == null ? void 0 : _b.code,
|
|
3231
|
+
submit_result_status: (_c = result.syncResult.submitResult) == null ? void 0 : _c.status
|
|
3232
|
+
} : null,
|
|
3233
|
+
draft_result: result.draftResult ? {
|
|
3234
|
+
code: (_d = result.draftResult) == null ? void 0 : _d.code,
|
|
3235
|
+
status: (_e = result.draftResult) == null ? void 0 : _e.status
|
|
3236
|
+
} : null,
|
|
3237
|
+
draft_error: result.draftError instanceof Error ? result.draftError.message : result.draftError
|
|
3238
|
+
});
|
|
3239
|
+
return {
|
|
3240
|
+
code: 200,
|
|
3241
|
+
status: true,
|
|
3242
|
+
message: "",
|
|
3243
|
+
data: {
|
|
3244
|
+
payment: result.payment,
|
|
3245
|
+
payments: result.payments,
|
|
3246
|
+
summary: result.summary,
|
|
3247
|
+
sync_result: result.syncResult
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
} catch (error) {
|
|
3251
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3252
|
+
this.logError("processSuccessfulLocalPayment: 支付恢复失败", {
|
|
3253
|
+
...recoveryContext,
|
|
3254
|
+
duration_ms: Date.now() - startedAt,
|
|
3255
|
+
error: message,
|
|
3256
|
+
error_detail: this.normalizeUnknownError(error)
|
|
3257
|
+
});
|
|
3258
|
+
return { code: 500, status: false, message, data: null };
|
|
3259
|
+
} finally {
|
|
3260
|
+
try {
|
|
3261
|
+
await baseSales.destroy();
|
|
3262
|
+
this.logInfo("processSuccessfulLocalPayment: 临时 BaseSales 销毁完成", {
|
|
3263
|
+
...recoveryContext,
|
|
3264
|
+
duration_ms: Date.now() - startedAt
|
|
3265
|
+
});
|
|
3266
|
+
} catch (error) {
|
|
3267
|
+
this.logError("processSuccessfulLocalPayment: 临时 BaseSales 销毁失败", {
|
|
3268
|
+
...recoveryContext,
|
|
3269
|
+
duration_ms: Date.now() - startedAt,
|
|
3270
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3271
|
+
error_detail: this.normalizeUnknownError(error)
|
|
3272
|
+
});
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
sanitizeLocalRecoveryOrder(order) {
|
|
3277
|
+
const next = {
|
|
3278
|
+
...order,
|
|
3279
|
+
country_calling_code: String(order.country_calling_code ?? ""),
|
|
3280
|
+
phone: String(order.phone ?? ""),
|
|
3281
|
+
email: String(order.email ?? "")
|
|
3282
|
+
};
|
|
3283
|
+
const externalSaleNumber = next.external_sale_number;
|
|
3284
|
+
if (Number(next.is_draft_order || 0) === 1 && next.order_id !== void 0 && externalSaleNumber !== void 0 && String(next.order_id) === String(externalSaleNumber)) {
|
|
3285
|
+
delete next.order_id;
|
|
3286
|
+
}
|
|
3287
|
+
return next;
|
|
3288
|
+
}
|
|
2529
3289
|
getDeviceTaskPlugin() {
|
|
2530
3290
|
var _a, _b;
|
|
2531
3291
|
return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
|
|
@@ -2938,6 +3698,7 @@ var Server = class {
|
|
|
2938
3698
|
});
|
|
2939
3699
|
}
|
|
2940
3700
|
async handleOrderCheckoutSubmit(params) {
|
|
3701
|
+
var _a;
|
|
2941
3702
|
const { backendPath, data, title } = params;
|
|
2942
3703
|
this.logInfo(`${title}: 开始处理`, {
|
|
2943
3704
|
backendPath,
|
|
@@ -2962,9 +3723,10 @@ var Server = class {
|
|
|
2962
3723
|
});
|
|
2963
3724
|
if ((pendingResult == null ? void 0 : pendingResult.status) === true) {
|
|
2964
3725
|
const pendingOrder = pendingResult.data;
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
checkoutData.
|
|
3726
|
+
const platform = (_a = this.core.context) == null ? void 0 : _a.getPlatform();
|
|
3727
|
+
const isAndroid = platform === "android";
|
|
3728
|
+
if (pendingOrder && this.shouldBuildSmallTicketData(checkoutData) && this.isSalesOrderFullyPaid(pendingOrder) && // TODO 这里先加个兼容,如果是安卓,则需要 type=virtual 才走打印,如果是苹果则无限制
|
|
3729
|
+
(isAndroid ? checkoutData.type === "virtual" : true)) {
|
|
2968
3730
|
await this.dispatchLocalReceiptPrint({
|
|
2969
3731
|
checkoutData,
|
|
2970
3732
|
order: pendingOrder,
|
|
@@ -3046,6 +3808,59 @@ var Server = class {
|
|
|
3046
3808
|
};
|
|
3047
3809
|
}
|
|
3048
3810
|
}
|
|
3811
|
+
async handleOrderDraftSubmit(params) {
|
|
3812
|
+
var _a, _b, _c;
|
|
3813
|
+
const { data, title } = params;
|
|
3814
|
+
this.logInfo(`${title}: 开始处理`, {
|
|
3815
|
+
order_id: data == null ? void 0 : data.order_id,
|
|
3816
|
+
external_sale_number: data == null ? void 0 : data.external_sale_number,
|
|
3817
|
+
order_number: data == null ? void 0 : data.order_number
|
|
3818
|
+
});
|
|
3819
|
+
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
3820
|
+
const createdAt = normalizedData.created_at || normalizedData.create_date || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
3821
|
+
const draftOrder = {
|
|
3822
|
+
...normalizedData,
|
|
3823
|
+
external_sale_number: normalizedData.external_sale_number || `LOCAL_DRAFT_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
|
|
3824
|
+
created_at: createdAt,
|
|
3825
|
+
schedule_date: normalizedData.schedule_date || createdAt,
|
|
3826
|
+
need_sync: 0,
|
|
3827
|
+
is_draft_order: 1
|
|
3828
|
+
};
|
|
3829
|
+
if (!this.order || typeof this.order.upsertLocalDraftOrders !== "function") {
|
|
3830
|
+
this.logError(`${title}: Order 模块不支持本地草稿写入`);
|
|
3831
|
+
return {
|
|
3832
|
+
code: 500,
|
|
3833
|
+
status: false,
|
|
3834
|
+
message: "Order 模块不支持本地草稿写入",
|
|
3835
|
+
data: null
|
|
3836
|
+
};
|
|
3837
|
+
}
|
|
3838
|
+
try {
|
|
3839
|
+
await this.order.upsertLocalDraftOrders([draftOrder]);
|
|
3840
|
+
this.logInfo(`${title}: 草稿订单已写入本地`, {
|
|
3841
|
+
order_id: draftOrder.order_id,
|
|
3842
|
+
external_sale_number: draftOrder.external_sale_number
|
|
3843
|
+
});
|
|
3844
|
+
return {
|
|
3845
|
+
code: 200,
|
|
3846
|
+
status: true,
|
|
3847
|
+
message: "",
|
|
3848
|
+
data: {
|
|
3849
|
+
...draftOrder,
|
|
3850
|
+
amount_gap: (_a = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _a.amount_gap,
|
|
3851
|
+
expect_amount: (_b = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _b.expect_amount,
|
|
3852
|
+
total_amount: (_c = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _c.total_amount,
|
|
3853
|
+
payment_status: draftOrder == null ? void 0 : draftOrder.payment_status
|
|
3854
|
+
}
|
|
3855
|
+
};
|
|
3856
|
+
} catch (error) {
|
|
3857
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3858
|
+
this.logError(`${title}: 写入本地草稿订单失败`, {
|
|
3859
|
+
error: errorMessage
|
|
3860
|
+
});
|
|
3861
|
+
return { code: 500, status: false, message: errorMessage, data: null };
|
|
3862
|
+
}
|
|
3863
|
+
}
|
|
3049
3864
|
async handlePendingSyncCheckoutOrder(params) {
|
|
3050
3865
|
var _a, _b, _c, _d;
|
|
3051
3866
|
const { backendPath, data, title, reason } = params;
|
|
@@ -3121,7 +3936,8 @@ var Server = class {
|
|
|
3121
3936
|
return null;
|
|
3122
3937
|
const pendingOrder = {
|
|
3123
3938
|
...data,
|
|
3124
|
-
need_sync: 1
|
|
3939
|
+
need_sync: 1,
|
|
3940
|
+
is_draft_order: 0
|
|
3125
3941
|
};
|
|
3126
3942
|
const productMap = await this.buildSmallTicketProductMap(pendingOrder);
|
|
3127
3943
|
const orderWithProductTitles = this.withPendingSyncProductTitles(
|
|
@@ -3174,7 +3990,7 @@ var Server = class {
|
|
|
3174
3990
|
return 0;
|
|
3175
3991
|
return payments.reduce((sum, payment) => {
|
|
3176
3992
|
const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
|
|
3177
|
-
if (status
|
|
3993
|
+
if (status !== "paid")
|
|
3178
3994
|
return sum;
|
|
3179
3995
|
return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
|
|
3180
3996
|
}, 0);
|
|
@@ -3231,6 +4047,123 @@ var Server = class {
|
|
|
3231
4047
|
return map;
|
|
3232
4048
|
}, {});
|
|
3233
4049
|
}
|
|
4050
|
+
collectSalesDetailProductIds(order) {
|
|
4051
|
+
const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
|
|
4052
|
+
const productIds = /* @__PURE__ */ new Set();
|
|
4053
|
+
const addProductId = (rawProductId) => {
|
|
4054
|
+
if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
|
|
4055
|
+
return;
|
|
4056
|
+
const productId = Number(rawProductId);
|
|
4057
|
+
if (Number.isFinite(productId))
|
|
4058
|
+
productIds.add(productId);
|
|
4059
|
+
};
|
|
4060
|
+
products.forEach((product) => {
|
|
4061
|
+
addProductId((product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id));
|
|
4062
|
+
if (Array.isArray(product == null ? void 0 : product.product_bundle)) {
|
|
4063
|
+
product.product_bundle.forEach((bundle) => {
|
|
4064
|
+
addProductId((bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id));
|
|
4065
|
+
});
|
|
4066
|
+
}
|
|
4067
|
+
});
|
|
4068
|
+
return Array.from(productIds);
|
|
4069
|
+
}
|
|
4070
|
+
async buildSalesDetailProductSnapshotMap(order) {
|
|
4071
|
+
var _a;
|
|
4072
|
+
const productIds = this.collectSalesDetailProductIds(order);
|
|
4073
|
+
const getSnapshots = (_a = this.products) == null ? void 0 : _a.getProductSnapshotsByIds;
|
|
4074
|
+
if (!productIds.length || typeof getSnapshots !== "function")
|
|
4075
|
+
return {};
|
|
4076
|
+
try {
|
|
4077
|
+
return await getSnapshots.call(this.products, productIds);
|
|
4078
|
+
} catch (error) {
|
|
4079
|
+
this.logWarning("buildSalesDetailProductSnapshotMap: 查询本地商品快照失败", {
|
|
4080
|
+
product_ids: productIds,
|
|
4081
|
+
error: error instanceof Error ? error.message : String(error)
|
|
4082
|
+
});
|
|
4083
|
+
return {};
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
withProductCatalogSnapshots(product, snapshotMap) {
|
|
4087
|
+
if (!product || typeof product !== "object")
|
|
4088
|
+
return product;
|
|
4089
|
+
const rawProductId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
|
|
4090
|
+
if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
|
|
4091
|
+
return product;
|
|
4092
|
+
const productId = Number(rawProductId);
|
|
4093
|
+
if (!Number.isFinite(productId))
|
|
4094
|
+
return product;
|
|
4095
|
+
const snapshot = snapshotMap[String(productId)];
|
|
4096
|
+
if (!snapshot)
|
|
4097
|
+
return product;
|
|
4098
|
+
const shouldFillCover = (product.product_cover === void 0 || product.product_cover === null || product.product_cover === "") && snapshot.cover !== void 0 && snapshot.cover !== null && snapshot.cover !== "";
|
|
4099
|
+
const metadata = product.metadata && typeof product.metadata === "object" ? product.metadata : {};
|
|
4100
|
+
const shouldFillHolderConfig = (metadata.holder_config === void 0 || metadata.holder_config === null) && snapshot.holder_config !== void 0 && snapshot.holder_config !== null;
|
|
4101
|
+
if (!shouldFillCover && !shouldFillHolderConfig)
|
|
4102
|
+
return product;
|
|
4103
|
+
return {
|
|
4104
|
+
...product,
|
|
4105
|
+
...shouldFillCover ? { product_cover: snapshot.cover } : {},
|
|
4106
|
+
...shouldFillHolderConfig ? {
|
|
4107
|
+
metadata: {
|
|
4108
|
+
...metadata,
|
|
4109
|
+
holder_config: snapshot.holder_config
|
|
4110
|
+
}
|
|
4111
|
+
} : {}
|
|
4112
|
+
};
|
|
4113
|
+
}
|
|
4114
|
+
withBundleCatalogSnapshots(product, snapshotMap) {
|
|
4115
|
+
if (!Array.isArray(product == null ? void 0 : product.product_bundle))
|
|
4116
|
+
return product;
|
|
4117
|
+
let hasChanged = false;
|
|
4118
|
+
const productBundle = product.product_bundle.map((bundle) => {
|
|
4119
|
+
if (!bundle || typeof bundle !== "object")
|
|
4120
|
+
return bundle;
|
|
4121
|
+
const rawProductId = (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id);
|
|
4122
|
+
if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
|
|
4123
|
+
return bundle;
|
|
4124
|
+
const productId = Number(rawProductId);
|
|
4125
|
+
if (!Number.isFinite(productId))
|
|
4126
|
+
return bundle;
|
|
4127
|
+
const snapshot = snapshotMap[String(productId)];
|
|
4128
|
+
const shouldFillCover = (bundle.cover === void 0 || bundle.cover === null || bundle.cover === "") && (snapshot == null ? void 0 : snapshot.cover) !== void 0 && snapshot.cover !== null && snapshot.cover !== "";
|
|
4129
|
+
if (!shouldFillCover)
|
|
4130
|
+
return bundle;
|
|
4131
|
+
hasChanged = true;
|
|
4132
|
+
return {
|
|
4133
|
+
...bundle,
|
|
4134
|
+
cover: snapshot.cover
|
|
4135
|
+
};
|
|
4136
|
+
});
|
|
4137
|
+
if (!hasChanged)
|
|
4138
|
+
return product;
|
|
4139
|
+
return {
|
|
4140
|
+
...product,
|
|
4141
|
+
product_bundle: productBundle
|
|
4142
|
+
};
|
|
4143
|
+
}
|
|
4144
|
+
async withSalesDetailProductSnapshots(order) {
|
|
4145
|
+
const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : null;
|
|
4146
|
+
if (!(products == null ? void 0 : products.length))
|
|
4147
|
+
return order;
|
|
4148
|
+
const snapshotMap = await this.buildSalesDetailProductSnapshotMap(order);
|
|
4149
|
+
if (!Object.keys(snapshotMap).length)
|
|
4150
|
+
return order;
|
|
4151
|
+
let hasChanged = false;
|
|
4152
|
+
const enrichedProducts = products.map((product) => {
|
|
4153
|
+
const productWithBundleSnapshots = this.withBundleCatalogSnapshots(product, snapshotMap);
|
|
4154
|
+
const nextProduct = this.withProductCatalogSnapshots(productWithBundleSnapshots, snapshotMap);
|
|
4155
|
+
if (nextProduct !== product)
|
|
4156
|
+
hasChanged = true;
|
|
4157
|
+
return nextProduct;
|
|
4158
|
+
});
|
|
4159
|
+
if (!hasChanged)
|
|
4160
|
+
return order;
|
|
4161
|
+
const enrichedOrder = {
|
|
4162
|
+
...order,
|
|
4163
|
+
products: enrichedProducts
|
|
4164
|
+
};
|
|
4165
|
+
return enrichedOrder;
|
|
4166
|
+
}
|
|
3234
4167
|
withPendingSyncProductTitles(order, productMap) {
|
|
3235
4168
|
const products = Array.isArray(order.products) ? order.products : null;
|
|
3236
4169
|
if (!(products == null ? void 0 : products.length))
|
|
@@ -3624,9 +4557,11 @@ var Server = class {
|
|
|
3624
4557
|
return value === void 0 ? void 0 : String(value);
|
|
3625
4558
|
}
|
|
3626
4559
|
buildCheckoutSyncSuccessPatch(fresh) {
|
|
4560
|
+
const patch = {
|
|
4561
|
+
is_draft_order: 0
|
|
4562
|
+
};
|
|
3627
4563
|
if (!fresh)
|
|
3628
|
-
return
|
|
3629
|
-
const patch = {};
|
|
4564
|
+
return patch;
|
|
3630
4565
|
if (fresh.order_id !== void 0 && fresh.order_id !== null)
|
|
3631
4566
|
patch.order_id = fresh.order_id;
|
|
3632
4567
|
if (fresh.order_number !== void 0 && fresh.order_number !== null) {
|
|
@@ -3907,6 +4842,10 @@ var Server = class {
|
|
|
3907
4842
|
const rawList = this.order.getOrders();
|
|
3908
4843
|
this.logInfo("computeOrderQueryResult: 本地订单数量", { rawCount: rawList.length });
|
|
3909
4844
|
const result = (0, import_filterOrders.filterOrders)(rawList, data);
|
|
4845
|
+
result.list.forEach((order) => {
|
|
4846
|
+
var _a;
|
|
4847
|
+
order.payments = (_a = order.payments) == null ? void 0 : _a.filter((payment) => !(0, import_payment_utils.isPendingOrderPayment)(payment));
|
|
4848
|
+
});
|
|
3910
4849
|
this.logInfo("computeOrderQueryResult: 过滤结果", {
|
|
3911
4850
|
rawCount: rawList.length,
|
|
3912
4851
|
filteredCount: result.count,
|
|
@@ -3992,8 +4931,14 @@ var Server = class {
|
|
|
3992
4931
|
*/
|
|
3993
4932
|
async computeProductQueryResult(context, options) {
|
|
3994
4933
|
const tTotal = performance.now();
|
|
3995
|
-
const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id } = context;
|
|
4934
|
+
const { menu_list_ids, ids, schedule_date, schedule_datetime, customer_id, extension_type, product_id, strategy_context } = context;
|
|
3996
4935
|
const queryIds = Array.isArray(ids) ? ids.map((id) => Number(id)).filter((id) => Number.isFinite(id)) : [];
|
|
4936
|
+
const formatterContext = this.buildProductFormatterContext({
|
|
4937
|
+
schedule_date,
|
|
4938
|
+
schedule_datetime,
|
|
4939
|
+
customer_id,
|
|
4940
|
+
strategy_context
|
|
4941
|
+
});
|
|
3997
4942
|
this.logInfo("computeProductQueryResult 开始", {
|
|
3998
4943
|
menuListIdsCount: (menu_list_ids == null ? void 0 : menu_list_ids.length) ?? 0,
|
|
3999
4944
|
ids: queryIds,
|
|
@@ -4002,20 +4947,17 @@ var Server = class {
|
|
|
4002
4947
|
customer_id,
|
|
4003
4948
|
extension_type,
|
|
4004
4949
|
product_id,
|
|
4950
|
+
strategyContextKeys: strategy_context ? Object.keys(strategy_context) : [],
|
|
4005
4951
|
changedIds: options == null ? void 0 : options.changedIds
|
|
4006
4952
|
});
|
|
4007
4953
|
if (!this.products) {
|
|
4008
4954
|
this.logError("computeProductQueryResult: Products 模块未注册");
|
|
4009
|
-
return { message: "Products 模块未注册", data:
|
|
4955
|
+
return { message: "Products 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
|
|
4010
4956
|
}
|
|
4011
4957
|
if (queryIds.length > 0) {
|
|
4012
4958
|
const uniqueIds = Array.from(new Set(queryIds));
|
|
4013
4959
|
const tPrice2 = performance.now();
|
|
4014
|
-
const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
|
|
4015
|
-
scheduleModule: this.getSchedule(),
|
|
4016
|
-
schedule_datetime,
|
|
4017
|
-
customer_id
|
|
4018
|
-
}, {
|
|
4960
|
+
const productsWithPrice = await this.products.getProductsWithPrice(schedule_date, formatterContext, {
|
|
4019
4961
|
changedIds: options == null ? void 0 : options.changedIds,
|
|
4020
4962
|
productIds: uniqueIds
|
|
4021
4963
|
});
|
|
@@ -4036,7 +4978,7 @@ var Server = class {
|
|
|
4036
4978
|
});
|
|
4037
4979
|
return {
|
|
4038
4980
|
code: 200,
|
|
4039
|
-
data:
|
|
4981
|
+
data: this.buildProductQueryResultPayload(extensionFilteredProducts),
|
|
4040
4982
|
message: "",
|
|
4041
4983
|
status: true
|
|
4042
4984
|
};
|
|
@@ -4044,9 +4986,7 @@ var Server = class {
|
|
|
4044
4986
|
if (product_id != null && Number.isFinite(Number(product_id))) {
|
|
4045
4987
|
const pid = Number(product_id);
|
|
4046
4988
|
const tPrice2 = performance.now();
|
|
4047
|
-
const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, {
|
|
4048
|
-
scheduleModule: this.getSchedule()
|
|
4049
|
-
}, {
|
|
4989
|
+
const allProductsWithPrice = await this.products.getProductsWithPrice(schedule_date, formatterContext, {
|
|
4050
4990
|
changedIds: options == null ? void 0 : options.changedIds
|
|
4051
4991
|
});
|
|
4052
4992
|
(0, import_product.perfMark)("computeQuery.getProductsWithPrice(single)", performance.now() - tPrice2, {
|
|
@@ -4076,11 +5016,7 @@ var Server = class {
|
|
|
4076
5016
|
}
|
|
4077
5017
|
if (this.shouldQueryProductsByExtensionTypes(extension_type)) {
|
|
4078
5018
|
const tPrice2 = performance.now();
|
|
4079
|
-
let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, {
|
|
4080
|
-
scheduleModule: this.getSchedule(),
|
|
4081
|
-
schedule_datetime,
|
|
4082
|
-
customer_id
|
|
4083
|
-
}, {
|
|
5019
|
+
let filteredProducts2 = await this.products.getProductsWithPrice(schedule_date, formatterContext, {
|
|
4084
5020
|
changedIds: options == null ? void 0 : options.changedIds
|
|
4085
5021
|
});
|
|
4086
5022
|
(0, import_product.perfMark)("computeQuery.getProductsWithPrice(extensionType)", performance.now() - tPrice2, {
|
|
@@ -4120,18 +5056,18 @@ var Server = class {
|
|
|
4120
5056
|
});
|
|
4121
5057
|
return {
|
|
4122
5058
|
code: 200,
|
|
4123
|
-
data:
|
|
5059
|
+
data: this.buildProductQueryResultPayload(filteredProducts2),
|
|
4124
5060
|
message: "",
|
|
4125
5061
|
status: true
|
|
4126
5062
|
};
|
|
4127
5063
|
}
|
|
4128
5064
|
if (!this.menu) {
|
|
4129
5065
|
this.logError("computeProductQueryResult: Menu 模块未注册");
|
|
4130
|
-
return { message: "Menu 模块未注册", data:
|
|
5066
|
+
return { message: "Menu 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
|
|
4131
5067
|
}
|
|
4132
5068
|
if (!this.schedule) {
|
|
4133
5069
|
this.logError("computeProductQueryResult: Schedule 模块未注册");
|
|
4134
|
-
return { message: "Schedule 模块未注册", data:
|
|
5070
|
+
return { message: "Schedule 模块未注册", data: this.buildProductQueryResultPayload([], 0) };
|
|
4135
5071
|
}
|
|
4136
5072
|
let activeMenuList = [];
|
|
4137
5073
|
if (menu_list_ids && Array.isArray(menu_list_ids) && menu_list_ids.length > 0) {
|
|
@@ -4155,11 +5091,7 @@ var Server = class {
|
|
|
4155
5091
|
isAllProducts: !!productScope.isAllProducts
|
|
4156
5092
|
});
|
|
4157
5093
|
const tPrice = performance.now();
|
|
4158
|
-
let filteredProducts = scopedProductIds.length > 0 ? await this.products.getProductsWithPrice(schedule_date, {
|
|
4159
|
-
scheduleModule: this.getSchedule(),
|
|
4160
|
-
schedule_datetime,
|
|
4161
|
-
customer_id
|
|
4162
|
-
}, {
|
|
5094
|
+
let filteredProducts = scopedProductIds.length > 0 ? await this.products.getProductsWithPrice(schedule_date, formatterContext, {
|
|
4163
5095
|
changedIds: options == null ? void 0 : options.changedIds,
|
|
4164
5096
|
productIds: productScope.isAllProducts ? void 0 : scopedProductIds
|
|
4165
5097
|
}) : [];
|
|
@@ -4202,11 +5134,29 @@ var Server = class {
|
|
|
4202
5134
|
});
|
|
4203
5135
|
return {
|
|
4204
5136
|
code: 200,
|
|
4205
|
-
data:
|
|
5137
|
+
data: this.buildProductQueryResultPayload(filteredProducts),
|
|
4206
5138
|
message: "",
|
|
4207
5139
|
status: true
|
|
4208
5140
|
};
|
|
4209
5141
|
}
|
|
5142
|
+
/**
|
|
5143
|
+
* 构建商品格式化上下文。
|
|
5144
|
+
*
|
|
5145
|
+
* 智能定价条件使用全量 menuList/scheduleList;Product Query 顶层参数只保留筛选商品集合所需字段。
|
|
5146
|
+
*/
|
|
5147
|
+
buildProductFormatterContext(context) {
|
|
5148
|
+
var _a, _b, _c, _d;
|
|
5149
|
+
const scheduleModule = this.getSchedule();
|
|
5150
|
+
return {
|
|
5151
|
+
scheduleModule,
|
|
5152
|
+
schedule_datetime: context.schedule_datetime,
|
|
5153
|
+
customer_id: context.customer_id,
|
|
5154
|
+
strategy_context: context.strategy_context,
|
|
5155
|
+
menuList: ((_b = (_a = this.menu) == null ? void 0 : _a.getMenuList) == null ? void 0 : _b.call(_a)) || [],
|
|
5156
|
+
scheduleList: ((_c = scheduleModule == null ? void 0 : scheduleModule.getScheduleList) == null ? void 0 : _c.call(scheduleModule)) || [],
|
|
5157
|
+
dataVariantEvaluator: (_d = this.core.context) == null ? void 0 : _d.dataVariantEvaluator
|
|
5158
|
+
};
|
|
5159
|
+
}
|
|
4210
5160
|
/**
|
|
4211
5161
|
* 数据变更后,遍历所有订阅者重新计算查询结果并通过 callback 推送
|
|
4212
5162
|
* 由 ProductsModule 的 onProductsSyncCompleted 事件触发
|