@pisell/pisellos 2.2.196 → 2.2.198

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.
@@ -86,6 +86,80 @@ var OrderModule = class extends import_BaseModule.BaseModule {
86
86
  */
87
87
  this.draftPersistEnabled = true;
88
88
  }
89
+ collectHydratedEditDiscounts(products) {
90
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
91
+ const discountMap = /* @__PURE__ */ new Map();
92
+ for (const product of products || []) {
93
+ for (const item of (product == null ? void 0 : product.discount_list) || []) {
94
+ const type = (item == null ? void 0 : item.type) ?? (item == null ? void 0 : item.tag);
95
+ if (!type || type === "product")
96
+ continue;
97
+ const resourceId = ((_a = item == null ? void 0 : item.discount) == null ? void 0 : _a.resource_id) ?? (item == null ? void 0 : item.resource_id) ?? (item == null ? void 0 : item.discount_id) ?? (item == null ? void 0 : item.order_discount_id);
98
+ if (resourceId === void 0 || resourceId === null || resourceId === "")
99
+ continue;
100
+ const id = Number(resourceId);
101
+ const key = Number.isFinite(id) ? id : String(resourceId);
102
+ const title = ((_b = item == null ? void 0 : item.discount) == null ? void 0 : _b.title) ?? {};
103
+ const amount = Number((item == null ? void 0 : item.amount) || 0);
104
+ const detail = {
105
+ amount: String((item == null ? void 0 : item.amount) ?? "0"),
106
+ type,
107
+ resource_id: key,
108
+ title,
109
+ original_amount: String(((_c = item == null ? void 0 : item.discount) == null ? void 0 : _c.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
110
+ num: Number(((_d = item == null ? void 0 : item.metadata) == null ? void 0 : _d.num) ?? (product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity) ?? 1) || 1,
111
+ metadata: item == null ? void 0 : item.metadata,
112
+ discount: item == null ? void 0 : item.discount,
113
+ _num: Number(((_e = item == null ? void 0 : item.metadata) == null ? void 0 : _e.num) ?? (product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity) ?? 1) || 1
114
+ };
115
+ discountMap.set(key, {
116
+ id: key,
117
+ product_name: "",
118
+ encoded: "",
119
+ code: "",
120
+ tag: type,
121
+ product_id: ((_f = item == null ? void 0 : item.discount) == null ? void 0 : _f.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
122
+ relation_type: "",
123
+ par_value: String(((_g = item == null ? void 0 : item.discount) == null ? void 0 : _g.original_amount) ?? (item == null ? void 0 : item.amount) ?? "0"),
124
+ used_par_value: String((item == null ? void 0 : item.amount) ?? "0"),
125
+ limit_status: "enable",
126
+ limited_relation_product_data: {
127
+ id: 0,
128
+ type: "products",
129
+ product_ids: [product == null ? void 0 : product.product_id].filter((value) => value !== void 0 && value !== null),
130
+ product_collection_id: [],
131
+ filter: 0,
132
+ exclude_product_ids: []
133
+ },
134
+ balance: String((item == null ? void 0 : item.amount) ?? "0"),
135
+ format_title: title,
136
+ product: {
137
+ id: (product == null ? void 0 : product.product_id) ?? 0,
138
+ title: "",
139
+ is_charge_tax: (product == null ? void 0 : product.is_charge_tax) ?? 0,
140
+ base_price: String((product == null ? void 0 : product.original_price) ?? (product == null ? void 0 : product.selling_price) ?? "0")
141
+ },
142
+ type,
143
+ resource_id: key,
144
+ isEditMode: true,
145
+ isSelected: true,
146
+ isAvailable: true,
147
+ isUsed: true,
148
+ isDisabled: true,
149
+ amount,
150
+ discount: {
151
+ ...(item == null ? void 0 : item.discount) || {},
152
+ resource_id: key,
153
+ discount_product_id: ((_h = item == null ? void 0 : item.discount) == null ? void 0 : _h.discount_product_id) ?? (product == null ? void 0 : product.product_id) ?? 0,
154
+ discount_calculation_mode: ((_i = item == null ? void 0 : item.discount) == null ? void 0 : _i.discount_calculation_mode) ?? "item_level"
155
+ },
156
+ applicableProductDetails: [detail],
157
+ appliedProductDetails: [detail]
158
+ });
159
+ }
160
+ }
161
+ return Array.from(discountMap.values());
162
+ }
89
163
  /**
90
164
  * Populate `savedAmount` on each discount based on product-level discount details.
91
165
  * Only selected discounts get a non-zero value.
@@ -244,7 +318,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
244
318
  }
245
319
  // ─── Discount: 公共 API ───
246
320
  async loadDiscountConfig(params) {
247
- var _a, _b, _c, _d, _e, _f;
321
+ var _a, _b, _c, _d, _e, _f, _g;
248
322
  const orderId = params.orderId || ((_a = this.store.tempOrder) == null ? void 0 : _a.order_id) || void 0;
249
323
  const discountList = await ((_b = this.store.discount) == null ? void 0 : _b.loadPrepareConfig({
250
324
  customer_id: params.customerId,
@@ -256,10 +330,18 @@ var OrderModule = class extends import_BaseModule.BaseModule {
256
330
  ...orderId ? { order_id: orderId } : {}
257
331
  }));
258
332
  if (discountList) {
259
- await ((_c = this.store.discount) == null ? void 0 : _c.setOriginalDiscountList(discountList));
260
- await ((_d = this.store.discount) == null ? void 0 : _d.setDiscountList(discountList));
261
- }
262
- if (params.apply !== false && ((_f = (_e = this.store.tempOrder) == null ? void 0 : _e.products) == null ? void 0 : _f.length)) {
333
+ const currentEditDiscounts = (((_c = this.store.discount) == null ? void 0 : _c.getDiscountList()) || []).filter((discount) => discount == null ? void 0 : discount.isEditMode);
334
+ const currentEditDiscountIds = new Set(
335
+ currentEditDiscounts.map((discount) => discount == null ? void 0 : discount.id)
336
+ );
337
+ const mergedDiscountList = [
338
+ ...currentEditDiscounts,
339
+ ...discountList.filter((discount) => !currentEditDiscountIds.has(discount == null ? void 0 : discount.id))
340
+ ];
341
+ await ((_d = this.store.discount) == null ? void 0 : _d.setOriginalDiscountList(mergedDiscountList));
342
+ await ((_e = this.store.discount) == null ? void 0 : _e.setDiscountList(mergedDiscountList));
343
+ }
344
+ if (params.apply !== false && ((_g = (_f = this.store.tempOrder) == null ? void 0 : _f.products) == null ? void 0 : _g.length)) {
263
345
  this.applyDiscount();
264
346
  }
265
347
  return this.getDiscountList();
@@ -268,6 +350,25 @@ var OrderModule = class extends import_BaseModule.BaseModule {
268
350
  var _a;
269
351
  return ((_a = this.store.discount) == null ? void 0 : _a.getDiscountList()) || [];
270
352
  }
353
+ async ensureEditDiscountConfigForProductChange(tempOrder) {
354
+ var _a, _b, _c, _d, _e, _f;
355
+ const orderId = tempOrder.order_id;
356
+ const customerId = Number(
357
+ tempOrder.customer_id || ((_a = tempOrder.customer) == null ? void 0 : _a.id) || ((_c = (_b = tempOrder._extend) == null ? void 0 : _b.customerSnapshot) == null ? void 0 : _c.id) || ((_e = (_d = tempOrder._extend) == null ? void 0 : _d.customerSnapshot) == null ? void 0 : _e.customer_id) || 0
358
+ );
359
+ if (!orderId || !customerId || customerId === 1)
360
+ return;
361
+ const currentDiscountList = ((_f = this.store.discount) == null ? void 0 : _f.getDiscountList()) || [];
362
+ const hasRuntimeDiscounts = currentDiscountList.some((discount) => !(discount == null ? void 0 : discount.isEditMode));
363
+ if (hasRuntimeDiscounts)
364
+ return;
365
+ await this.loadDiscountConfig({
366
+ customerId,
367
+ action: "edit",
368
+ orderId: Number(orderId),
369
+ apply: false
370
+ });
371
+ }
271
372
  async scanCode(code, customerId) {
272
373
  var _a, _b, _c, _d, _e;
273
374
  const resultDiscountWithReason = await ((_a = this.store.discount) == null ? void 0 : _a.batchSearch(code, { customerId })) || { discountList: [], unavailableReasonKey: null };
@@ -741,14 +842,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
741
842
  customerPaidAmount: summary.customerPaidAmount.plus(paymentRecord.amount || 0),
742
843
  orderPaidAmount: summary.orderPaidAmount.plus(paymentRecord.origin_amount || 0),
743
844
  gapPaidAmount: summary.gapPaidAmount.plus(this.calculatePaymentGapAmount(paymentRecord)),
744
- payServiceChargeAmount: summary.payServiceChargeAmount.plus(this.calculatePaymentServiceFee(paymentRecord))
845
+ payServiceChargeAmount: summary.payServiceChargeAmount.plus(this.calculatePaymentServiceFee(paymentRecord)),
846
+ roundingAmount: summary.roundingAmount.plus(this.calculatePaymentRoundingAmount(paymentRecord))
745
847
  };
746
848
  },
747
849
  {
748
850
  customerPaidAmount: new import_decimal.default(0),
749
851
  orderPaidAmount: new import_decimal.default(0),
750
852
  gapPaidAmount: new import_decimal.default(0),
751
- payServiceChargeAmount: new import_decimal.default(0)
853
+ payServiceChargeAmount: new import_decimal.default(0),
854
+ roundingAmount: new import_decimal.default(0)
752
855
  }
753
856
  );
754
857
  }
@@ -768,6 +871,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
768
871
  const rounding = new import_decimal.default(payment.rounding_amount || 0);
769
872
  return new import_decimal.default(payment.origin_amount || 0).minus(rounding);
770
873
  }
874
+ calculatePaymentRoundingAmount(payment) {
875
+ if (payment.rounding_amount === void 0 || payment.rounding_amount === null || payment.rounding_amount === "") {
876
+ return new import_decimal.default(0);
877
+ }
878
+ return new import_decimal.default(payment.rounding_amount || 0);
879
+ }
771
880
  formatSummaryMetadataMoney(value) {
772
881
  if (value === void 0 || value === null || value === "")
773
882
  return void 0;
@@ -834,7 +943,219 @@ var OrderModule = class extends import_BaseModule.BaseModule {
834
943
  calculatePaymentTargetAmount(tempOrder, summary) {
835
944
  const depositAmount = summary.deposit_amount || tempOrder.deposit_amount || "0.00";
836
945
  const isDeposit = tempOrder.is_deposit === 1 || new import_decimal.default(depositAmount || 0).gt(0);
837
- return isDeposit ? new import_decimal.default(depositAmount || 0) : new import_decimal.default(summary.total_amount || summary.expect_amount || 0);
946
+ return isDeposit ? new import_decimal.default(depositAmount || 0) : new import_decimal.default(summary.expect_amount || summary.total_amount || 0);
947
+ }
948
+ normalizeFingerprintMoney(value) {
949
+ if (value === void 0 || value === null || value === "")
950
+ return "";
951
+ try {
952
+ const parsed = new import_decimal.default(String(value || 0));
953
+ return parsed.toFixed(4);
954
+ } catch {
955
+ return String(value);
956
+ }
957
+ }
958
+ normalizeFingerprintValue(value) {
959
+ if (Array.isArray(value)) {
960
+ return value.map((item) => this.normalizeFingerprintValue(item));
961
+ }
962
+ if (!value || typeof value !== "object")
963
+ return value ?? "";
964
+ return Object.keys(value).sort().reduce((result, key) => {
965
+ result[key] = this.normalizeFingerprintValue(value[key]);
966
+ return result;
967
+ }, {});
968
+ }
969
+ buildProductFingerprintItem(product) {
970
+ const sku = (product == null ? void 0 : product.product_sku) || {};
971
+ const metadata = (product == null ? void 0 : product.metadata) || {};
972
+ const discountTypes = ((product == null ? void 0 : product.discount_list) || []).map((discount) => (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag));
973
+ const extensionType = (product == null ? void 0 : product.extension_type) || (discountTypes.includes("good_pass") ? "good_pass" : "normal");
974
+ return {
975
+ product_id: (product == null ? void 0 : product.product_id) ?? null,
976
+ product_variant_id: (product == null ? void 0 : product.product_variant_id) ?? null,
977
+ extension_type: extensionType,
978
+ num: (0, import_utils3.getSafeProductNum)((product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity)),
979
+ selling_price: this.normalizeFingerprintMoney(product == null ? void 0 : product.selling_price),
980
+ original_price: this.normalizeFingerprintMoney(product == null ? void 0 : product.original_price),
981
+ payment_price: this.normalizeFingerprintMoney((product == null ? void 0 : product.payment_price) ?? (product == null ? void 0 : product.selling_price)),
982
+ metadata: {
983
+ source_product_price: this.normalizeFingerprintMoney(metadata.source_product_price),
984
+ main_product_selling_price: this.normalizeFingerprintMoney(metadata.main_product_selling_price),
985
+ main_product_original_price: this.normalizeFingerprintMoney(metadata.main_product_original_price),
986
+ product_discount_difference: this.normalizeFingerprintMoney(metadata.product_discount_difference)
987
+ },
988
+ product_sku: this.normalizeFingerprintValue({
989
+ code: sku.code ?? "",
990
+ barcode: sku.barcode ?? "",
991
+ variant_id: sku.variant_id ?? (product == null ? void 0 : product.product_variant_id) ?? 0,
992
+ variant: sku.variant || [],
993
+ option: (0, import_utils.getProductSkuOptions)(product || {}).map((option) => ({
994
+ id: (option == null ? void 0 : option.id) ?? (option == null ? void 0 : option.option_group_item_id) ?? null,
995
+ option_group_id: (option == null ? void 0 : option.option_group_id) ?? null,
996
+ option_group_item_id: (option == null ? void 0 : option.option_group_item_id) ?? (option == null ? void 0 : option.id) ?? null,
997
+ num: Number((option == null ? void 0 : option.num) ?? 1) || 1,
998
+ add_price: this.normalizeFingerprintMoney((option == null ? void 0 : option.add_price) ?? (option == null ? void 0 : option.price))
999
+ }))
1000
+ }),
1001
+ product_bundle: this.normalizeFingerprintValue(((product == null ? void 0 : product.product_bundle) || []).map((bundle) => ({
1002
+ bundle_product_id: (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id) ?? null,
1003
+ bundle_variant_id: (bundle == null ? void 0 : bundle.bundle_variant_id) ?? (bundle == null ? void 0 : bundle.product_variant_id) ?? 0,
1004
+ num: (0, import_utils3.getSafeProductNum)((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity)),
1005
+ price: this.normalizeFingerprintMoney(bundle == null ? void 0 : bundle.price),
1006
+ bundle_selling_price: this.normalizeFingerprintMoney(bundle == null ? void 0 : bundle.bundle_selling_price),
1007
+ price_type: (bundle == null ? void 0 : bundle.price_type) ?? "",
1008
+ price_type_ext: (bundle == null ? void 0 : bundle.price_type_ext) ?? ""
1009
+ }))),
1010
+ discount_list: this.normalizeFingerprintValue(((product == null ? void 0 : product.discount_list) || []).map((discount) => {
1011
+ var _a;
1012
+ return {
1013
+ type: (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag) ?? "",
1014
+ discount_id: (discount == null ? void 0 : discount.discount_id) ?? (discount == null ? void 0 : discount.order_discount_id) ?? ((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id) ?? null,
1015
+ amount: this.normalizeFingerprintMoney(discount == null ? void 0 : discount.amount)
1016
+ };
1017
+ }))
1018
+ };
1019
+ }
1020
+ buildOrderProductsFingerprint(products) {
1021
+ const items = (products || []).map((product) => this.buildProductFingerprintItem(product));
1022
+ items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
1023
+ return JSON.stringify(items);
1024
+ }
1025
+ buildProductStructuralFingerprintItem(product) {
1026
+ const sku = (product == null ? void 0 : product.product_sku) || {};
1027
+ const metadata = (product == null ? void 0 : product.metadata) || {};
1028
+ const discountTypes = ((product == null ? void 0 : product.discount_list) || []).map((discount) => (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag));
1029
+ const extensionType = (product == null ? void 0 : product.extension_type) || (discountTypes.includes("good_pass") ? "good_pass" : "normal");
1030
+ return {
1031
+ product_id: (product == null ? void 0 : product.product_id) ?? null,
1032
+ product_variant_id: (product == null ? void 0 : product.product_variant_id) ?? null,
1033
+ extension_type: extensionType,
1034
+ num: (0, import_utils3.getSafeProductNum)((product == null ? void 0 : product.num) ?? (product == null ? void 0 : product.product_quantity)),
1035
+ metadata: {
1036
+ unique_identification_number: metadata.unique_identification_number ?? (product == null ? void 0 : product.unique_identification_number) ?? "",
1037
+ price_override: metadata.price_override ?? "",
1038
+ is_manual_discount: metadata.is_manual_discount ?? "",
1039
+ product_discount_reason: metadata.product_discount_reason ?? ""
1040
+ },
1041
+ product_sku: this.normalizeFingerprintValue({
1042
+ code: sku.code ?? "",
1043
+ barcode: sku.barcode ?? "",
1044
+ variant_id: sku.variant_id ?? (product == null ? void 0 : product.product_variant_id) ?? 0,
1045
+ variant: sku.variant || [],
1046
+ option: (0, import_utils.getProductSkuOptions)(product || {}).map((option) => ({
1047
+ id: (option == null ? void 0 : option.id) ?? (option == null ? void 0 : option.option_group_item_id) ?? null,
1048
+ option_group_id: (option == null ? void 0 : option.option_group_id) ?? null,
1049
+ option_group_item_id: (option == null ? void 0 : option.option_group_item_id) ?? (option == null ? void 0 : option.id) ?? null,
1050
+ num: Number((option == null ? void 0 : option.num) ?? 1) || 1,
1051
+ add_price: this.normalizeFingerprintMoney((option == null ? void 0 : option.add_price) ?? (option == null ? void 0 : option.price))
1052
+ }))
1053
+ }),
1054
+ product_bundle: this.normalizeFingerprintValue(((product == null ? void 0 : product.product_bundle) || []).map((bundle) => ({
1055
+ bundle_id: (bundle == null ? void 0 : bundle.bundle_id) ?? (bundle == null ? void 0 : bundle.id) ?? null,
1056
+ bundle_group_id: (bundle == null ? void 0 : bundle.bundle_group_id) ?? (bundle == null ? void 0 : bundle.group_id) ?? null,
1057
+ bundle_product_id: (bundle == null ? void 0 : bundle.bundle_product_id) ?? (bundle == null ? void 0 : bundle._bundle_product_id) ?? (bundle == null ? void 0 : bundle.product_id) ?? null,
1058
+ bundle_variant_id: (bundle == null ? void 0 : bundle.bundle_variant_id) ?? (bundle == null ? void 0 : bundle.product_variant_id) ?? 0,
1059
+ num: (0, import_utils3.getSafeProductNum)((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity)),
1060
+ price_type: (bundle == null ? void 0 : bundle.price_type) ?? "",
1061
+ price_type_ext: (bundle == null ? void 0 : bundle.price_type_ext) ?? "",
1062
+ option: this.normalizeFingerprintValue(((bundle == null ? void 0 : bundle.option) || []).map((option) => ({
1063
+ id: (option == null ? void 0 : option.id) ?? (option == null ? void 0 : option.option_group_item_id) ?? null,
1064
+ option_group_id: (option == null ? void 0 : option.option_group_id) ?? null,
1065
+ option_group_item_id: (option == null ? void 0 : option.option_group_item_id) ?? (option == null ? void 0 : option.id) ?? null,
1066
+ num: Number((option == null ? void 0 : option.num) ?? 1) || 1,
1067
+ add_price: this.normalizeFingerprintMoney((option == null ? void 0 : option.add_price) ?? (option == null ? void 0 : option.price))
1068
+ })))
1069
+ }))),
1070
+ discount_list: this.normalizeFingerprintValue(((product == null ? void 0 : product.discount_list) || []).map((discount) => {
1071
+ var _a;
1072
+ return {
1073
+ type: (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag) ?? "",
1074
+ discount_id: (discount == null ? void 0 : discount.discount_id) ?? (discount == null ? void 0 : discount.order_discount_id) ?? ((_a = discount == null ? void 0 : discount.discount) == null ? void 0 : _a.resource_id) ?? null,
1075
+ amount: this.normalizeFingerprintMoney(discount == null ? void 0 : discount.amount)
1076
+ };
1077
+ }))
1078
+ };
1079
+ }
1080
+ buildOrderProductsStructuralFingerprint(products) {
1081
+ const items = (products || []).map((product) => this.buildProductStructuralFingerprintItem(product));
1082
+ items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
1083
+ return JSON.stringify(items);
1084
+ }
1085
+ getOriginalSalesSnapshot(tempOrder) {
1086
+ var _a;
1087
+ const snapshot = (_a = tempOrder._extend) == null ? void 0 : _a.originalSalesSnapshot;
1088
+ if (!snapshot || typeof snapshot !== "object")
1089
+ return null;
1090
+ if (typeof snapshot.productFingerprint !== "string")
1091
+ return null;
1092
+ return snapshot;
1093
+ }
1094
+ restoreOriginalSnapshotIfProductsUnchanged(tempOrder) {
1095
+ const snapshot = this.getOriginalSalesSnapshot(tempOrder);
1096
+ if (!snapshot)
1097
+ return null;
1098
+ const currentFingerprint = this.buildOrderProductsFingerprint(tempOrder.products);
1099
+ if (currentFingerprint !== snapshot.productFingerprint) {
1100
+ const currentStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(tempOrder.products);
1101
+ const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(
1102
+ Array.isArray(snapshot.products) ? snapshot.products : []
1103
+ );
1104
+ if (currentStructuralFingerprint !== snapshotStructuralFingerprint)
1105
+ return null;
1106
+ }
1107
+ const summary = {
1108
+ ...(0, import_utils.createEmptySummary)(),
1109
+ ...(0, import_lodash_es.cloneDeep)(snapshot.summary || {})
1110
+ };
1111
+ if (Array.isArray(snapshot.products)) {
1112
+ tempOrder.products = (0, import_lodash_es.cloneDeep)(snapshot.products);
1113
+ }
1114
+ if (Array.isArray(snapshot.surcharges)) {
1115
+ tempOrder.surcharges = (0, import_lodash_es.cloneDeep)(snapshot.surcharges);
1116
+ }
1117
+ tempOrder.surcharge_fee = summary.surcharge_fee || tempOrder.surcharge_fee;
1118
+ tempOrder.deposit_amount = summary.deposit_amount || "0.00";
1119
+ tempOrder.is_deposit = summary.deposit_amount !== "0.00" ? 1 : 0;
1120
+ this.store.summary = summary;
1121
+ return summary;
1122
+ }
1123
+ clearPersistedAmountFieldsForFullRecalc(products) {
1124
+ const moneyKeys = [
1125
+ "surcharge_fee",
1126
+ "main_product_attached_bundle_surcharge_fee",
1127
+ "surcharge_rounding_remainder",
1128
+ "main_product_attached_bundle_tax_fee",
1129
+ "tax_fee",
1130
+ "original_tax_fee",
1131
+ "tax_fee_rounding_remainder",
1132
+ "original_tax_fee_rounding_remainder"
1133
+ ];
1134
+ const metadataMoneyKeys = [
1135
+ "main_product_attached_bundle_surcharge_fee",
1136
+ "surcharge_rounding_remainder",
1137
+ "main_product_attached_bundle_tax_fee",
1138
+ "tax_fee_rounding_remainder"
1139
+ ];
1140
+ for (const product of products || []) {
1141
+ const record = product;
1142
+ for (const key of moneyKeys)
1143
+ delete record[key];
1144
+ if (record.metadata && typeof record.metadata === "object") {
1145
+ record.metadata = { ...record.metadata };
1146
+ for (const key of metadataMoneyKeys)
1147
+ delete record.metadata[key];
1148
+ }
1149
+ for (const bundle of record.product_bundle || []) {
1150
+ for (const key of moneyKeys)
1151
+ delete bundle[key];
1152
+ if (bundle.metadata && typeof bundle.metadata === "object") {
1153
+ bundle.metadata = { ...bundle.metadata };
1154
+ for (const key of metadataMoneyKeys)
1155
+ delete bundle.metadata[key];
1156
+ }
1157
+ }
1158
+ }
838
1159
  }
839
1160
  getPaymentTargetAmount() {
840
1161
  const tempOrder = this.ensureTempOrder();
@@ -1092,6 +1413,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1092
1413
  if (!tempOrder)
1093
1414
  return null;
1094
1415
  this.sanitizeTempOrderProducts(tempOrder);
1416
+ const snapshotSummary = this.restoreOriginalSnapshotIfProductsUnchanged(tempOrder);
1417
+ if (snapshotSummary)
1418
+ return snapshotSummary;
1419
+ const shouldFullRecalculateFromSnapshot = Boolean(this.getOriginalSalesSnapshot(tempOrder));
1420
+ const summaryProducts = shouldFullRecalculateFromSnapshot ? (0, import_lodash_es.cloneDeep)(tempOrder.products || []) : tempOrder.products;
1421
+ if (shouldFullRecalculateFromSnapshot) {
1422
+ this.clearPersistedAmountFieldsForFullRecalc(summaryProducts || []);
1423
+ }
1095
1424
  const salesSummary = this.getSalesSummary();
1096
1425
  const existedSummary = this.store.summary || (0, import_utils.createEmptySummary)();
1097
1426
  const totalRefundAmount = existedSummary.total_refund_amount || "0.00";
@@ -1112,7 +1441,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1112
1441
  summary: emptyBaseSummary,
1113
1442
  orderPaidAmount: paidPaymentSummary.gapPaidAmount
1114
1443
  }),
1115
- pay_service_charge_amount: paidPaymentSummary.payServiceChargeAmount.toFixed(2)
1444
+ pay_service_charge_amount: paidPaymentSummary.payServiceChargeAmount.toFixed(2),
1445
+ rounding_amount: paidPaymentSummary.roundingAmount.toFixed(2)
1116
1446
  };
1117
1447
  tempOrder.surcharge_fee = emptySummary.surcharge_fee;
1118
1448
  this.store.summary = emptySummary;
@@ -1123,26 +1453,47 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1123
1453
  return this.store.summary;
1124
1454
  }
1125
1455
  const salesSummaryResult = await salesSummary.getSummary({
1126
- products: tempOrder.products,
1456
+ products: summaryProducts,
1127
1457
  isPriceIncludeTax: tempOrder.is_price_include_tax,
1128
1458
  shopDiscount: tempOrder.shop_discount
1129
1459
  });
1460
+ if (shouldFullRecalculateFromSnapshot) {
1461
+ tempOrder.products = summaryProducts;
1462
+ }
1130
1463
  this.syncSummaryProductMetadata(tempOrder.products || []);
1464
+ const roundingAmount = paidPaymentSummary.roundingAmount;
1465
+ const payServiceChargeAmount = paidPaymentSummary.payServiceChargeAmount;
1466
+ const hasSalesSummaryAmount = salesSummaryResult.expect_amount !== void 0 || salesSummaryResult.total_amount !== void 0;
1467
+ const expectAmount = hasSalesSummaryAmount ? new import_decimal.default(salesSummaryResult.expect_amount ?? salesSummaryResult.total_amount ?? 0) : null;
1468
+ const amountPaymentPatch = hasSalesSummaryAmount || !roundingAmount.eq(0) || !payServiceChargeAmount.eq(0) ? {
1469
+ rounding_amount: roundingAmount.toFixed(2),
1470
+ ...expectAmount ? {
1471
+ total_amount: import_decimal.default.max(
1472
+ 0,
1473
+ expectAmount.plus(roundingAmount).plus(payServiceChargeAmount)
1474
+ ).toFixed(2)
1475
+ } : {}
1476
+ } : {};
1477
+ const normalizedExpectAmountPatch = expectAmount && salesSummaryResult.expect_amount === void 0 ? { expect_amount: expectAmount.toFixed(2) } : {};
1131
1478
  const summaryForGap = {
1132
1479
  ...salesSummaryResult,
1133
- total_refund_amount: totalRefundAmount
1480
+ total_refund_amount: totalRefundAmount,
1481
+ ...amountPaymentPatch,
1482
+ ...normalizedExpectAmountPatch
1134
1483
  };
1135
1484
  const summary = {
1136
1485
  ...salesSummaryResult,
1137
1486
  total_refund_amount: totalRefundAmount,
1138
1487
  customer_paid_amount: paidPaymentSummary.customerPaidAmount.toFixed(2),
1139
1488
  order_paid_amount: paidPaymentSummary.orderPaidAmount.toFixed(2),
1489
+ ...amountPaymentPatch,
1490
+ ...normalizedExpectAmountPatch,
1140
1491
  amount_gap: this.calculateSummaryAmountGap({
1141
1492
  tempOrder,
1142
1493
  summary: summaryForGap,
1143
1494
  orderPaidAmount: paidPaymentSummary.gapPaidAmount
1144
1495
  }),
1145
- pay_service_charge_amount: paidPaymentSummary.payServiceChargeAmount.toFixed(2)
1496
+ pay_service_charge_amount: payServiceChargeAmount.toFixed(2)
1146
1497
  };
1147
1498
  this.store.summary = summary;
1148
1499
  if (summary.is_price_include_tax !== void 0) {
@@ -1226,6 +1577,49 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1226
1577
  email: String(source.email ?? params.email)
1227
1578
  };
1228
1579
  }
1580
+ isCustomerBoundDiscount(discount) {
1581
+ const type = (discount == null ? void 0 : discount.type) ?? (discount == null ? void 0 : discount.tag);
1582
+ return type === "good_pass" || type === "discount_card" || type === "product_discount_card";
1583
+ }
1584
+ clearCustomerBoundDiscounts(tempOrder) {
1585
+ var _a, _b, _c, _d;
1586
+ const filterDiscountList = (discountList) => {
1587
+ if (!Array.isArray(discountList))
1588
+ return [];
1589
+ return discountList.filter((discount) => !this.isCustomerBoundDiscount(discount));
1590
+ };
1591
+ tempOrder.products = (tempOrder.products || []).map((product) => {
1592
+ const nextProduct = {
1593
+ ...product,
1594
+ discount_list: filterDiscountList(product.discount_list)
1595
+ };
1596
+ if (Array.isArray(nextProduct.product_bundle)) {
1597
+ nextProduct.product_bundle = nextProduct.product_bundle.map((bundle) => ({
1598
+ ...bundle,
1599
+ discount_list: filterDiscountList(bundle.discount_list)
1600
+ }));
1601
+ }
1602
+ return nextProduct;
1603
+ });
1604
+ delete tempOrder.discount_list;
1605
+ const discountModule = this.store.discount;
1606
+ if (!discountModule)
1607
+ return;
1608
+ const currentDiscounts = ((_a = discountModule.getDiscountList) == null ? void 0 : _a.call(discountModule)) || [];
1609
+ const currentOriginalDiscounts = ((_b = discountModule.getOriginalDiscountList) == null ? void 0 : _b.call(discountModule)) || [];
1610
+ const nextDiscounts = currentDiscounts.filter((discount) => {
1611
+ if (discount == null ? void 0 : discount.isEditMode)
1612
+ return true;
1613
+ return !this.isCustomerBoundDiscount(discount);
1614
+ });
1615
+ const nextOriginalDiscounts = currentOriginalDiscounts.filter((discount) => {
1616
+ if (discount == null ? void 0 : discount.isEditMode)
1617
+ return true;
1618
+ return !this.isCustomerBoundDiscount(discount);
1619
+ });
1620
+ void ((_c = discountModule.setDiscountList) == null ? void 0 : _c.call(discountModule, nextDiscounts));
1621
+ void ((_d = discountModule.setOriginalDiscountList) == null ? void 0 : _d.call(discountModule, nextOriginalDiscounts));
1622
+ }
1229
1623
  /**
1230
1624
  * 更新当前 tempOrder 的客户协议字段。
1231
1625
  *
@@ -1234,6 +1628,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1234
1628
  */
1235
1629
  updateTempOrderCustomer(customer) {
1236
1630
  const tempOrder = this.ensureTempOrder();
1631
+ const previousCustomerId = tempOrder.customer_id ?? null;
1237
1632
  const customerId = customer.customer_id ?? customer.customerId ?? customer.id ?? null;
1238
1633
  const customerName = customer.customer_name ?? customer.customerName ?? customer.display_name ?? customer.name ?? "";
1239
1634
  tempOrder.customer_id = customerId === null || customerId === void 0 || customerId === "" ? null : Number(customerId);
@@ -1251,6 +1646,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1251
1646
  phone: tempOrder.phone,
1252
1647
  email: tempOrder.email
1253
1648
  });
1649
+ const nextCustomerId = tempOrder.customer_id ?? null;
1254
1650
  this.persistTempOrder();
1255
1651
  return {
1256
1652
  customerId: tempOrder.customer_id,
@@ -1289,6 +1685,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1289
1685
  const nextCustomerId = tempOrder.customer_id ?? null;
1290
1686
  if (String(previousCustomerId ?? "") !== String(nextCustomerId ?? "")) {
1291
1687
  (0, import_utils.clearTempOrderHolderAssignments)(tempOrder);
1688
+ this.clearCustomerBoundDiscounts(tempOrder);
1292
1689
  }
1293
1690
  this.persistTempOrder();
1294
1691
  this.saveDraftInBackground();
@@ -1325,6 +1722,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1325
1722
  tempOrder.customer = null;
1326
1723
  if (tempOrder._extend)
1327
1724
  delete tempOrder._extend.customerSnapshot;
1725
+ this.clearCustomerBoundDiscounts(tempOrder);
1328
1726
  this.persistTempOrder();
1329
1727
  this.saveDraftInBackground();
1330
1728
  this.core.effects.emit(import_types.OrderHooks.OnOrderCustomerChange, null);
@@ -1447,7 +1845,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1447
1845
  const tempOrder = this.ensureTempOrder();
1448
1846
  const mappedVouchers = (0, import_utils.mapPaymentItemsToOrderPayments)(
1449
1847
  payments.map(
1450
- (payment) => this.normalizePaymentSource(payment, { defaultPaid: false })
1848
+ (payment) => this.normalizePaymentSource(payment, { defaultPaid: true })
1451
1849
  )
1452
1850
  ).filter((payment) => {
1453
1851
  return payment.voucher_id !== void 0 && Number(payment.voucher_id) !== 0;
@@ -1610,6 +2008,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1610
2008
  if (linked) {
1611
2009
  tempOrder.bookings = [...tempOrder.bookings || [], linked.booking];
1612
2010
  }
2011
+ await this.ensureEditDiscountConfigForProductChange(tempOrder);
1613
2012
  await this.applyPromotion();
1614
2013
  this.applyDiscount();
1615
2014
  this.sanitizeTempOrderProducts(tempOrder);
@@ -1635,6 +2034,44 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1635
2034
  (item) => (item == null ? void 0 : item.type) === "good_pass" || (item == null ? void 0 : item.tag) === "good_pass"
1636
2035
  );
1637
2036
  }
2037
+ getBundleRuntimeIdentity(bundle) {
2038
+ if (!bundle || typeof bundle !== "object")
2039
+ return "";
2040
+ return [
2041
+ bundle.bundle_id ?? bundle.id ?? "",
2042
+ bundle.bundle_group_id ?? bundle.group_id ?? "",
2043
+ bundle.bundle_product_id ?? bundle._bundle_product_id ?? bundle.product_id ?? "",
2044
+ bundle.bundle_variant_id ?? bundle.product_variant_id ?? 0
2045
+ ].join("|");
2046
+ }
2047
+ preservePersistedBundlePriceFields(previousBundles, nextBundles) {
2048
+ if (!Array.isArray(nextBundles))
2049
+ return nextBundles;
2050
+ if (!Array.isArray(previousBundles) || previousBundles.length === 0)
2051
+ return nextBundles;
2052
+ const previousByIdentity = /* @__PURE__ */ new Map();
2053
+ previousBundles.forEach((bundle) => {
2054
+ const identity = this.getBundleRuntimeIdentity(bundle);
2055
+ if (identity)
2056
+ previousByIdentity.set(identity, bundle);
2057
+ });
2058
+ return nextBundles.map((bundle, index) => {
2059
+ if (!bundle || typeof bundle !== "object")
2060
+ return bundle;
2061
+ const previous = previousByIdentity.get(this.getBundleRuntimeIdentity(bundle)) || previousBundles[index];
2062
+ if (!previous || typeof previous !== "object")
2063
+ return bundle;
2064
+ return {
2065
+ ...bundle,
2066
+ price: previous.price,
2067
+ custom_price: previous.custom_price,
2068
+ bundle_payment_price: previous.bundle_payment_price,
2069
+ bundle_selling_price: previous.bundle_selling_price,
2070
+ original_price: previous.original_price,
2071
+ product_price: previous.product_price
2072
+ };
2073
+ });
2074
+ }
1638
2075
  async updateOrderProduct(params) {
1639
2076
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
1640
2077
  const {
@@ -1715,6 +2152,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1715
2152
  main_product_original_price: (_k = targetProduct.metadata) == null ? void 0 : _k.main_product_original_price,
1716
2153
  price_schema_version: ((_l = targetProduct.metadata) == null ? void 0 : _l.price_schema_version) ?? 2
1717
2154
  };
2155
+ nextProduct.product_bundle = this.preservePersistedBundlePriceFields(
2156
+ targetProduct.product_bundle,
2157
+ nextProduct.product_bundle
2158
+ );
1718
2159
  } else if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
1719
2160
  const existedMeta = nextProduct.metadata || {};
1720
2161
  nextProduct.metadata = { ...existedMeta };
@@ -2380,11 +2821,25 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2380
2821
  * 例如数组字段、商品行唯一值、价格 metadata、summary 派生状态和 _extend。
2381
2822
  */
2382
2823
  async hydrateTempOrderFromRecord(record, options) {
2824
+ var _a, _b;
2383
2825
  const raw = record && typeof record === "object" && record.data && record.order_id == null ? record.data : record || {};
2384
2826
  const nextTempOrder = this.normalizeTempOrderForRuntime(raw);
2385
2827
  this.store.tempOrder = nextTempOrder;
2386
2828
  this.store.summary = raw.summary && typeof raw.summary === "object" ? { ...(0, import_utils.createEmptySummary)(), ...raw.summary } : (0, import_utils.createEmptySummary)();
2829
+ nextTempOrder._extend = {
2830
+ ...nextTempOrder._extend || {},
2831
+ originalSalesSnapshot: {
2832
+ summary: (0, import_lodash_es.cloneDeep)(this.store.summary),
2833
+ products: (0, import_lodash_es.cloneDeep)(nextTempOrder.products || []),
2834
+ payments: (0, import_lodash_es.cloneDeep)(nextTempOrder.payments || []),
2835
+ surcharges: (0, import_lodash_es.cloneDeep)(nextTempOrder.surcharges || []),
2836
+ productFingerprint: this.buildOrderProductsFingerprint(nextTempOrder.products || [])
2837
+ }
2838
+ };
2387
2839
  this.store.lastOrderInfo = raw.lastOrderInfo || raw;
2840
+ const hydratedEditDiscounts = this.collectHydratedEditDiscounts(nextTempOrder.products);
2841
+ await ((_a = this.store.discount) == null ? void 0 : _a.setOriginalDiscountList(hydratedEditDiscounts));
2842
+ await ((_b = this.store.discount) == null ? void 0 : _b.setDiscountList(hydratedEditDiscounts));
2388
2843
  if (options == null ? void 0 : options.recalcOnHydrate) {
2389
2844
  await this.recalculateSummary({ createIfMissing: false });
2390
2845
  }
@@ -296,18 +296,22 @@ var WalletPassPaymentImpl = class {
296
296
  return (0, import_utils.formatWalletPassList2PreparePayments)(list);
297
297
  }
298
298
  async getUserIdentificationCodeListAsync(params) {
299
- var _a, _b;
299
+ var _a, _b, _c;
300
300
  try {
301
301
  const newParams = {
302
302
  ...this.walletParams,
303
303
  ...params
304
304
  };
305
+ if (!((_a = newParams.products) == null ? void 0 : _a.length)) {
306
+ this.paymentModule.logInfo("[WalletPass] 商品列表为空,跳过获取用户识别码列表");
307
+ return [];
308
+ }
305
309
  this.paymentModule.logInfo("[WalletPass] 开始获取用户识别码列表", {
306
310
  customer_id: newParams.customer_id,
307
311
  available: newParams.available,
308
- prepare_payments_count: ((_a = newParams.prepare_payments) == null ? void 0 : _a.length) || 0,
312
+ prepare_payments_count: ((_b = newParams.prepare_payments) == null ? void 0 : _b.length) || 0,
309
313
  filter_prepare_wallet_pass: newParams.filter_prepare_wallet_pass,
310
- payment_order_id: (_b = this.walletParams) == null ? void 0 : _b.payment_order_id
314
+ payment_order_id: (_c = this.walletParams) == null ? void 0 : _c.payment_order_id
311
315
  });
312
316
  const response = await this.paymentModule.request.post(
313
317
  "/machinecode/prepare/deduction",