@pisell/pisellos 2.3.28 → 2.3.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/Order/index.d.ts +32 -8
- package/dist/modules/Order/index.js +883 -521
- package/dist/modules/Order/payment-utils.d.ts +23 -0
- package/dist/modules/Order/payment-utils.js +203 -0
- package/dist/modules/Order/types.d.ts +33 -1
- package/dist/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +405 -0
- package/dist/modules/Order/utils.d.ts +2 -1
- package/dist/modules/Order/utils.js +6 -12
- 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/index.d.ts +1 -1
- package/dist/server/index.d.ts +14 -0
- package/dist/server/index.js +1826 -1000
- package/dist/server/modules/order/index.d.ts +47 -4
- package/dist/server/modules/order/index.js +1415 -711
- package/dist/server/modules/order/types.d.ts +11 -3
- package/dist/server/modules/order/types.js +1 -1
- package/dist/solution/BaseSales/index.d.ts +40 -4
- package/dist/solution/BaseSales/index.js +1268 -749
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +9 -4
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +6 -8
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +13 -1
- package/dist/solution/BookingTicket/index.js +2 -1
- package/dist/utils/payment-number.d.ts +9 -0
- package/dist/utils/payment-number.js +69 -0
- package/lib/modules/Order/index.d.ts +32 -8
- package/lib/modules/Order/index.js +270 -64
- package/lib/modules/Order/payment-utils.d.ts +23 -0
- package/lib/modules/Order/payment-utils.js +193 -0
- package/lib/modules/Order/types.d.ts +33 -1
- package/lib/modules/Order/utils/orderCollectionIdentity.d.ts +53 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +415 -0
- package/lib/modules/Order/utils.d.ts +2 -1
- package/lib/modules/Order/utils.js +6 -14
- 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/index.d.ts +1 -1
- package/lib/server/index.d.ts +14 -0
- package/lib/server/index.js +604 -8
- package/lib/server/modules/order/index.d.ts +47 -4
- package/lib/server/modules/order/index.js +578 -116
- package/lib/server/modules/order/types.d.ts +11 -3
- package/lib/solution/BaseSales/index.d.ts +40 -4
- package/lib/solution/BaseSales/index.js +363 -37
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +9 -4
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -5
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +13 -1
- package/lib/solution/BookingTicket/index.js +2 -1
- 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,7 @@ __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"));
|
|
37
38
|
var import_products = require("./modules/products");
|
|
38
39
|
var import_menu = require("./modules/menu");
|
|
39
40
|
var import_quotation = require("./modules/quotation");
|
|
@@ -50,6 +51,7 @@ var import_types3 = require("./modules/order/types");
|
|
|
50
51
|
var import_filterOrders = require("./modules/order/utils/filterOrders");
|
|
51
52
|
var import_filterBookings = require("./modules/order/utils/filterBookings");
|
|
52
53
|
var import_small_ticket = require("./utils/small-ticket");
|
|
54
|
+
var import_BaseSales = require("../solution/BaseSales");
|
|
53
55
|
__reExport(server_exports, require("./modules"), module.exports);
|
|
54
56
|
var PRODUCT_TITLE_SNAPSHOT_KEYS = [
|
|
55
57
|
"en",
|
|
@@ -85,6 +87,7 @@ var Server = class {
|
|
|
85
87
|
this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
|
|
86
88
|
this.salesSearchSubscribers = /* @__PURE__ */ new Map();
|
|
87
89
|
this.deviceTaskActionsRegistered = false;
|
|
90
|
+
this.localPaymentUpdateQueues = /* @__PURE__ */ new Map();
|
|
88
91
|
this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
|
|
89
92
|
// 模块注册表 - 定义所有可用的模块配置
|
|
90
93
|
this.moduleRegistry = {
|
|
@@ -560,6 +563,128 @@ var Server = class {
|
|
|
560
563
|
title: "handleOrderSalesCheckout"
|
|
561
564
|
});
|
|
562
565
|
};
|
|
566
|
+
this.handleOrderSalesDraft = async ({ data }) => {
|
|
567
|
+
return this.handleOrderDraftSubmit({
|
|
568
|
+
data,
|
|
569
|
+
title: "handleOrderSalesDraft"
|
|
570
|
+
});
|
|
571
|
+
};
|
|
572
|
+
this.handleGetLocalPayment = async ({ data }) => {
|
|
573
|
+
const saleId = data == null ? void 0 : data.sale_id;
|
|
574
|
+
const paymentNumber = data == null ? void 0 : data.payment_number;
|
|
575
|
+
const operationId = this.createLocalPaymentOperationId("get");
|
|
576
|
+
const requestContext = {
|
|
577
|
+
operation_id: operationId,
|
|
578
|
+
sale_id: saleId ?? null,
|
|
579
|
+
payment_number: paymentNumber ?? null
|
|
580
|
+
};
|
|
581
|
+
this.logInfo("handleGetLocalPayment: 请求进入", requestContext);
|
|
582
|
+
if (saleId === void 0 || saleId === null || saleId === "" || paymentNumber === void 0 || paymentNumber === null || paymentNumber === "") {
|
|
583
|
+
this.logWarning("handleGetLocalPayment: 参数校验失败", {
|
|
584
|
+
...requestContext,
|
|
585
|
+
missing_fields: [
|
|
586
|
+
...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
|
|
587
|
+
...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : []
|
|
588
|
+
]
|
|
589
|
+
});
|
|
590
|
+
return {
|
|
591
|
+
code: 400,
|
|
592
|
+
status: false,
|
|
593
|
+
message: "sale_id 和 payment_number 必填",
|
|
594
|
+
data: null
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
if (!this.order) {
|
|
598
|
+
this.logError("handleGetLocalPayment: Order 模块未注册", requestContext);
|
|
599
|
+
return { code: 500, status: false, message: "Order 模块未注册", data: null };
|
|
600
|
+
}
|
|
601
|
+
const startedAt = Date.now();
|
|
602
|
+
try {
|
|
603
|
+
this.logInfo("handleGetLocalPayment: 开始查询本地支付项", requestContext);
|
|
604
|
+
const found = await this.order.getLocalPayment({
|
|
605
|
+
saleId,
|
|
606
|
+
paymentNumber,
|
|
607
|
+
operationId
|
|
608
|
+
});
|
|
609
|
+
if (!found) {
|
|
610
|
+
this.logWarning("handleGetLocalPayment: 本地支付项不存在", {
|
|
611
|
+
...requestContext,
|
|
612
|
+
duration_ms: Date.now() - startedAt
|
|
613
|
+
});
|
|
614
|
+
return { code: 404, status: false, message: "本地支付项不存在", data: null };
|
|
615
|
+
}
|
|
616
|
+
this.logInfo("handleGetLocalPayment: 查询命中", {
|
|
617
|
+
...requestContext,
|
|
618
|
+
duration_ms: Date.now() - startedAt,
|
|
619
|
+
matched_by: found.matchedBy,
|
|
620
|
+
payment_index: found.paymentIndex,
|
|
621
|
+
...this.buildLocalPaymentOrderLogContext(found.order),
|
|
622
|
+
payment: found.payment
|
|
623
|
+
});
|
|
624
|
+
return { code: 200, status: true, message: "", data: found.payment };
|
|
625
|
+
} catch (error) {
|
|
626
|
+
this.logError("handleGetLocalPayment: 查询异常", {
|
|
627
|
+
...requestContext,
|
|
628
|
+
duration_ms: Date.now() - startedAt,
|
|
629
|
+
error: error instanceof Error ? error.message : String(error),
|
|
630
|
+
error_detail: this.normalizeUnknownError(error)
|
|
631
|
+
});
|
|
632
|
+
throw error;
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
this.handleUpdateLocalPayment = async ({ data }) => {
|
|
636
|
+
const saleId = data == null ? void 0 : data.sale_id;
|
|
637
|
+
const paymentNumber = data == null ? void 0 : data.payment_number;
|
|
638
|
+
const number = data == null ? void 0 : data.number;
|
|
639
|
+
const status = data == null ? void 0 : data.status;
|
|
640
|
+
const serviceCharge = data == null ? void 0 : data.service_charge;
|
|
641
|
+
const cardReaderSurcharge = data == null ? void 0 : data.card_reader_surcharge;
|
|
642
|
+
const hasSurchargeInput = serviceCharge !== void 0 || cardReaderSurcharge !== void 0;
|
|
643
|
+
const invalidSurchargeFields = this.getInvalidLocalPaymentSurchargeFields(
|
|
644
|
+
serviceCharge,
|
|
645
|
+
cardReaderSurcharge
|
|
646
|
+
);
|
|
647
|
+
const operationId = this.createLocalPaymentOperationId("update");
|
|
648
|
+
const requestContext = {
|
|
649
|
+
operation_id: operationId,
|
|
650
|
+
sale_id: saleId ?? null,
|
|
651
|
+
payment_number: paymentNumber ?? null,
|
|
652
|
+
transaction_number: number ?? null,
|
|
653
|
+
requested_status: status ?? null,
|
|
654
|
+
service_charge: serviceCharge ?? null,
|
|
655
|
+
card_reader_surcharge: cardReaderSurcharge ?? null
|
|
656
|
+
};
|
|
657
|
+
this.logInfo("handleUpdateLocalPayment: 请求进入", requestContext);
|
|
658
|
+
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) {
|
|
659
|
+
this.logWarning("handleUpdateLocalPayment: 参数校验失败", {
|
|
660
|
+
...requestContext,
|
|
661
|
+
missing_or_invalid_fields: [
|
|
662
|
+
...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
|
|
663
|
+
...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : [],
|
|
664
|
+
...number === void 0 || number === null || number === "" ? ["number"] : [],
|
|
665
|
+
...status !== "success" && status !== "fail" ? ["status"] : [],
|
|
666
|
+
...invalidSurchargeFields
|
|
667
|
+
]
|
|
668
|
+
});
|
|
669
|
+
return {
|
|
670
|
+
code: 400,
|
|
671
|
+
status: false,
|
|
672
|
+
message: invalidSurchargeFields.length > 0 ? `手续费参数非法: ${invalidSurchargeFields.join(", ")}` : "sale_id、payment_number、number 必填,status 仅支持 success/fail",
|
|
673
|
+
data: null
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
const queueKey = `${String(saleId)}:${String(paymentNumber)}`;
|
|
677
|
+
return this.runLocalPaymentUpdateInQueue(queueKey, () => this.processLocalPaymentUpdate({
|
|
678
|
+
operationId,
|
|
679
|
+
saleId,
|
|
680
|
+
paymentNumber,
|
|
681
|
+
number: String(number),
|
|
682
|
+
status,
|
|
683
|
+
serviceCharge,
|
|
684
|
+
cardReaderSurcharge,
|
|
685
|
+
hasSurchargeInput
|
|
686
|
+
}), requestContext);
|
|
687
|
+
};
|
|
563
688
|
this.handleOrderCheckout = async ({ data }) => {
|
|
564
689
|
return this.handleOrderCheckoutSubmit({
|
|
565
690
|
backendPath: "/order/checkout",
|
|
@@ -1424,13 +1549,15 @@ var Server = class {
|
|
|
1424
1549
|
...checkoutData,
|
|
1425
1550
|
...fresh,
|
|
1426
1551
|
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1427
|
-
need_sync: 0
|
|
1552
|
+
need_sync: 0,
|
|
1553
|
+
is_draft_order: 0
|
|
1428
1554
|
} : {
|
|
1429
1555
|
...fresh,
|
|
1430
1556
|
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1431
|
-
need_sync: 0
|
|
1557
|
+
need_sync: 0,
|
|
1558
|
+
is_draft_order: 0
|
|
1432
1559
|
};
|
|
1433
|
-
await this.order.upsertOrdersFromRemote([syncedOrder]);
|
|
1560
|
+
await this.order.upsertOrdersFromRemote([syncedOrder], "checkoutSync");
|
|
1434
1561
|
this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
|
|
1435
1562
|
order_id: fresh.order_id,
|
|
1436
1563
|
external_sale_number: syncedOrder.external_sale_number,
|
|
@@ -1448,7 +1575,8 @@ var Server = class {
|
|
|
1448
1575
|
...checkoutData,
|
|
1449
1576
|
...patch,
|
|
1450
1577
|
external_sale_number: externalSaleNumber,
|
|
1451
|
-
need_sync: 0
|
|
1578
|
+
need_sync: 0,
|
|
1579
|
+
is_draft_order: 0
|
|
1452
1580
|
};
|
|
1453
1581
|
this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
|
|
1454
1582
|
order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
|
|
@@ -1828,6 +1956,11 @@ var Server = class {
|
|
|
1828
1956
|
path: "/shop/order/sales/checkout",
|
|
1829
1957
|
handler: this.handleOrderSalesCheckout.bind(this)
|
|
1830
1958
|
},
|
|
1959
|
+
{
|
|
1960
|
+
method: "post",
|
|
1961
|
+
path: "/shop/order/sales/draft",
|
|
1962
|
+
handler: this.handleOrderSalesDraft.bind(this)
|
|
1963
|
+
},
|
|
1831
1964
|
{
|
|
1832
1965
|
method: "post",
|
|
1833
1966
|
path: "/order/checkout",
|
|
@@ -1838,6 +1971,16 @@ var Server = class {
|
|
|
1838
1971
|
path: "/shop/local/print-order",
|
|
1839
1972
|
handler: this.handleLocalPrintOrder.bind(this)
|
|
1840
1973
|
},
|
|
1974
|
+
{
|
|
1975
|
+
method: "post",
|
|
1976
|
+
path: "/shop/local/getLocalPayment",
|
|
1977
|
+
handler: this.handleGetLocalPayment.bind(this)
|
|
1978
|
+
},
|
|
1979
|
+
{
|
|
1980
|
+
method: "post",
|
|
1981
|
+
path: "/shop/local/updateLocalPayment",
|
|
1982
|
+
handler: this.handleUpdateLocalPayment.bind(this)
|
|
1983
|
+
},
|
|
1841
1984
|
{
|
|
1842
1985
|
method: "post",
|
|
1843
1986
|
path: "/shop/machinecode/batch",
|
|
@@ -2528,6 +2671,403 @@ var Server = class {
|
|
|
2528
2671
|
};
|
|
2529
2672
|
}
|
|
2530
2673
|
}
|
|
2674
|
+
createLocalPaymentOperationId(action) {
|
|
2675
|
+
return `local_payment_${action}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2676
|
+
}
|
|
2677
|
+
buildLocalPaymentOrderLogContext(order) {
|
|
2678
|
+
if (!order)
|
|
2679
|
+
return {};
|
|
2680
|
+
return {
|
|
2681
|
+
order_id: order.order_id ?? null,
|
|
2682
|
+
external_sale_number: order.external_sale_number ?? null,
|
|
2683
|
+
order_number: order.order_number ?? null,
|
|
2684
|
+
shop_order_number: order.shop_order_number ?? null,
|
|
2685
|
+
shop_full_order_number: order.shop_full_order_number ?? null,
|
|
2686
|
+
order_status: order.status ?? null,
|
|
2687
|
+
payment_status: order.payment_status ?? null,
|
|
2688
|
+
is_draft_order: Number(order.is_draft_order || 0),
|
|
2689
|
+
need_sync: Number(order.need_sync || 0),
|
|
2690
|
+
platform: order.platform ?? null,
|
|
2691
|
+
business_code: order.business_code ?? null,
|
|
2692
|
+
order_sales_channel: order.order_sales_channel ?? null,
|
|
2693
|
+
sales_channel: order.sales_channel ?? null,
|
|
2694
|
+
order_type: order.type ?? null,
|
|
2695
|
+
payments_count: Array.isArray(order.payments) ? order.payments.length : 0
|
|
2696
|
+
};
|
|
2697
|
+
}
|
|
2698
|
+
isValidLocalPaymentDecimal(value) {
|
|
2699
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
2700
|
+
return false;
|
|
2701
|
+
if (typeof value === "string" && value.trim() === "")
|
|
2702
|
+
return false;
|
|
2703
|
+
try {
|
|
2704
|
+
return new import_decimal.default(value).isFinite();
|
|
2705
|
+
} catch {
|
|
2706
|
+
return false;
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
getInvalidLocalPaymentSurchargeFields(serviceCharge, cardReaderSurcharge) {
|
|
2710
|
+
const invalidFields = [];
|
|
2711
|
+
if (serviceCharge !== void 0) {
|
|
2712
|
+
if (serviceCharge === null || typeof serviceCharge !== "object" || Array.isArray(serviceCharge)) {
|
|
2713
|
+
invalidFields.push("service_charge");
|
|
2714
|
+
} else {
|
|
2715
|
+
const input = serviceCharge;
|
|
2716
|
+
if (input.fixed !== void 0 && !this.isValidLocalPaymentDecimal(input.fixed)) {
|
|
2717
|
+
invalidFields.push("service_charge.fixed");
|
|
2718
|
+
}
|
|
2719
|
+
if (input.percentage !== void 0 && !this.isValidLocalPaymentDecimal(input.percentage)) {
|
|
2720
|
+
invalidFields.push("service_charge.percentage");
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
if (cardReaderSurcharge !== void 0 && !this.isValidLocalPaymentDecimal(cardReaderSurcharge)) {
|
|
2725
|
+
invalidFields.push("card_reader_surcharge");
|
|
2726
|
+
}
|
|
2727
|
+
return invalidFields;
|
|
2728
|
+
}
|
|
2729
|
+
buildLocalPaymentSurchargeUpdate(params) {
|
|
2730
|
+
var _a, _b, _c;
|
|
2731
|
+
const amount = new import_decimal.default(((_a = params.serviceCharge) == null ? void 0 : _a.fixed) || 0).plus(params.cardReaderSurcharge || 0).toFixed(2);
|
|
2732
|
+
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);
|
|
2733
|
+
return {
|
|
2734
|
+
service_charge: {
|
|
2735
|
+
amount,
|
|
2736
|
+
...((_c = params.serviceCharge) == null ? void 0 : _c.percentage) !== void 0 ? { percentage: params.serviceCharge.percentage } : {}
|
|
2737
|
+
},
|
|
2738
|
+
service_fee: serviceFee
|
|
2739
|
+
};
|
|
2740
|
+
}
|
|
2741
|
+
async runLocalPaymentUpdateInQueue(key, task, context) {
|
|
2742
|
+
var _a;
|
|
2743
|
+
const queuedAt = Date.now();
|
|
2744
|
+
const hasPreviousTask = this.localPaymentUpdateQueues.has(key);
|
|
2745
|
+
const previous = this.localPaymentUpdateQueues.get(key) || Promise.resolve();
|
|
2746
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列入队", {
|
|
2747
|
+
...context,
|
|
2748
|
+
queue_key: key,
|
|
2749
|
+
waiting_for_previous: hasPreviousTask,
|
|
2750
|
+
active_queue_count: this.localPaymentUpdateQueues.size
|
|
2751
|
+
});
|
|
2752
|
+
const current = previous.catch(() => void 0).then(async () => {
|
|
2753
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列开始执行", {
|
|
2754
|
+
...context,
|
|
2755
|
+
queue_key: key,
|
|
2756
|
+
queue_wait_ms: Date.now() - queuedAt
|
|
2757
|
+
});
|
|
2758
|
+
return task();
|
|
2759
|
+
});
|
|
2760
|
+
const tail = current.then(() => void 0, () => void 0);
|
|
2761
|
+
this.localPaymentUpdateQueues.set(key, tail);
|
|
2762
|
+
try {
|
|
2763
|
+
const result = await current;
|
|
2764
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列执行完成", {
|
|
2765
|
+
...context,
|
|
2766
|
+
queue_key: key,
|
|
2767
|
+
total_duration_ms: Date.now() - queuedAt,
|
|
2768
|
+
result_code: result == null ? void 0 : result.code,
|
|
2769
|
+
result_status: result == null ? void 0 : result.status,
|
|
2770
|
+
payment: (_a = result == null ? void 0 : result.data) == null ? void 0 : _a.payment
|
|
2771
|
+
});
|
|
2772
|
+
return result;
|
|
2773
|
+
} catch (error) {
|
|
2774
|
+
this.logError("handleUpdateLocalPayment: 串行队列执行失败", {
|
|
2775
|
+
...context,
|
|
2776
|
+
queue_key: key,
|
|
2777
|
+
total_duration_ms: Date.now() - queuedAt,
|
|
2778
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2779
|
+
error_detail: this.normalizeUnknownError(error)
|
|
2780
|
+
});
|
|
2781
|
+
throw error;
|
|
2782
|
+
} finally {
|
|
2783
|
+
let released = false;
|
|
2784
|
+
if (this.localPaymentUpdateQueues.get(key) === tail) {
|
|
2785
|
+
this.localPaymentUpdateQueues.delete(key);
|
|
2786
|
+
released = true;
|
|
2787
|
+
}
|
|
2788
|
+
this.logInfo("handleUpdateLocalPayment: 串行队列释放", {
|
|
2789
|
+
...context,
|
|
2790
|
+
queue_key: key,
|
|
2791
|
+
released,
|
|
2792
|
+
active_queue_count: this.localPaymentUpdateQueues.size
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
async processLocalPaymentUpdate(params) {
|
|
2797
|
+
var _a, _b, _c;
|
|
2798
|
+
const requestContext = {
|
|
2799
|
+
operation_id: params.operationId,
|
|
2800
|
+
sale_id: params.saleId,
|
|
2801
|
+
payment_number: params.paymentNumber,
|
|
2802
|
+
transaction_number: params.number,
|
|
2803
|
+
requested_status: params.status,
|
|
2804
|
+
service_charge: params.serviceCharge ?? null,
|
|
2805
|
+
card_reader_surcharge: params.cardReaderSurcharge ?? null
|
|
2806
|
+
};
|
|
2807
|
+
this.logInfo("processLocalPaymentUpdate: 开始处理", requestContext);
|
|
2808
|
+
if (!this.order) {
|
|
2809
|
+
this.logError("processLocalPaymentUpdate: Order 模块未注册", requestContext);
|
|
2810
|
+
return { code: 500, status: false, message: "Order 模块未注册", data: null };
|
|
2811
|
+
}
|
|
2812
|
+
this.logInfo("processLocalPaymentUpdate: 开始查询本地支付项", requestContext);
|
|
2813
|
+
const found = await this.order.getLocalPayment({
|
|
2814
|
+
saleId: params.saleId,
|
|
2815
|
+
paymentNumber: params.paymentNumber,
|
|
2816
|
+
operationId: params.operationId
|
|
2817
|
+
});
|
|
2818
|
+
if (!found) {
|
|
2819
|
+
this.logWarning("processLocalPaymentUpdate: 本地支付项不存在", requestContext);
|
|
2820
|
+
return { code: 404, status: false, message: "本地支付项不存在", data: null };
|
|
2821
|
+
}
|
|
2822
|
+
const surchargeUpdate = params.status === "success" && params.hasSurchargeInput ? this.buildLocalPaymentSurchargeUpdate({
|
|
2823
|
+
paymentAmount: (_a = found.payment) == null ? void 0 : _a.amount,
|
|
2824
|
+
serviceCharge: params.serviceCharge,
|
|
2825
|
+
cardReaderSurcharge: params.cardReaderSurcharge
|
|
2826
|
+
}) : void 0;
|
|
2827
|
+
const incomingPaymentUpdate = params.status === "success" ? {
|
|
2828
|
+
status: "paid",
|
|
2829
|
+
...surchargeUpdate || {},
|
|
2830
|
+
metadata: {
|
|
2831
|
+
unique_payment_number: params.number,
|
|
2832
|
+
transactions: [{ number: params.number, status: "success" }]
|
|
2833
|
+
}
|
|
2834
|
+
} : {
|
|
2835
|
+
metadata: {
|
|
2836
|
+
transactions: [{ number: params.number, status: "fail" }]
|
|
2837
|
+
}
|
|
2838
|
+
};
|
|
2839
|
+
const transactions = Array.isArray((_c = (_b = found.payment) == null ? void 0 : _b.metadata) == null ? void 0 : _c.transactions) ? found.payment.metadata.transactions : [];
|
|
2840
|
+
const existingTransaction = transactions.find((item) => String((item == null ? void 0 : item.number) || "") === params.number);
|
|
2841
|
+
const hasRecordedSuccess = transactions.some((item) => (item == null ? void 0 : item.status) === "success");
|
|
2842
|
+
const orderIsDraft = Number(found.order.is_draft_order || 0) === 1;
|
|
2843
|
+
const foundContext = {
|
|
2844
|
+
...requestContext,
|
|
2845
|
+
matched_by: found.matchedBy,
|
|
2846
|
+
payment_index: found.paymentIndex,
|
|
2847
|
+
...this.buildLocalPaymentOrderLogContext(found.order),
|
|
2848
|
+
payment: found.payment,
|
|
2849
|
+
incoming_payment_update: incomingPaymentUpdate,
|
|
2850
|
+
existing_transaction: existingTransaction || null,
|
|
2851
|
+
has_recorded_success: hasRecordedSuccess
|
|
2852
|
+
};
|
|
2853
|
+
this.logInfo("processLocalPaymentUpdate: 查询命中", foundContext);
|
|
2854
|
+
if (params.status === "fail" && (found.payment.status === "paid" || hasRecordedSuccess)) {
|
|
2855
|
+
this.logInfo("processLocalPaymentUpdate: 幂等返回", {
|
|
2856
|
+
...foundContext,
|
|
2857
|
+
idempotent_reason: "ignore_failure_after_success"
|
|
2858
|
+
});
|
|
2859
|
+
return {
|
|
2860
|
+
code: 200,
|
|
2861
|
+
status: true,
|
|
2862
|
+
message: "",
|
|
2863
|
+
data: { payment: found.payment, order: found.order, idempotent: true }
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
const alreadyRecordedFailure = params.status === "fail" && (existingTransaction == null ? void 0 : existingTransaction.status) === "fail";
|
|
2867
|
+
if (alreadyRecordedFailure) {
|
|
2868
|
+
this.logInfo("processLocalPaymentUpdate: 幂等返回", {
|
|
2869
|
+
...foundContext,
|
|
2870
|
+
idempotent_reason: "failure_already_recorded"
|
|
2871
|
+
});
|
|
2872
|
+
return {
|
|
2873
|
+
code: 200,
|
|
2874
|
+
status: true,
|
|
2875
|
+
message: "",
|
|
2876
|
+
data: { payment: found.payment, order: found.order, idempotent: true }
|
|
2877
|
+
};
|
|
2878
|
+
}
|
|
2879
|
+
if (params.status === "success" && (existingTransaction == null ? void 0 : existingTransaction.status) === "success" && found.payment.status === "paid" && !orderIsDraft) {
|
|
2880
|
+
this.logInfo("processLocalPaymentUpdate: 幂等返回", {
|
|
2881
|
+
...foundContext,
|
|
2882
|
+
idempotent_reason: "success_already_committed"
|
|
2883
|
+
});
|
|
2884
|
+
return {
|
|
2885
|
+
code: 200,
|
|
2886
|
+
status: true,
|
|
2887
|
+
message: "",
|
|
2888
|
+
data: { payment: found.payment, order: found.order, idempotent: true }
|
|
2889
|
+
};
|
|
2890
|
+
}
|
|
2891
|
+
if (params.status === "success") {
|
|
2892
|
+
this.logInfo("processLocalPaymentUpdate: 进入 success 恢复分支", {
|
|
2893
|
+
...foundContext,
|
|
2894
|
+
force_submit_if_paid: found.payment.status === "paid" && orderIsDraft
|
|
2895
|
+
});
|
|
2896
|
+
return this.processSuccessfulLocalPayment({
|
|
2897
|
+
...params,
|
|
2898
|
+
order: found.order,
|
|
2899
|
+
payment: found.payment,
|
|
2900
|
+
matchBy: found.matchedBy === "payment_number" ? "payment_number" : "compat",
|
|
2901
|
+
forceSubmitIfPaid: found.payment.status === "paid" && orderIsDraft,
|
|
2902
|
+
paymentUpdate: incomingPaymentUpdate
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
this.logInfo("processLocalPaymentUpdate: 进入 fail 本地更新分支", {
|
|
2906
|
+
...foundContext,
|
|
2907
|
+
incoming_payment_update: incomingPaymentUpdate
|
|
2908
|
+
});
|
|
2909
|
+
let updated;
|
|
2910
|
+
try {
|
|
2911
|
+
updated = await this.order.updateLocalPayment({
|
|
2912
|
+
saleId: params.saleId,
|
|
2913
|
+
paymentNumber: params.paymentNumber,
|
|
2914
|
+
operationId: params.operationId,
|
|
2915
|
+
updates: incomingPaymentUpdate
|
|
2916
|
+
});
|
|
2917
|
+
} catch (error) {
|
|
2918
|
+
this.logError("processLocalPaymentUpdate: fail 本地更新失败", {
|
|
2919
|
+
...foundContext,
|
|
2920
|
+
incoming_payment_update: incomingPaymentUpdate,
|
|
2921
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2922
|
+
error_detail: this.normalizeUnknownError(error)
|
|
2923
|
+
});
|
|
2924
|
+
throw error;
|
|
2925
|
+
}
|
|
2926
|
+
if (!updated) {
|
|
2927
|
+
this.logWarning("processLocalPaymentUpdate: fail 本地更新未命中", foundContext);
|
|
2928
|
+
return { code: 404, status: false, message: "本地支付项不存在", data: null };
|
|
2929
|
+
}
|
|
2930
|
+
this.logInfo("processLocalPaymentUpdate: fail 本地更新完成", {
|
|
2931
|
+
...requestContext,
|
|
2932
|
+
...this.buildLocalPaymentOrderLogContext(updated.order),
|
|
2933
|
+
previous_payment: updated.previousPayment,
|
|
2934
|
+
payment: updated.payment
|
|
2935
|
+
});
|
|
2936
|
+
return {
|
|
2937
|
+
code: 200,
|
|
2938
|
+
status: true,
|
|
2939
|
+
message: "",
|
|
2940
|
+
data: {
|
|
2941
|
+
local_only: true,
|
|
2942
|
+
payment: updated.payment,
|
|
2943
|
+
order: updated.order
|
|
2944
|
+
}
|
|
2945
|
+
};
|
|
2946
|
+
}
|
|
2947
|
+
async processSuccessfulLocalPayment(params) {
|
|
2948
|
+
var _a, _b, _c, _d, _e;
|
|
2949
|
+
const moduleName = `local_payment_recovery_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2950
|
+
const baseSales = new import_BaseSales.BaseSalesImpl(moduleName);
|
|
2951
|
+
const startedAt = Date.now();
|
|
2952
|
+
const recoveryContext = {
|
|
2953
|
+
operation_id: params.operationId,
|
|
2954
|
+
sale_id: params.saleId,
|
|
2955
|
+
payment_number: params.paymentNumber,
|
|
2956
|
+
transaction_number: params.number,
|
|
2957
|
+
requested_status: "success",
|
|
2958
|
+
match_by: params.matchBy,
|
|
2959
|
+
force_submit_if_paid: params.forceSubmitIfPaid,
|
|
2960
|
+
incoming_payment_update: params.paymentUpdate,
|
|
2961
|
+
base_sales_module_name: moduleName,
|
|
2962
|
+
...this.buildLocalPaymentOrderLogContext(params.order),
|
|
2963
|
+
payment: params.payment
|
|
2964
|
+
};
|
|
2965
|
+
this.logInfo("processSuccessfulLocalPayment: 创建临时 BaseSales", recoveryContext);
|
|
2966
|
+
try {
|
|
2967
|
+
const order = this.sanitizeLocalRecoveryOrder(params.order);
|
|
2968
|
+
this.logInfo("processSuccessfulLocalPayment: 本地订单清洗完成", {
|
|
2969
|
+
...recoveryContext,
|
|
2970
|
+
sanitized_order_id: order.order_id ?? null,
|
|
2971
|
+
removed_synthetic_order_id: params.order.order_id != null && order.order_id == null
|
|
2972
|
+
});
|
|
2973
|
+
await baseSales.initialize(this.core, {
|
|
2974
|
+
otherParams: {
|
|
2975
|
+
platform: order.platform,
|
|
2976
|
+
businessCode: order.business_code,
|
|
2977
|
+
business_code: order.business_code,
|
|
2978
|
+
channel: order.order_sales_channel || order.sales_channel,
|
|
2979
|
+
type: order.type,
|
|
2980
|
+
enableTempOrderPersist: false
|
|
2981
|
+
}
|
|
2982
|
+
});
|
|
2983
|
+
this.logInfo("processSuccessfulLocalPayment: BaseSales 初始化完成", recoveryContext);
|
|
2984
|
+
await baseSales.loadSalesDetail({
|
|
2985
|
+
externalSaleNumber: String(params.saleId),
|
|
2986
|
+
preloadedSalesDetail: order
|
|
2987
|
+
});
|
|
2988
|
+
this.logInfo("processSuccessfulLocalPayment: 本地订单 hydrate 完成", recoveryContext);
|
|
2989
|
+
this.logInfo("processSuccessfulLocalPayment: 开始更新支付项并提交", {
|
|
2990
|
+
...recoveryContext,
|
|
2991
|
+
incoming_payment_update: params.paymentUpdate
|
|
2992
|
+
});
|
|
2993
|
+
const result = await baseSales.updateOrderPayment(
|
|
2994
|
+
params.paymentNumber,
|
|
2995
|
+
params.paymentUpdate,
|
|
2996
|
+
{
|
|
2997
|
+
submitWhenPaid: true,
|
|
2998
|
+
matchBy: params.matchBy,
|
|
2999
|
+
forceSubmitIfPaid: params.forceSubmitIfPaid,
|
|
3000
|
+
applyUpdatesWhenPaid: params.forceSubmitIfPaid,
|
|
3001
|
+
smallTicketDataFlag: 1
|
|
3002
|
+
}
|
|
3003
|
+
);
|
|
3004
|
+
this.logInfo("processSuccessfulLocalPayment: 支付恢复完成", {
|
|
3005
|
+
...recoveryContext,
|
|
3006
|
+
duration_ms: Date.now() - startedAt,
|
|
3007
|
+
payment: result.payment,
|
|
3008
|
+
payments_count: ((_a = result.payments) == null ? void 0 : _a.length) || 0,
|
|
3009
|
+
summary: result.summary,
|
|
3010
|
+
sync_result: result.syncResult ? {
|
|
3011
|
+
is_fully_paid: result.syncResult.isFullyPaid,
|
|
3012
|
+
is_order_fully_paid: result.syncResult.isOrderFullyPaid,
|
|
3013
|
+
is_deposit_fully_paid: result.syncResult.isDepositFullyPaid,
|
|
3014
|
+
payment_stage: result.syncResult.paymentStage,
|
|
3015
|
+
deposit_amount: result.syncResult.depositAmount,
|
|
3016
|
+
order_expected_amount: result.syncResult.orderExpectedAmount,
|
|
3017
|
+
submit_result_code: (_b = result.syncResult.submitResult) == null ? void 0 : _b.code,
|
|
3018
|
+
submit_result_status: (_c = result.syncResult.submitResult) == null ? void 0 : _c.status
|
|
3019
|
+
} : null,
|
|
3020
|
+
draft_result: result.draftResult ? {
|
|
3021
|
+
code: (_d = result.draftResult) == null ? void 0 : _d.code,
|
|
3022
|
+
status: (_e = result.draftResult) == null ? void 0 : _e.status
|
|
3023
|
+
} : null,
|
|
3024
|
+
draft_error: result.draftError instanceof Error ? result.draftError.message : result.draftError
|
|
3025
|
+
});
|
|
3026
|
+
return {
|
|
3027
|
+
code: 200,
|
|
3028
|
+
status: true,
|
|
3029
|
+
message: "",
|
|
3030
|
+
data: {
|
|
3031
|
+
payment: result.payment,
|
|
3032
|
+
payments: result.payments,
|
|
3033
|
+
summary: result.summary,
|
|
3034
|
+
sync_result: result.syncResult
|
|
3035
|
+
}
|
|
3036
|
+
};
|
|
3037
|
+
} catch (error) {
|
|
3038
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3039
|
+
this.logError("processSuccessfulLocalPayment: 支付恢复失败", {
|
|
3040
|
+
...recoveryContext,
|
|
3041
|
+
duration_ms: Date.now() - startedAt,
|
|
3042
|
+
error: message,
|
|
3043
|
+
error_detail: this.normalizeUnknownError(error)
|
|
3044
|
+
});
|
|
3045
|
+
return { code: 500, status: false, message, data: null };
|
|
3046
|
+
} finally {
|
|
3047
|
+
try {
|
|
3048
|
+
await baseSales.destroy();
|
|
3049
|
+
this.logInfo("processSuccessfulLocalPayment: 临时 BaseSales 销毁完成", {
|
|
3050
|
+
...recoveryContext,
|
|
3051
|
+
duration_ms: Date.now() - startedAt
|
|
3052
|
+
});
|
|
3053
|
+
} catch (error) {
|
|
3054
|
+
this.logError("processSuccessfulLocalPayment: 临时 BaseSales 销毁失败", {
|
|
3055
|
+
...recoveryContext,
|
|
3056
|
+
duration_ms: Date.now() - startedAt,
|
|
3057
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3058
|
+
error_detail: this.normalizeUnknownError(error)
|
|
3059
|
+
});
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
sanitizeLocalRecoveryOrder(order) {
|
|
3064
|
+
const next = { ...order };
|
|
3065
|
+
const externalSaleNumber = next.external_sale_number;
|
|
3066
|
+
if (Number(next.is_draft_order || 0) === 1 && next.order_id !== void 0 && externalSaleNumber !== void 0 && String(next.order_id) === String(externalSaleNumber)) {
|
|
3067
|
+
delete next.order_id;
|
|
3068
|
+
}
|
|
3069
|
+
return next;
|
|
3070
|
+
}
|
|
2531
3071
|
getDeviceTaskPlugin() {
|
|
2532
3072
|
var _a, _b;
|
|
2533
3073
|
return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
|
|
@@ -3048,6 +3588,59 @@ var Server = class {
|
|
|
3048
3588
|
};
|
|
3049
3589
|
}
|
|
3050
3590
|
}
|
|
3591
|
+
async handleOrderDraftSubmit(params) {
|
|
3592
|
+
var _a, _b, _c;
|
|
3593
|
+
const { data, title } = params;
|
|
3594
|
+
this.logInfo(`${title}: 开始处理`, {
|
|
3595
|
+
order_id: data == null ? void 0 : data.order_id,
|
|
3596
|
+
external_sale_number: data == null ? void 0 : data.external_sale_number,
|
|
3597
|
+
order_number: data == null ? void 0 : data.order_number
|
|
3598
|
+
});
|
|
3599
|
+
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
3600
|
+
const createdAt = normalizedData.created_at || normalizedData.create_date || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
3601
|
+
const draftOrder = {
|
|
3602
|
+
...normalizedData,
|
|
3603
|
+
external_sale_number: normalizedData.external_sale_number || `LOCAL_DRAFT_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
|
|
3604
|
+
created_at: createdAt,
|
|
3605
|
+
schedule_date: normalizedData.schedule_date || createdAt,
|
|
3606
|
+
need_sync: 0,
|
|
3607
|
+
is_draft_order: 1
|
|
3608
|
+
};
|
|
3609
|
+
if (!this.order || typeof this.order.upsertLocalDraftOrders !== "function") {
|
|
3610
|
+
this.logError(`${title}: Order 模块不支持本地草稿写入`);
|
|
3611
|
+
return {
|
|
3612
|
+
code: 500,
|
|
3613
|
+
status: false,
|
|
3614
|
+
message: "Order 模块不支持本地草稿写入",
|
|
3615
|
+
data: null
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3618
|
+
try {
|
|
3619
|
+
await this.order.upsertLocalDraftOrders([draftOrder]);
|
|
3620
|
+
this.logInfo(`${title}: 草稿订单已写入本地`, {
|
|
3621
|
+
order_id: draftOrder.order_id,
|
|
3622
|
+
external_sale_number: draftOrder.external_sale_number
|
|
3623
|
+
});
|
|
3624
|
+
return {
|
|
3625
|
+
code: 200,
|
|
3626
|
+
status: true,
|
|
3627
|
+
message: "",
|
|
3628
|
+
data: {
|
|
3629
|
+
...draftOrder,
|
|
3630
|
+
amount_gap: (_a = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _a.amount_gap,
|
|
3631
|
+
expect_amount: (_b = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _b.expect_amount,
|
|
3632
|
+
total_amount: (_c = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _c.total_amount,
|
|
3633
|
+
payment_status: draftOrder == null ? void 0 : draftOrder.payment_status
|
|
3634
|
+
}
|
|
3635
|
+
};
|
|
3636
|
+
} catch (error) {
|
|
3637
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3638
|
+
this.logError(`${title}: 写入本地草稿订单失败`, {
|
|
3639
|
+
error: errorMessage
|
|
3640
|
+
});
|
|
3641
|
+
return { code: 500, status: false, message: errorMessage, data: null };
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3051
3644
|
async handlePendingSyncCheckoutOrder(params) {
|
|
3052
3645
|
var _a, _b, _c, _d;
|
|
3053
3646
|
const { backendPath, data, title, reason } = params;
|
|
@@ -3123,7 +3716,8 @@ var Server = class {
|
|
|
3123
3716
|
return null;
|
|
3124
3717
|
const pendingOrder = {
|
|
3125
3718
|
...data,
|
|
3126
|
-
need_sync: 1
|
|
3719
|
+
need_sync: 1,
|
|
3720
|
+
is_draft_order: 0
|
|
3127
3721
|
};
|
|
3128
3722
|
const productMap = await this.buildSmallTicketProductMap(pendingOrder);
|
|
3129
3723
|
const orderWithProductTitles = this.withPendingSyncProductTitles(
|
|
@@ -3176,7 +3770,7 @@ var Server = class {
|
|
|
3176
3770
|
return 0;
|
|
3177
3771
|
return payments.reduce((sum, payment) => {
|
|
3178
3772
|
const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
|
|
3179
|
-
if (status
|
|
3773
|
+
if (status !== "paid")
|
|
3180
3774
|
return sum;
|
|
3181
3775
|
return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
|
|
3182
3776
|
}, 0);
|
|
@@ -3743,9 +4337,11 @@ var Server = class {
|
|
|
3743
4337
|
return value === void 0 ? void 0 : String(value);
|
|
3744
4338
|
}
|
|
3745
4339
|
buildCheckoutSyncSuccessPatch(fresh) {
|
|
4340
|
+
const patch = {
|
|
4341
|
+
is_draft_order: 0
|
|
4342
|
+
};
|
|
3746
4343
|
if (!fresh)
|
|
3747
|
-
return
|
|
3748
|
-
const patch = {};
|
|
4344
|
+
return patch;
|
|
3749
4345
|
if (fresh.order_id !== void 0 && fresh.order_id !== null)
|
|
3750
4346
|
patch.order_id = fresh.order_id;
|
|
3751
4347
|
if (fresh.order_number !== void 0 && fresh.order_number !== null) {
|