@pisell/pisellos 2.3.29 → 2.3.31

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.
Files changed (48) hide show
  1. package/dist/modules/Order/index.d.ts +27 -8
  2. package/dist/modules/Order/index.js +736 -473
  3. package/dist/modules/Order/payment-utils.d.ts +23 -0
  4. package/dist/modules/Order/payment-utils.js +203 -0
  5. package/dist/modules/Order/types.d.ts +33 -1
  6. package/dist/modules/Order/utils.js +4 -4
  7. package/dist/modules/Payment/index.d.ts +2 -0
  8. package/dist/modules/Payment/index.js +78 -49
  9. package/dist/modules/Payment/types.d.ts +26 -24
  10. package/dist/modules/Payment/types.js +2 -0
  11. package/dist/server/index.d.ts +14 -0
  12. package/dist/server/index.js +1850 -1024
  13. package/dist/server/modules/order/index.d.ts +40 -3
  14. package/dist/server/modules/order/index.js +1200 -501
  15. package/dist/server/modules/order/types.d.ts +11 -3
  16. package/dist/server/modules/order/types.js +1 -1
  17. package/dist/solution/BaseSales/index.d.ts +33 -3
  18. package/dist/solution/BaseSales/index.js +609 -322
  19. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  20. package/dist/solution/BookingByStep/index.d.ts +1 -1
  21. package/dist/solution/BookingTicket/index.d.ts +1 -1
  22. package/dist/solution/BookingTicket/index.js +2 -1
  23. package/dist/utils/payment-number.d.ts +9 -0
  24. package/dist/utils/payment-number.js +69 -0
  25. package/lib/model/strategy/adapter/promotion/index.js +0 -49
  26. package/lib/modules/Order/index.d.ts +27 -8
  27. package/lib/modules/Order/index.js +180 -60
  28. package/lib/modules/Order/payment-utils.d.ts +23 -0
  29. package/lib/modules/Order/payment-utils.js +193 -0
  30. package/lib/modules/Order/types.d.ts +33 -1
  31. package/lib/modules/Order/utils.js +2 -3
  32. package/lib/modules/Payment/index.d.ts +2 -0
  33. package/lib/modules/Payment/index.js +33 -12
  34. package/lib/modules/Payment/types.d.ts +26 -24
  35. package/lib/server/index.d.ts +14 -0
  36. package/lib/server/index.js +604 -8
  37. package/lib/server/modules/order/index.d.ts +40 -3
  38. package/lib/server/modules/order/index.js +434 -31
  39. package/lib/server/modules/order/types.d.ts +11 -3
  40. package/lib/solution/BaseSales/index.d.ts +33 -3
  41. package/lib/solution/BaseSales/index.js +167 -7
  42. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +6 -1
  43. package/lib/solution/BookingByStep/index.d.ts +1 -1
  44. package/lib/solution/BookingTicket/index.d.ts +1 -1
  45. package/lib/solution/BookingTicket/index.js +2 -1
  46. package/lib/utils/payment-number.d.ts +9 -0
  47. package/lib/utils/payment-number.js +64 -0
  48. package/package.json +1 -1
@@ -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",
@@ -87,6 +89,7 @@ var Server = class {
87
89
  this.BOOKING_REMOTE_CACHE_MAX_ENTRIES = 80;
88
90
  this.salesSearchSubscribers = /* @__PURE__ */ new Map();
89
91
  this.deviceTaskActionsRegistered = false;
92
+ this.localPaymentUpdateQueues = /* @__PURE__ */ new Map();
90
93
  this.floorPlanQuerySubscribers = /* @__PURE__ */ new Map();
91
94
  // 模块注册表 - 定义所有可用的模块配置
92
95
  this.moduleRegistry = {
@@ -575,6 +578,128 @@ var Server = class {
575
578
  title: "handleOrderSalesCheckout"
576
579
  });
577
580
  };
581
+ this.handleOrderSalesDraft = async ({ data }) => {
582
+ return this.handleOrderDraftSubmit({
583
+ data,
584
+ title: "handleOrderSalesDraft"
585
+ });
586
+ };
587
+ this.handleGetLocalPayment = async ({ data }) => {
588
+ const saleId = data == null ? void 0 : data.sale_id;
589
+ const paymentNumber = data == null ? void 0 : data.payment_number;
590
+ const operationId = this.createLocalPaymentOperationId("get");
591
+ const requestContext = {
592
+ operation_id: operationId,
593
+ sale_id: saleId ?? null,
594
+ payment_number: paymentNumber ?? null
595
+ };
596
+ this.logInfo("handleGetLocalPayment: 请求进入", requestContext);
597
+ if (saleId === void 0 || saleId === null || saleId === "" || paymentNumber === void 0 || paymentNumber === null || paymentNumber === "") {
598
+ this.logWarning("handleGetLocalPayment: 参数校验失败", {
599
+ ...requestContext,
600
+ missing_fields: [
601
+ ...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
602
+ ...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : []
603
+ ]
604
+ });
605
+ return {
606
+ code: 400,
607
+ status: false,
608
+ message: "sale_id 和 payment_number 必填",
609
+ data: null
610
+ };
611
+ }
612
+ if (!this.order) {
613
+ this.logError("handleGetLocalPayment: Order 模块未注册", requestContext);
614
+ return { code: 500, status: false, message: "Order 模块未注册", data: null };
615
+ }
616
+ const startedAt = Date.now();
617
+ try {
618
+ this.logInfo("handleGetLocalPayment: 开始查询本地支付项", requestContext);
619
+ const found = await this.order.getLocalPayment({
620
+ saleId,
621
+ paymentNumber,
622
+ operationId
623
+ });
624
+ if (!found) {
625
+ this.logWarning("handleGetLocalPayment: 本地支付项不存在", {
626
+ ...requestContext,
627
+ duration_ms: Date.now() - startedAt
628
+ });
629
+ return { code: 404, status: false, message: "本地支付项不存在", data: null };
630
+ }
631
+ this.logInfo("handleGetLocalPayment: 查询命中", {
632
+ ...requestContext,
633
+ duration_ms: Date.now() - startedAt,
634
+ matched_by: found.matchedBy,
635
+ payment_index: found.paymentIndex,
636
+ ...this.buildLocalPaymentOrderLogContext(found.order),
637
+ payment: found.payment
638
+ });
639
+ return { code: 200, status: true, message: "", data: found.payment };
640
+ } catch (error) {
641
+ this.logError("handleGetLocalPayment: 查询异常", {
642
+ ...requestContext,
643
+ duration_ms: Date.now() - startedAt,
644
+ error: error instanceof Error ? error.message : String(error),
645
+ error_detail: this.normalizeUnknownError(error)
646
+ });
647
+ throw error;
648
+ }
649
+ };
650
+ this.handleUpdateLocalPayment = async ({ data }) => {
651
+ const saleId = data == null ? void 0 : data.sale_id;
652
+ const paymentNumber = data == null ? void 0 : data.payment_number;
653
+ const number = data == null ? void 0 : data.number;
654
+ const status = data == null ? void 0 : data.status;
655
+ const serviceCharge = data == null ? void 0 : data.service_charge;
656
+ const cardReaderSurcharge = data == null ? void 0 : data.card_reader_surcharge;
657
+ const hasSurchargeInput = serviceCharge !== void 0 || cardReaderSurcharge !== void 0;
658
+ const invalidSurchargeFields = this.getInvalidLocalPaymentSurchargeFields(
659
+ serviceCharge,
660
+ cardReaderSurcharge
661
+ );
662
+ const operationId = this.createLocalPaymentOperationId("update");
663
+ const requestContext = {
664
+ operation_id: operationId,
665
+ sale_id: saleId ?? null,
666
+ payment_number: paymentNumber ?? null,
667
+ transaction_number: number ?? null,
668
+ requested_status: status ?? null,
669
+ service_charge: serviceCharge ?? null,
670
+ card_reader_surcharge: cardReaderSurcharge ?? null
671
+ };
672
+ this.logInfo("handleUpdateLocalPayment: 请求进入", requestContext);
673
+ 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) {
674
+ this.logWarning("handleUpdateLocalPayment: 参数校验失败", {
675
+ ...requestContext,
676
+ missing_or_invalid_fields: [
677
+ ...saleId === void 0 || saleId === null || saleId === "" ? ["sale_id"] : [],
678
+ ...paymentNumber === void 0 || paymentNumber === null || paymentNumber === "" ? ["payment_number"] : [],
679
+ ...number === void 0 || number === null || number === "" ? ["number"] : [],
680
+ ...status !== "success" && status !== "fail" ? ["status"] : [],
681
+ ...invalidSurchargeFields
682
+ ]
683
+ });
684
+ return {
685
+ code: 400,
686
+ status: false,
687
+ message: invalidSurchargeFields.length > 0 ? `手续费参数非法: ${invalidSurchargeFields.join(", ")}` : "sale_id、payment_number、number 必填,status 仅支持 success/fail",
688
+ data: null
689
+ };
690
+ }
691
+ const queueKey = `${String(saleId)}:${String(paymentNumber)}`;
692
+ return this.runLocalPaymentUpdateInQueue(queueKey, () => this.processLocalPaymentUpdate({
693
+ operationId,
694
+ saleId,
695
+ paymentNumber,
696
+ number: String(number),
697
+ status,
698
+ serviceCharge,
699
+ cardReaderSurcharge,
700
+ hasSurchargeInput
701
+ }), requestContext);
702
+ };
578
703
  this.handleOrderCheckout = async ({ data }) => {
579
704
  return this.handleOrderCheckoutSubmit({
580
705
  backendPath: "/order/checkout",
@@ -1439,13 +1564,15 @@ var Server = class {
1439
1564
  ...checkoutData,
1440
1565
  ...fresh,
1441
1566
  external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1442
- need_sync: 0
1567
+ need_sync: 0,
1568
+ is_draft_order: 0
1443
1569
  } : {
1444
1570
  ...fresh,
1445
1571
  external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1446
- need_sync: 0
1572
+ need_sync: 0,
1573
+ is_draft_order: 0
1447
1574
  };
1448
- await this.order.upsertOrdersFromRemote([syncedOrder]);
1575
+ await this.order.upsertOrdersFromRemote([syncedOrder], "checkoutSync");
1449
1576
  this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
1450
1577
  order_id: fresh.order_id,
1451
1578
  external_sale_number: syncedOrder.external_sale_number,
@@ -1463,7 +1590,8 @@ var Server = class {
1463
1590
  ...checkoutData,
1464
1591
  ...patch,
1465
1592
  external_sale_number: externalSaleNumber,
1466
- need_sync: 0
1593
+ need_sync: 0,
1594
+ is_draft_order: 0
1467
1595
  };
1468
1596
  this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
1469
1597
  order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
@@ -1843,6 +1971,11 @@ var Server = class {
1843
1971
  path: "/shop/order/sales/checkout",
1844
1972
  handler: this.handleOrderSalesCheckout.bind(this)
1845
1973
  },
1974
+ {
1975
+ method: "post",
1976
+ path: "/shop/order/sales/draft",
1977
+ handler: this.handleOrderSalesDraft.bind(this)
1978
+ },
1846
1979
  {
1847
1980
  method: "post",
1848
1981
  path: "/order/checkout",
@@ -1853,6 +1986,16 @@ var Server = class {
1853
1986
  path: "/shop/local/print-order",
1854
1987
  handler: this.handleLocalPrintOrder.bind(this)
1855
1988
  },
1989
+ {
1990
+ method: "post",
1991
+ path: "/shop/local/getLocalPayment",
1992
+ handler: this.handleGetLocalPayment.bind(this)
1993
+ },
1994
+ {
1995
+ method: "post",
1996
+ path: "/shop/local/updateLocalPayment",
1997
+ handler: this.handleUpdateLocalPayment.bind(this)
1998
+ },
1856
1999
  {
1857
2000
  method: "post",
1858
2001
  path: "/shop/machinecode/batch",
@@ -2694,6 +2837,403 @@ var Server = class {
2694
2837
  };
2695
2838
  }
2696
2839
  }
2840
+ createLocalPaymentOperationId(action) {
2841
+ return `local_payment_${action}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
2842
+ }
2843
+ buildLocalPaymentOrderLogContext(order) {
2844
+ if (!order)
2845
+ return {};
2846
+ return {
2847
+ order_id: order.order_id ?? null,
2848
+ external_sale_number: order.external_sale_number ?? null,
2849
+ order_number: order.order_number ?? null,
2850
+ shop_order_number: order.shop_order_number ?? null,
2851
+ shop_full_order_number: order.shop_full_order_number ?? null,
2852
+ order_status: order.status ?? null,
2853
+ payment_status: order.payment_status ?? null,
2854
+ is_draft_order: Number(order.is_draft_order || 0),
2855
+ need_sync: Number(order.need_sync || 0),
2856
+ platform: order.platform ?? null,
2857
+ business_code: order.business_code ?? null,
2858
+ order_sales_channel: order.order_sales_channel ?? null,
2859
+ sales_channel: order.sales_channel ?? null,
2860
+ order_type: order.type ?? null,
2861
+ payments_count: Array.isArray(order.payments) ? order.payments.length : 0
2862
+ };
2863
+ }
2864
+ isValidLocalPaymentDecimal(value) {
2865
+ if (typeof value !== "string" && typeof value !== "number")
2866
+ return false;
2867
+ if (typeof value === "string" && value.trim() === "")
2868
+ return false;
2869
+ try {
2870
+ return new import_decimal.default(value).isFinite();
2871
+ } catch {
2872
+ return false;
2873
+ }
2874
+ }
2875
+ getInvalidLocalPaymentSurchargeFields(serviceCharge, cardReaderSurcharge) {
2876
+ const invalidFields = [];
2877
+ if (serviceCharge !== void 0) {
2878
+ if (serviceCharge === null || typeof serviceCharge !== "object" || Array.isArray(serviceCharge)) {
2879
+ invalidFields.push("service_charge");
2880
+ } else {
2881
+ const input = serviceCharge;
2882
+ if (input.fixed !== void 0 && !this.isValidLocalPaymentDecimal(input.fixed)) {
2883
+ invalidFields.push("service_charge.fixed");
2884
+ }
2885
+ if (input.percentage !== void 0 && !this.isValidLocalPaymentDecimal(input.percentage)) {
2886
+ invalidFields.push("service_charge.percentage");
2887
+ }
2888
+ }
2889
+ }
2890
+ if (cardReaderSurcharge !== void 0 && !this.isValidLocalPaymentDecimal(cardReaderSurcharge)) {
2891
+ invalidFields.push("card_reader_surcharge");
2892
+ }
2893
+ return invalidFields;
2894
+ }
2895
+ buildLocalPaymentSurchargeUpdate(params) {
2896
+ var _a, _b, _c;
2897
+ const amount = new import_decimal.default(((_a = params.serviceCharge) == null ? void 0 : _a.fixed) || 0).plus(params.cardReaderSurcharge || 0).toFixed(2);
2898
+ 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);
2899
+ return {
2900
+ service_charge: {
2901
+ amount,
2902
+ ...((_c = params.serviceCharge) == null ? void 0 : _c.percentage) !== void 0 ? { percentage: params.serviceCharge.percentage } : {}
2903
+ },
2904
+ service_fee: serviceFee
2905
+ };
2906
+ }
2907
+ async runLocalPaymentUpdateInQueue(key, task, context) {
2908
+ var _a;
2909
+ const queuedAt = Date.now();
2910
+ const hasPreviousTask = this.localPaymentUpdateQueues.has(key);
2911
+ const previous = this.localPaymentUpdateQueues.get(key) || Promise.resolve();
2912
+ this.logInfo("handleUpdateLocalPayment: 串行队列入队", {
2913
+ ...context,
2914
+ queue_key: key,
2915
+ waiting_for_previous: hasPreviousTask,
2916
+ active_queue_count: this.localPaymentUpdateQueues.size
2917
+ });
2918
+ const current = previous.catch(() => void 0).then(async () => {
2919
+ this.logInfo("handleUpdateLocalPayment: 串行队列开始执行", {
2920
+ ...context,
2921
+ queue_key: key,
2922
+ queue_wait_ms: Date.now() - queuedAt
2923
+ });
2924
+ return task();
2925
+ });
2926
+ const tail = current.then(() => void 0, () => void 0);
2927
+ this.localPaymentUpdateQueues.set(key, tail);
2928
+ try {
2929
+ const result = await current;
2930
+ this.logInfo("handleUpdateLocalPayment: 串行队列执行完成", {
2931
+ ...context,
2932
+ queue_key: key,
2933
+ total_duration_ms: Date.now() - queuedAt,
2934
+ result_code: result == null ? void 0 : result.code,
2935
+ result_status: result == null ? void 0 : result.status,
2936
+ payment: (_a = result == null ? void 0 : result.data) == null ? void 0 : _a.payment
2937
+ });
2938
+ return result;
2939
+ } catch (error) {
2940
+ this.logError("handleUpdateLocalPayment: 串行队列执行失败", {
2941
+ ...context,
2942
+ queue_key: key,
2943
+ total_duration_ms: Date.now() - queuedAt,
2944
+ error: error instanceof Error ? error.message : String(error),
2945
+ error_detail: this.normalizeUnknownError(error)
2946
+ });
2947
+ throw error;
2948
+ } finally {
2949
+ let released = false;
2950
+ if (this.localPaymentUpdateQueues.get(key) === tail) {
2951
+ this.localPaymentUpdateQueues.delete(key);
2952
+ released = true;
2953
+ }
2954
+ this.logInfo("handleUpdateLocalPayment: 串行队列释放", {
2955
+ ...context,
2956
+ queue_key: key,
2957
+ released,
2958
+ active_queue_count: this.localPaymentUpdateQueues.size
2959
+ });
2960
+ }
2961
+ }
2962
+ async processLocalPaymentUpdate(params) {
2963
+ var _a, _b, _c;
2964
+ const requestContext = {
2965
+ operation_id: params.operationId,
2966
+ sale_id: params.saleId,
2967
+ payment_number: params.paymentNumber,
2968
+ transaction_number: params.number,
2969
+ requested_status: params.status,
2970
+ service_charge: params.serviceCharge ?? null,
2971
+ card_reader_surcharge: params.cardReaderSurcharge ?? null
2972
+ };
2973
+ this.logInfo("processLocalPaymentUpdate: 开始处理", requestContext);
2974
+ if (!this.order) {
2975
+ this.logError("processLocalPaymentUpdate: Order 模块未注册", requestContext);
2976
+ return { code: 500, status: false, message: "Order 模块未注册", data: null };
2977
+ }
2978
+ this.logInfo("processLocalPaymentUpdate: 开始查询本地支付项", requestContext);
2979
+ const found = await this.order.getLocalPayment({
2980
+ saleId: params.saleId,
2981
+ paymentNumber: params.paymentNumber,
2982
+ operationId: params.operationId
2983
+ });
2984
+ if (!found) {
2985
+ this.logWarning("processLocalPaymentUpdate: 本地支付项不存在", requestContext);
2986
+ return { code: 404, status: false, message: "本地支付项不存在", data: null };
2987
+ }
2988
+ const surchargeUpdate = params.status === "success" && params.hasSurchargeInput ? this.buildLocalPaymentSurchargeUpdate({
2989
+ paymentAmount: (_a = found.payment) == null ? void 0 : _a.amount,
2990
+ serviceCharge: params.serviceCharge,
2991
+ cardReaderSurcharge: params.cardReaderSurcharge
2992
+ }) : void 0;
2993
+ const incomingPaymentUpdate = params.status === "success" ? {
2994
+ status: "paid",
2995
+ ...surchargeUpdate || {},
2996
+ metadata: {
2997
+ unique_payment_number: params.number,
2998
+ transactions: [{ number: params.number, status: "success" }]
2999
+ }
3000
+ } : {
3001
+ metadata: {
3002
+ transactions: [{ number: params.number, status: "fail" }]
3003
+ }
3004
+ };
3005
+ const transactions = Array.isArray((_c = (_b = found.payment) == null ? void 0 : _b.metadata) == null ? void 0 : _c.transactions) ? found.payment.metadata.transactions : [];
3006
+ const existingTransaction = transactions.find((item) => String((item == null ? void 0 : item.number) || "") === params.number);
3007
+ const hasRecordedSuccess = transactions.some((item) => (item == null ? void 0 : item.status) === "success");
3008
+ const orderIsDraft = Number(found.order.is_draft_order || 0) === 1;
3009
+ const foundContext = {
3010
+ ...requestContext,
3011
+ matched_by: found.matchedBy,
3012
+ payment_index: found.paymentIndex,
3013
+ ...this.buildLocalPaymentOrderLogContext(found.order),
3014
+ payment: found.payment,
3015
+ incoming_payment_update: incomingPaymentUpdate,
3016
+ existing_transaction: existingTransaction || null,
3017
+ has_recorded_success: hasRecordedSuccess
3018
+ };
3019
+ this.logInfo("processLocalPaymentUpdate: 查询命中", foundContext);
3020
+ if (params.status === "fail" && (found.payment.status === "paid" || hasRecordedSuccess)) {
3021
+ this.logInfo("processLocalPaymentUpdate: 幂等返回", {
3022
+ ...foundContext,
3023
+ idempotent_reason: "ignore_failure_after_success"
3024
+ });
3025
+ return {
3026
+ code: 200,
3027
+ status: true,
3028
+ message: "",
3029
+ data: { payment: found.payment, order: found.order, idempotent: true }
3030
+ };
3031
+ }
3032
+ const alreadyRecordedFailure = params.status === "fail" && (existingTransaction == null ? void 0 : existingTransaction.status) === "fail";
3033
+ if (alreadyRecordedFailure) {
3034
+ this.logInfo("processLocalPaymentUpdate: 幂等返回", {
3035
+ ...foundContext,
3036
+ idempotent_reason: "failure_already_recorded"
3037
+ });
3038
+ return {
3039
+ code: 200,
3040
+ status: true,
3041
+ message: "",
3042
+ data: { payment: found.payment, order: found.order, idempotent: true }
3043
+ };
3044
+ }
3045
+ if (params.status === "success" && (existingTransaction == null ? void 0 : existingTransaction.status) === "success" && found.payment.status === "paid" && !orderIsDraft) {
3046
+ this.logInfo("processLocalPaymentUpdate: 幂等返回", {
3047
+ ...foundContext,
3048
+ idempotent_reason: "success_already_committed"
3049
+ });
3050
+ return {
3051
+ code: 200,
3052
+ status: true,
3053
+ message: "",
3054
+ data: { payment: found.payment, order: found.order, idempotent: true }
3055
+ };
3056
+ }
3057
+ if (params.status === "success") {
3058
+ this.logInfo("processLocalPaymentUpdate: 进入 success 恢复分支", {
3059
+ ...foundContext,
3060
+ force_submit_if_paid: found.payment.status === "paid" && orderIsDraft
3061
+ });
3062
+ return this.processSuccessfulLocalPayment({
3063
+ ...params,
3064
+ order: found.order,
3065
+ payment: found.payment,
3066
+ matchBy: found.matchedBy === "payment_number" ? "payment_number" : "compat",
3067
+ forceSubmitIfPaid: found.payment.status === "paid" && orderIsDraft,
3068
+ paymentUpdate: incomingPaymentUpdate
3069
+ });
3070
+ }
3071
+ this.logInfo("processLocalPaymentUpdate: 进入 fail 本地更新分支", {
3072
+ ...foundContext,
3073
+ incoming_payment_update: incomingPaymentUpdate
3074
+ });
3075
+ let updated;
3076
+ try {
3077
+ updated = await this.order.updateLocalPayment({
3078
+ saleId: params.saleId,
3079
+ paymentNumber: params.paymentNumber,
3080
+ operationId: params.operationId,
3081
+ updates: incomingPaymentUpdate
3082
+ });
3083
+ } catch (error) {
3084
+ this.logError("processLocalPaymentUpdate: fail 本地更新失败", {
3085
+ ...foundContext,
3086
+ incoming_payment_update: incomingPaymentUpdate,
3087
+ error: error instanceof Error ? error.message : String(error),
3088
+ error_detail: this.normalizeUnknownError(error)
3089
+ });
3090
+ throw error;
3091
+ }
3092
+ if (!updated) {
3093
+ this.logWarning("processLocalPaymentUpdate: fail 本地更新未命中", foundContext);
3094
+ return { code: 404, status: false, message: "本地支付项不存在", data: null };
3095
+ }
3096
+ this.logInfo("processLocalPaymentUpdate: fail 本地更新完成", {
3097
+ ...requestContext,
3098
+ ...this.buildLocalPaymentOrderLogContext(updated.order),
3099
+ previous_payment: updated.previousPayment,
3100
+ payment: updated.payment
3101
+ });
3102
+ return {
3103
+ code: 200,
3104
+ status: true,
3105
+ message: "",
3106
+ data: {
3107
+ local_only: true,
3108
+ payment: updated.payment,
3109
+ order: updated.order
3110
+ }
3111
+ };
3112
+ }
3113
+ async processSuccessfulLocalPayment(params) {
3114
+ var _a, _b, _c, _d, _e;
3115
+ const moduleName = `local_payment_recovery_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
3116
+ const baseSales = new import_BaseSales.BaseSalesImpl(moduleName);
3117
+ const startedAt = Date.now();
3118
+ const recoveryContext = {
3119
+ operation_id: params.operationId,
3120
+ sale_id: params.saleId,
3121
+ payment_number: params.paymentNumber,
3122
+ transaction_number: params.number,
3123
+ requested_status: "success",
3124
+ match_by: params.matchBy,
3125
+ force_submit_if_paid: params.forceSubmitIfPaid,
3126
+ incoming_payment_update: params.paymentUpdate,
3127
+ base_sales_module_name: moduleName,
3128
+ ...this.buildLocalPaymentOrderLogContext(params.order),
3129
+ payment: params.payment
3130
+ };
3131
+ this.logInfo("processSuccessfulLocalPayment: 创建临时 BaseSales", recoveryContext);
3132
+ try {
3133
+ const order = this.sanitizeLocalRecoveryOrder(params.order);
3134
+ this.logInfo("processSuccessfulLocalPayment: 本地订单清洗完成", {
3135
+ ...recoveryContext,
3136
+ sanitized_order_id: order.order_id ?? null,
3137
+ removed_synthetic_order_id: params.order.order_id != null && order.order_id == null
3138
+ });
3139
+ await baseSales.initialize(this.core, {
3140
+ otherParams: {
3141
+ platform: order.platform,
3142
+ businessCode: order.business_code,
3143
+ business_code: order.business_code,
3144
+ channel: order.order_sales_channel || order.sales_channel,
3145
+ type: order.type,
3146
+ enableTempOrderPersist: false
3147
+ }
3148
+ });
3149
+ this.logInfo("processSuccessfulLocalPayment: BaseSales 初始化完成", recoveryContext);
3150
+ await baseSales.loadSalesDetail({
3151
+ externalSaleNumber: String(params.saleId),
3152
+ preloadedSalesDetail: order
3153
+ });
3154
+ this.logInfo("processSuccessfulLocalPayment: 本地订单 hydrate 完成", recoveryContext);
3155
+ this.logInfo("processSuccessfulLocalPayment: 开始更新支付项并提交", {
3156
+ ...recoveryContext,
3157
+ incoming_payment_update: params.paymentUpdate
3158
+ });
3159
+ const result = await baseSales.updateOrderPayment(
3160
+ params.paymentNumber,
3161
+ params.paymentUpdate,
3162
+ {
3163
+ submitWhenPaid: true,
3164
+ matchBy: params.matchBy,
3165
+ forceSubmitIfPaid: params.forceSubmitIfPaid,
3166
+ applyUpdatesWhenPaid: params.forceSubmitIfPaid,
3167
+ smallTicketDataFlag: 1
3168
+ }
3169
+ );
3170
+ this.logInfo("processSuccessfulLocalPayment: 支付恢复完成", {
3171
+ ...recoveryContext,
3172
+ duration_ms: Date.now() - startedAt,
3173
+ payment: result.payment,
3174
+ payments_count: ((_a = result.payments) == null ? void 0 : _a.length) || 0,
3175
+ summary: result.summary,
3176
+ sync_result: result.syncResult ? {
3177
+ is_fully_paid: result.syncResult.isFullyPaid,
3178
+ is_order_fully_paid: result.syncResult.isOrderFullyPaid,
3179
+ is_deposit_fully_paid: result.syncResult.isDepositFullyPaid,
3180
+ payment_stage: result.syncResult.paymentStage,
3181
+ deposit_amount: result.syncResult.depositAmount,
3182
+ order_expected_amount: result.syncResult.orderExpectedAmount,
3183
+ submit_result_code: (_b = result.syncResult.submitResult) == null ? void 0 : _b.code,
3184
+ submit_result_status: (_c = result.syncResult.submitResult) == null ? void 0 : _c.status
3185
+ } : null,
3186
+ draft_result: result.draftResult ? {
3187
+ code: (_d = result.draftResult) == null ? void 0 : _d.code,
3188
+ status: (_e = result.draftResult) == null ? void 0 : _e.status
3189
+ } : null,
3190
+ draft_error: result.draftError instanceof Error ? result.draftError.message : result.draftError
3191
+ });
3192
+ return {
3193
+ code: 200,
3194
+ status: true,
3195
+ message: "",
3196
+ data: {
3197
+ payment: result.payment,
3198
+ payments: result.payments,
3199
+ summary: result.summary,
3200
+ sync_result: result.syncResult
3201
+ }
3202
+ };
3203
+ } catch (error) {
3204
+ const message = error instanceof Error ? error.message : String(error);
3205
+ this.logError("processSuccessfulLocalPayment: 支付恢复失败", {
3206
+ ...recoveryContext,
3207
+ duration_ms: Date.now() - startedAt,
3208
+ error: message,
3209
+ error_detail: this.normalizeUnknownError(error)
3210
+ });
3211
+ return { code: 500, status: false, message, data: null };
3212
+ } finally {
3213
+ try {
3214
+ await baseSales.destroy();
3215
+ this.logInfo("processSuccessfulLocalPayment: 临时 BaseSales 销毁完成", {
3216
+ ...recoveryContext,
3217
+ duration_ms: Date.now() - startedAt
3218
+ });
3219
+ } catch (error) {
3220
+ this.logError("processSuccessfulLocalPayment: 临时 BaseSales 销毁失败", {
3221
+ ...recoveryContext,
3222
+ duration_ms: Date.now() - startedAt,
3223
+ error: error instanceof Error ? error.message : String(error),
3224
+ error_detail: this.normalizeUnknownError(error)
3225
+ });
3226
+ }
3227
+ }
3228
+ }
3229
+ sanitizeLocalRecoveryOrder(order) {
3230
+ const next = { ...order };
3231
+ const externalSaleNumber = next.external_sale_number;
3232
+ if (Number(next.is_draft_order || 0) === 1 && next.order_id !== void 0 && externalSaleNumber !== void 0 && String(next.order_id) === String(externalSaleNumber)) {
3233
+ delete next.order_id;
3234
+ }
3235
+ return next;
3236
+ }
2697
3237
  getDeviceTaskPlugin() {
2698
3238
  var _a, _b;
2699
3239
  return ((_b = (_a = this.app) == null ? void 0 : _a.getPlugin) == null ? void 0 : _b.call(_a, "deviceTask")) || null;
@@ -3214,6 +3754,59 @@ var Server = class {
3214
3754
  };
3215
3755
  }
3216
3756
  }
3757
+ async handleOrderDraftSubmit(params) {
3758
+ var _a, _b, _c;
3759
+ const { data, title } = params;
3760
+ this.logInfo(`${title}: 开始处理`, {
3761
+ order_id: data == null ? void 0 : data.order_id,
3762
+ external_sale_number: data == null ? void 0 : data.external_sale_number,
3763
+ order_number: data == null ? void 0 : data.order_number
3764
+ });
3765
+ const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
3766
+ const createdAt = normalizedData.created_at || normalizedData.create_date || (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
3767
+ const draftOrder = {
3768
+ ...normalizedData,
3769
+ external_sale_number: normalizedData.external_sale_number || `LOCAL_DRAFT_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
3770
+ created_at: createdAt,
3771
+ schedule_date: normalizedData.schedule_date || createdAt,
3772
+ need_sync: 0,
3773
+ is_draft_order: 1
3774
+ };
3775
+ if (!this.order || typeof this.order.upsertLocalDraftOrders !== "function") {
3776
+ this.logError(`${title}: Order 模块不支持本地草稿写入`);
3777
+ return {
3778
+ code: 500,
3779
+ status: false,
3780
+ message: "Order 模块不支持本地草稿写入",
3781
+ data: null
3782
+ };
3783
+ }
3784
+ try {
3785
+ await this.order.upsertLocalDraftOrders([draftOrder]);
3786
+ this.logInfo(`${title}: 草稿订单已写入本地`, {
3787
+ order_id: draftOrder.order_id,
3788
+ external_sale_number: draftOrder.external_sale_number
3789
+ });
3790
+ return {
3791
+ code: 200,
3792
+ status: true,
3793
+ message: "",
3794
+ data: {
3795
+ ...draftOrder,
3796
+ amount_gap: (_a = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _a.amount_gap,
3797
+ expect_amount: (_b = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _b.expect_amount,
3798
+ total_amount: (_c = draftOrder == null ? void 0 : draftOrder.summary) == null ? void 0 : _c.total_amount,
3799
+ payment_status: draftOrder == null ? void 0 : draftOrder.payment_status
3800
+ }
3801
+ };
3802
+ } catch (error) {
3803
+ const errorMessage = error instanceof Error ? error.message : String(error);
3804
+ this.logError(`${title}: 写入本地草稿订单失败`, {
3805
+ error: errorMessage
3806
+ });
3807
+ return { code: 500, status: false, message: errorMessage, data: null };
3808
+ }
3809
+ }
3217
3810
  async handlePendingSyncCheckoutOrder(params) {
3218
3811
  var _a, _b, _c, _d;
3219
3812
  const { backendPath, data, title, reason } = params;
@@ -3289,7 +3882,8 @@ var Server = class {
3289
3882
  return null;
3290
3883
  const pendingOrder = {
3291
3884
  ...data,
3292
- need_sync: 1
3885
+ need_sync: 1,
3886
+ is_draft_order: 0
3293
3887
  };
3294
3888
  const productMap = await this.buildSmallTicketProductMap(pendingOrder);
3295
3889
  const orderWithProductTitles = this.withPendingSyncProductTitles(
@@ -3342,7 +3936,7 @@ var Server = class {
3342
3936
  return 0;
3343
3937
  return payments.reduce((sum, payment) => {
3344
3938
  const status = String((payment == null ? void 0 : payment.status) || "").toLowerCase();
3345
- if (status === "voided" || status === "failed" || status === "cancelled")
3939
+ if (status !== "paid")
3346
3940
  return sum;
3347
3941
  return sum + this.toAmountNumber((payment == null ? void 0 : payment.amount) ?? (payment == null ? void 0 : payment.origin_amount));
3348
3942
  }, 0);
@@ -3909,9 +4503,11 @@ var Server = class {
3909
4503
  return value === void 0 ? void 0 : String(value);
3910
4504
  }
3911
4505
  buildCheckoutSyncSuccessPatch(fresh) {
4506
+ const patch = {
4507
+ is_draft_order: 0
4508
+ };
3912
4509
  if (!fresh)
3913
- return {};
3914
- const patch = {};
4510
+ return patch;
3915
4511
  if (fresh.order_id !== void 0 && fresh.order_id !== null)
3916
4512
  patch.order_id = fresh.order_id;
3917
4513
  if (fresh.order_number !== void 0 && fresh.order_number !== null) {