@pisell/pisellos 2.3.33 → 2.3.35

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 (33) hide show
  1. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
  2. package/dist/modules/BookingContext/utils/cacheItemToBookingInput.js +32 -1
  3. package/dist/modules/Order/index.d.ts +1 -1
  4. package/dist/modules/Order/index.js +84 -34
  5. package/dist/modules/Order/payment-utils.d.ts +3 -0
  6. package/dist/modules/Order/payment-utils.js +25 -3
  7. package/dist/modules/Order/utils/orderCollectionIdentity.js +7 -2
  8. package/dist/server/index.d.ts +2 -0
  9. package/dist/server/index.js +73 -10
  10. package/dist/server/modules/order/index.d.ts +4 -1
  11. package/dist/server/modules/order/index.js +108 -18
  12. package/dist/solution/BaseSales/index.js +10 -1
  13. package/dist/solution/BaseSales/utils/cartPromotion.js +19 -7
  14. package/dist/solution/BookingByStep/index.d.ts +1 -1
  15. package/dist/solution/Sales/index.d.ts +1 -0
  16. package/dist/solution/Sales/index.js +10 -2
  17. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.d.ts +1 -1
  18. package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +23 -2
  19. package/lib/modules/Order/index.d.ts +1 -1
  20. package/lib/modules/Order/index.js +75 -11
  21. package/lib/modules/Order/payment-utils.d.ts +3 -0
  22. package/lib/modules/Order/payment-utils.js +33 -2
  23. package/lib/modules/Order/utils/orderCollectionIdentity.js +3 -0
  24. package/lib/server/index.d.ts +2 -0
  25. package/lib/server/index.js +60 -10
  26. package/lib/server/modules/order/index.d.ts +4 -1
  27. package/lib/server/modules/order/index.js +89 -10
  28. package/lib/solution/BaseSales/index.js +9 -0
  29. package/lib/solution/BaseSales/utils/cartPromotion.js +13 -1
  30. package/lib/solution/BookingByStep/index.d.ts +1 -1
  31. package/lib/solution/Sales/index.d.ts +1 -0
  32. package/lib/solution/Sales/index.js +5 -3
  33. package/package.json +1 -1
@@ -485,7 +485,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
485
485
  generateIdempotencyToken(): string;
486
486
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
487
487
  createOrder(params: CommitOrderParams['query']): {
488
- type: "appointment_booking" | "virtual";
488
+ type: "virtual" | "appointment_booking";
489
489
  platform: string;
490
490
  sales_channel: string;
491
491
  order_sales_channel: string;
@@ -2872,12 +2872,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2872
2872
  const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
2873
2873
  const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingBookingUid;
2874
2874
  const matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex((item) => {
2875
+ var _a2;
2875
2876
  if (this.hasGoodPassDiscount(item))
2876
2877
  return false;
2877
2878
  if (this.hasOrderProductLineNote(item))
2878
2879
  return false;
2879
2880
  if (item.order_detail_id !== void 0 && item.order_detail_id !== null)
2880
2881
  return false;
2882
+ if ((_a2 = item.metadata) == null ? void 0 : _a2.is_edit_for_runtime)
2883
+ return false;
2881
2884
  if (item.product_id !== productToAdd.product_id)
2882
2885
  return false;
2883
2886
  if (item.product_variant_id !== productToAdd.product_variant_id)
@@ -3119,7 +3122,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3119
3122
  });
3120
3123
  }
3121
3124
  applyOrderProductUpdateToTempOrder(tempOrder, params) {
3122
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
3125
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
3123
3126
  const {
3124
3127
  product_id,
3125
3128
  product_variant_id,
@@ -3183,9 +3186,22 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3183
3186
  nextProduct.num = (0, import_utils3.getSafeProductNum)(nextProduct.num);
3184
3187
  const callerUpdatesTopPrice = Object.prototype.hasOwnProperty.call(updates || {}, "selling_price") || Object.prototype.hasOwnProperty.call(updates || {}, "original_price");
3185
3188
  const callerUpdatesMainMeta = ((_c = updates == null ? void 0 : updates.metadata) == null ? void 0 : _c.main_product_selling_price) !== void 0 || ((_d = updates == null ? void 0 : updates.metadata) == null ? void 0 : _d.main_product_original_price) !== void 0 || ((_e = updates == null ? void 0 : updates.metadata) == null ? void 0 : _e.source_product_price) !== void 0;
3189
+ const callerUpdatesSourcePrice = ((_f = updates == null ? void 0 : updates.metadata) == null ? void 0 : _f.source_product_price) !== void 0;
3190
+ const callerUpdatesMainSellingPrice = ((_g = updates == null ? void 0 : updates.metadata) == null ? void 0 : _g.main_product_selling_price) !== void 0;
3191
+ const callerUpdatesMainOriginalPrice = ((_h = updates == null ? void 0 : updates.metadata) == null ? void 0 : _h.main_product_original_price) !== void 0;
3192
+ const previousLineFingerprint = (0, import_utils3.buildProductLineFingerprint)(
3193
+ (0, import_utils.getProductSkuOptions)(targetProduct),
3194
+ targetProduct.product_bundle
3195
+ );
3196
+ const nextLineFingerprint = (0, import_utils3.buildProductLineFingerprint)(
3197
+ (0, import_utils.getProductSkuOptions)(nextProduct),
3198
+ nextProduct.product_bundle
3199
+ );
3200
+ const callerChangesVariant = Number(product_variant_id || 0) !== Number(targetProduct.product_variant_id || 0);
3201
+ const callerChangesLineConfiguration = callerChangesVariant || previousLineFingerprint !== nextLineFingerprint;
3186
3202
  const isPersistedOrderLine = targetProduct.order_detail_id !== void 0 && targetProduct.order_detail_id !== null;
3187
3203
  const callerChangesDiscountList = Array.isArray(updates == null ? void 0 : updates.discount_list) && updates.discount_list.length > 0 && !isSameDiscountList(updates.discount_list, targetProduct.discount_list);
3188
- const callerUpdatesManualPrice = ((_f = updates == null ? void 0 : updates.metadata) == null ? void 0 : _f.price_override) !== void 0 || ((_g = updates == null ? void 0 : updates.metadata) == null ? void 0 : _g.is_manual_discount) !== void 0 || ((_h = updates == null ? void 0 : updates.metadata) == null ? void 0 : _h.product_discount_reason) !== void 0 || callerChangesDiscountList;
3204
+ const callerUpdatesManualPrice = ((_i = updates == null ? void 0 : updates.metadata) == null ? void 0 : _i.price_override) !== void 0 || ((_j = updates == null ? void 0 : updates.metadata) == null ? void 0 : _j.is_manual_discount) !== void 0 || ((_k = updates == null ? void 0 : updates.metadata) == null ? void 0 : _k.product_discount_reason) !== void 0 || callerChangesDiscountList;
3189
3205
  const callerAllowsBookingReprice = (() => {
3190
3206
  if (params.allow_booking_reprice !== true || !booking || !callerUpdatesTopPrice || !callerUpdatesMainMeta) {
3191
3207
  return false;
@@ -3200,21 +3216,69 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3200
3216
  };
3201
3217
  return hasChangedPrice(updates.selling_price, targetProduct.selling_price) || hasChangedPrice(updates.original_price, targetProduct.original_price);
3202
3218
  })();
3203
- if (isPersistedOrderLine && !callerUpdatesManualPrice && !callerAllowsBookingReprice) {
3219
+ if (isPersistedOrderLine && !callerChangesLineConfiguration && !callerUpdatesManualPrice && !callerAllowsBookingReprice) {
3204
3220
  nextProduct.selling_price = targetProduct.selling_price;
3205
3221
  nextProduct.original_price = targetProduct.original_price;
3206
3222
  nextProduct.payment_price = targetProduct.payment_price;
3207
3223
  nextProduct.metadata = {
3208
3224
  ...nextProduct.metadata || {},
3209
- source_product_price: (_i = targetProduct.metadata) == null ? void 0 : _i.source_product_price,
3210
- main_product_selling_price: (_j = targetProduct.metadata) == null ? void 0 : _j.main_product_selling_price,
3211
- main_product_original_price: (_k = targetProduct.metadata) == null ? void 0 : _k.main_product_original_price,
3212
- price_schema_version: ((_l = targetProduct.metadata) == null ? void 0 : _l.price_schema_version) ?? 2
3225
+ source_product_price: (_l = targetProduct.metadata) == null ? void 0 : _l.source_product_price,
3226
+ main_product_selling_price: (_m = targetProduct.metadata) == null ? void 0 : _m.main_product_selling_price,
3227
+ main_product_original_price: (_n = targetProduct.metadata) == null ? void 0 : _n.main_product_original_price,
3228
+ price_schema_version: ((_o = targetProduct.metadata) == null ? void 0 : _o.price_schema_version) ?? 2
3213
3229
  };
3214
3230
  nextProduct.product_bundle = this.preservePersistedBundlePriceFields(
3215
3231
  targetProduct.product_bundle,
3216
3232
  nextProduct.product_bundle
3217
3233
  );
3234
+ } else if (callerChangesLineConfiguration && callerUpdatesSourcePrice && (!callerUpdatesMainSellingPrice || !callerUpdatesMainOriginalPrice)) {
3235
+ const previousMainOriginal = new import_decimal.default(
3236
+ Number((_p = targetProduct.metadata) == null ? void 0 : _p.main_product_original_price) || 0
3237
+ );
3238
+ const previousMainSelling = new import_decimal.default(
3239
+ Number((_q = targetProduct.metadata) == null ? void 0 : _q.main_product_selling_price) || previousMainOriginal.toNumber()
3240
+ );
3241
+ const preservedDiscount = previousMainOriginal.minus(previousMainSelling);
3242
+ const nextMainOriginal = new import_decimal.default(
3243
+ Number(updates.metadata.source_product_price) || 0
3244
+ ).plus((0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(nextProduct)));
3245
+ nextProduct.metadata = {
3246
+ ...nextProduct.metadata || {},
3247
+ source_product_price: String(updates.metadata.source_product_price),
3248
+ main_product_original_price: callerUpdatesMainOriginalPrice ? String(updates.metadata.main_product_original_price) : nextMainOriginal.toDecimalPlaces(2).toFixed(2),
3249
+ main_product_selling_price: callerUpdatesMainSellingPrice ? String(updates.metadata.main_product_selling_price) : nextMainOriginal.minus(preservedDiscount).toDecimalPlaces(2).toFixed(2),
3250
+ price_schema_version: 2
3251
+ };
3252
+ } else if (callerChangesVariant && !callerUpdatesTopPrice && !callerUpdatesMainMeta) {
3253
+ const existedMeta = nextProduct.metadata || {};
3254
+ nextProduct.metadata = { ...existedMeta };
3255
+ delete nextProduct.metadata.source_product_price;
3256
+ delete nextProduct.metadata.main_product_selling_price;
3257
+ delete nextProduct.metadata.main_product_original_price;
3258
+ delete nextProduct.metadata.price_schema_version;
3259
+ } else if (callerChangesLineConfiguration && !callerUpdatesTopPrice && !callerUpdatesMainMeta) {
3260
+ const previousOptionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(targetProduct));
3261
+ const nextOptionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(nextProduct));
3262
+ const previousMainOriginal = new import_decimal.default(
3263
+ Number(
3264
+ ((_r = targetProduct.metadata) == null ? void 0 : _r.main_product_original_price) ?? targetProduct.original_price ?? 0
3265
+ ) || 0
3266
+ );
3267
+ const previousMainSelling = new import_decimal.default(
3268
+ Number(
3269
+ ((_s = targetProduct.metadata) == null ? void 0 : _s.main_product_selling_price) ?? targetProduct.selling_price ?? previousMainOriginal.toNumber()
3270
+ ) || 0
3271
+ );
3272
+ const preservedDiscount = previousMainOriginal.minus(previousMainSelling);
3273
+ const previousSource = ((_t = targetProduct.metadata) == null ? void 0 : _t.source_product_price) != null ? new import_decimal.default(Number(targetProduct.metadata.source_product_price) || 0) : previousMainOriginal.minus(previousOptionSum);
3274
+ const nextMainOriginal = previousSource.plus(nextOptionSum);
3275
+ nextProduct.metadata = {
3276
+ ...nextProduct.metadata || {},
3277
+ source_product_price: previousSource.toDecimalPlaces(2).toFixed(2),
3278
+ main_product_original_price: nextMainOriginal.toDecimalPlaces(2).toFixed(2),
3279
+ main_product_selling_price: nextMainOriginal.minus(preservedDiscount).toDecimalPlaces(2).toFixed(2),
3280
+ price_schema_version: 2
3281
+ };
3218
3282
  } else if (callerUpdatesTopPrice && !callerUpdatesMainMeta) {
3219
3283
  const existedMeta = nextProduct.metadata || {};
3220
3284
  nextProduct.metadata = { ...existedMeta };
@@ -3230,7 +3294,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3230
3294
  normalizedProduct.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
3231
3295
  normalizedProduct.discount_list
3232
3296
  );
3233
- const preservedBookingUid = nextProduct.booking_uid || ((_m = nextProduct.metadata) == null ? void 0 : _m.booking_uid) || targetProduct.booking_uid || ((_n = targetProduct.metadata) == null ? void 0 : _n.booking_uid);
3297
+ const preservedBookingUid = nextProduct.booking_uid || ((_u = nextProduct.metadata) == null ? void 0 : _u.booking_uid) || targetProduct.booking_uid || ((_v = targetProduct.metadata) == null ? void 0 : _v.booking_uid);
3234
3298
  if (!booking && preservedBookingUid) {
3235
3299
  normalizedProduct.booking_uid = preservedBookingUid;
3236
3300
  normalizedProduct.metadata = {
@@ -3240,7 +3304,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3240
3304
  }
3241
3305
  if (booking) {
3242
3306
  const productUid = String(
3243
- ((_o = normalizedProduct.metadata) == null ? void 0 : _o.unique_identification_number) || ((_p = targetProduct.metadata) == null ? void 0 : _p.unique_identification_number) || unique_identification_number || (0, import_utils.createUuidV4)()
3307
+ ((_w = normalizedProduct.metadata) == null ? void 0 : _w.unique_identification_number) || ((_x = targetProduct.metadata) == null ? void 0 : _x.unique_identification_number) || unique_identification_number || (0, import_utils.createUuidV4)()
3244
3308
  );
3245
3309
  normalizedProduct.metadata = {
3246
3310
  ...normalizedProduct.metadata || {},
@@ -3271,9 +3335,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3271
3335
  tempOrder,
3272
3336
  updates,
3273
3337
  tempOrder.products[productIndex],
3274
- (_q = tempOrder.products[productIndex].metadata) == null ? void 0 : _q.unique_identification_number
3338
+ (_y = tempOrder.products[productIndex].metadata) == null ? void 0 : _y.unique_identification_number
3275
3339
  );
3276
- return (_r = tempOrder.products[productIndex].metadata) == null ? void 0 : _r.unique_identification_number;
3340
+ return (_z = tempOrder.products[productIndex].metadata) == null ? void 0 : _z.unique_identification_number;
3277
3341
  }
3278
3342
  async updateOrderProduct(params) {
3279
3343
  const tempOrder = this.ensureTempOrder();
@@ -10,6 +10,8 @@ export interface OrderPaymentIdentityMatch<T> {
10
10
  matchedBy: OrderPaymentIdentityType;
11
11
  }
12
12
  export declare function getOrderPaymentIdentityKeys(payment: unknown): string[];
13
+ export declare function isPendingOrderPayment(payment: unknown): boolean;
14
+ export declare function isIdentifiedPendingOrderPayment(payment: unknown): boolean;
13
15
  export declare function hasOrderPaymentIdentityOverlap(left: unknown, right: unknown): boolean;
14
16
  export declare function resolveOrderPaymentIdentity<T extends Record<string, any>>(payments: T[] | null | undefined, identity: string | number, mode?: 'payment_number' | 'compat'): OrderPaymentIdentityMatch<T> | null;
15
17
  export declare function ensureOrderPaymentNumber<T extends Record<string, any>>(payment: T, devicePrefix: string, createPaymentNumber: () => string): T & {
@@ -20,4 +22,5 @@ export declare function mergeOrderPaymentRecord<T extends Record<string, any>>(p
20
22
  export declare function mergeOrderPaymentSnapshot<T extends Record<string, any>>(current: T, incoming: T): T;
21
23
  export declare function mergeOrderPaymentListsByIdentity<T extends Record<string, any>>(existing: T[] | null | undefined, incoming: T[] | null | undefined, options?: {
22
24
  preserveUnmatchedExisting?: boolean;
25
+ preserveUnmatchedExistingWhen?: (payment: T) => boolean;
23
26
  }): T[];
@@ -22,6 +22,8 @@ __export(payment_utils_exports, {
22
22
  ensureOrderPaymentNumber: () => ensureOrderPaymentNumber,
23
23
  getOrderPaymentIdentityKeys: () => getOrderPaymentIdentityKeys,
24
24
  hasOrderPaymentIdentityOverlap: () => hasOrderPaymentIdentityOverlap,
25
+ isIdentifiedPendingOrderPayment: () => isIdentifiedPendingOrderPayment,
26
+ isPendingOrderPayment: () => isPendingOrderPayment,
25
27
  mergeOrderPaymentListsByIdentity: () => mergeOrderPaymentListsByIdentity,
26
28
  mergeOrderPaymentRecord: () => mergeOrderPaymentRecord,
27
29
  mergeOrderPaymentSnapshot: () => mergeOrderPaymentSnapshot,
@@ -55,6 +57,13 @@ function getOrderPaymentIdentityKeys(payment) {
55
57
  return value === null ? [] : [`${type}:${value}`];
56
58
  });
57
59
  }
60
+ function isPendingOrderPayment(payment) {
61
+ const record = payment;
62
+ return String((record == null ? void 0 : record.status) || "").toLowerCase() === "payment_pending";
63
+ }
64
+ function isIdentifiedPendingOrderPayment(payment) {
65
+ return isPendingOrderPayment(payment) && getOrderPaymentIdentityKeys(payment).length > 0;
66
+ }
58
67
  function hasOrderPaymentIdentityOverlap(left, right) {
59
68
  const leftKeys = new Set(getOrderPaymentIdentityKeys(left));
60
69
  if (leftKeys.size === 0)
@@ -131,6 +140,19 @@ function mergeOrderPaymentRecord(payment, updates) {
131
140
  function mergeOrderPaymentSnapshot(current, incoming) {
132
141
  const currentMetadata = current.metadata || {};
133
142
  const incomingMetadata = incoming.metadata || {};
143
+ const currentUniquePaymentNumber = normalizePaymentIdentityValue(
144
+ currentMetadata.unique_payment_number
145
+ );
146
+ const incomingUniquePaymentNumber = normalizePaymentIdentityValue(
147
+ incomingMetadata.unique_payment_number
148
+ );
149
+ const incomingOrderPaymentId = normalizePaymentIdentityValue(
150
+ incoming.order_payment_id
151
+ );
152
+ const incomingFallbackPrefix = incomingOrderPaymentId ? `os-fallback:payment:order-payment:${incomingOrderPaymentId}` : null;
153
+ const incomingUsesDerivedUniquePaymentNumber = Boolean(
154
+ incomingUniquePaymentNumber && incomingFallbackPrefix && (incomingUniquePaymentNumber === incomingFallbackPrefix || incomingUniquePaymentNumber.startsWith(`${incomingFallbackPrefix}:conflict:`))
155
+ );
134
156
  const transactions = mergeOrderPaymentTransactions(
135
157
  currentMetadata.transactions,
136
158
  incomingMetadata.transactions
@@ -138,10 +160,12 @@ function mergeOrderPaymentSnapshot(current, incoming) {
138
160
  return {
139
161
  ...current,
140
162
  ...incoming,
163
+ order_payment_id: normalizePaymentIdentityValue(incoming.order_payment_id) !== null ? incoming.order_payment_id : current.order_payment_id,
141
164
  payment_number: incoming.payment_number || current.payment_number,
142
165
  metadata: {
143
166
  ...currentMetadata,
144
167
  ...incomingMetadata,
168
+ ...incomingUsesDerivedUniquePaymentNumber && currentUniquePaymentNumber ? { unique_payment_number: currentUniquePaymentNumber } : {},
145
169
  ...transactions.length > 0 ? { transactions } : {}
146
170
  }
147
171
  };
@@ -172,19 +196,26 @@ function mergeOrderPaymentListsByIdentity(existing, incoming, options = {}) {
172
196
  if (options.preserveUnmatchedExisting) {
173
197
  return compactOrderPaymentList([...existingList, ...incomingList]);
174
198
  }
175
- return compactOrderPaymentList(incomingList.map((incomingPayment) => {
199
+ const mergedIncoming = incomingList.map((incomingPayment) => {
176
200
  const matchingExisting = existingList.filter((existingPayment) => hasOrderPaymentIdentityOverlap(existingPayment, incomingPayment));
177
201
  return matchingExisting.reduce(
178
202
  (merged, existingPayment) => mergeOrderPaymentSnapshot(existingPayment, merged),
179
203
  incomingPayment
180
204
  );
181
- }));
205
+ });
206
+ const preservedExisting = options.preserveUnmatchedExistingWhen ? existingList.filter((existingPayment) => {
207
+ var _a;
208
+ return !incomingList.some((incomingPayment) => hasOrderPaymentIdentityOverlap(existingPayment, incomingPayment)) && ((_a = options.preserveUnmatchedExistingWhen) == null ? void 0 : _a.call(options, existingPayment));
209
+ }) : [];
210
+ return compactOrderPaymentList([...mergedIncoming, ...preservedExisting]);
182
211
  }
183
212
  // Annotate the CommonJS export names for ESM import in node:
184
213
  0 && (module.exports = {
185
214
  ensureOrderPaymentNumber,
186
215
  getOrderPaymentIdentityKeys,
187
216
  hasOrderPaymentIdentityOverlap,
217
+ isIdentifiedPendingOrderPayment,
218
+ isPendingOrderPayment,
188
219
  mergeOrderPaymentListsByIdentity,
189
220
  mergeOrderPaymentRecord,
190
221
  mergeOrderPaymentSnapshot,
@@ -220,6 +220,9 @@ function normalizeOrderCollection(kind, items, options) {
220
220
  const persistentId = getOrderCollectionPersistentId(kind, item);
221
221
  let uid = getOrderCollectionUid(kind, item);
222
222
  if (!uid) {
223
+ if (kind === "payment" && !isBlankOrderCollectionIdentity(item == null ? void 0 : item.payment_number)) {
224
+ continue;
225
+ }
223
226
  uid = persistentId ? buildOrderCollectionFallbackUid(kind, persistentId) : allocateAnonymousUid(occupiedUids, createAnonymousUid);
224
227
  item = setOrderCollectionUid(kind, item, uid);
225
228
  result[index] = item;
@@ -121,6 +121,8 @@ declare class Server {
121
121
  private handleSyncSalesTask;
122
122
  private runCheckoutSync;
123
123
  private omitCheckoutSyncMode;
124
+ private buildRemoteCheckoutData;
125
+ private mergeCheckoutSyncPayments;
124
126
  private persistSyncedCheckoutOrder;
125
127
  /**
126
128
  * 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
@@ -35,6 +35,7 @@ __export(server_exports, {
35
35
  module.exports = __toCommonJS(server_exports);
36
36
  var import_dayjs = __toESM(require("dayjs"));
37
37
  var import_decimal = __toESM(require("decimal.js"));
38
+ var import_lodash_es = require("lodash-es");
38
39
  var import_products = require("./modules/products");
39
40
  var import_menu = require("./modules/menu");
40
41
  var import_quotation = require("./modules/quotation");
@@ -52,6 +53,7 @@ var import_filterOrders = require("./modules/order/utils/filterOrders");
52
53
  var import_filterBookings = require("./modules/order/utils/filterBookings");
53
54
  var import_small_ticket = require("./utils/small-ticket");
54
55
  var import_BaseSales = require("../solution/BaseSales");
56
+ var import_payment_utils = require("../modules/Order/payment-utils");
55
57
  __reExport(server_exports, require("./modules"), module.exports);
56
58
  var PRODUCT_TITLE_SNAPSHOT_KEYS = [
57
59
  "en",
@@ -1481,7 +1483,7 @@ var Server = class {
1481
1483
  const { backendPath, title } = params;
1482
1484
  const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
1483
1485
  const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
1484
- const remoteCheckoutData = this.omitCheckoutSyncMode(checkoutData);
1486
+ const remoteCheckoutData = this.buildRemoteCheckoutData(checkoutData, title);
1485
1487
  if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
1486
1488
  throw new Error("app.request 不可用");
1487
1489
  }
@@ -1497,20 +1499,20 @@ var Server = class {
1497
1499
  errorResponse: response,
1498
1500
  response,
1499
1501
  normalizedResponse: this.normalizeCheckoutResponse(response),
1500
- checkoutData: remoteCheckoutData
1502
+ checkoutData
1501
1503
  };
1502
1504
  }
1503
1505
  const fresh = this.extractOrderDataFromCheckoutResponse(response);
1504
1506
  const externalSaleNumber = this.getCheckoutExternalSaleNumber(
1505
- remoteCheckoutData,
1507
+ checkoutData,
1506
1508
  {
1507
1509
  external_sale_number: params.externalSaleNumber,
1508
- data: remoteCheckoutData
1510
+ data: checkoutData
1509
1511
  }
1510
1512
  );
1511
1513
  const syncedOrder = await this.persistSyncedCheckoutOrder({
1512
1514
  backendPath,
1513
- checkoutData: remoteCheckoutData,
1515
+ checkoutData,
1514
1516
  externalSaleNumber,
1515
1517
  fresh,
1516
1518
  title,
@@ -1521,11 +1523,11 @@ var Server = class {
1521
1523
  checkoutResponseOrder: fresh
1522
1524
  }) : void 0;
1523
1525
  if (printableSyncedOrder && this.shouldPrintSyncedOrder({
1524
- checkoutData: remoteCheckoutData,
1526
+ checkoutData,
1525
1527
  syncedOrder: printableSyncedOrder
1526
1528
  })) {
1527
1529
  await this.dispatchPrintOtherReceiptTask({
1528
- checkoutData: remoteCheckoutData,
1530
+ checkoutData,
1529
1531
  syncedOrder: printableSyncedOrder,
1530
1532
  response,
1531
1533
  deviceId: params.deviceId
@@ -1535,7 +1537,7 @@ var Server = class {
1535
1537
  rejected: false,
1536
1538
  response,
1537
1539
  normalizedResponse: this.normalizeCheckoutResponse(response),
1538
- checkoutData: remoteCheckoutData,
1540
+ checkoutData,
1539
1541
  syncedOrder,
1540
1542
  fresh
1541
1543
  };
@@ -1548,6 +1550,54 @@ var Server = class {
1548
1550
  delete next.syncMode;
1549
1551
  return next;
1550
1552
  }
1553
+ buildRemoteCheckoutData(data, title) {
1554
+ const next = (0, import_lodash_es.cloneDeep)(this.omitCheckoutSyncMode(data));
1555
+ if (!next || typeof next !== "object")
1556
+ return next;
1557
+ const record = next;
1558
+ if (!Array.isArray(record.payments))
1559
+ return next;
1560
+ const originalPayments = record.payments;
1561
+ const filteredPayments = originalPayments.filter((payment) => !(0, import_payment_utils.isPendingOrderPayment)(payment));
1562
+ const removedPayments = originalPayments.filter((payment) => (0, import_payment_utils.isPendingOrderPayment)(payment));
1563
+ record.payments = filteredPayments;
1564
+ this.logInfo(`${title}: checkout 云端支付项已过滤`, {
1565
+ external_sale_number: record.external_sale_number,
1566
+ original_payment_count: originalPayments.length,
1567
+ remote_payment_count: filteredPayments.length,
1568
+ filtered_pending_count: removedPayments.length,
1569
+ filtered_payment_identities: removedPayments.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1570
+ });
1571
+ return next;
1572
+ }
1573
+ mergeCheckoutSyncPayments(checkoutData, fresh, title) {
1574
+ const localPayments = Array.isArray(checkoutData == null ? void 0 : checkoutData.payments) ? checkoutData.payments : [];
1575
+ const freshRecord = fresh;
1576
+ if (!Array.isArray(freshRecord.payments)) {
1577
+ return localPayments.length > 0 ? { ...freshRecord, payments: (0, import_lodash_es.cloneDeep)(localPayments) } : freshRecord;
1578
+ }
1579
+ const freshPayments = freshRecord.payments;
1580
+ const mergedPayments = (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
1581
+ localPayments,
1582
+ freshPayments,
1583
+ { preserveUnmatchedExistingWhen: import_payment_utils.isIdentifiedPendingOrderPayment }
1584
+ );
1585
+ const remoteIdentityKeys = new Set(
1586
+ freshPayments.flatMap((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1587
+ );
1588
+ const preservedPending = localPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => remoteIdentityKeys.has(key)));
1589
+ if (preservedPending.length > 0) {
1590
+ this.logInfo(`${title}: checkout 响应合并保留本地 pending 支付项`, {
1591
+ external_sale_number: checkoutData == null ? void 0 : checkoutData.external_sale_number,
1592
+ preserved_pending_count: preservedPending.length,
1593
+ preserved_payment_identities: preservedPending.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1594
+ });
1595
+ }
1596
+ return {
1597
+ ...freshRecord,
1598
+ payments: mergedPayments
1599
+ };
1600
+ }
1551
1601
  async persistSyncedCheckoutOrder(params) {
1552
1602
  const {
1553
1603
  backendPath,
@@ -1562,12 +1612,12 @@ var Server = class {
1562
1612
  if (this.order && fresh && (shouldMergeRemoteOrder || persistCheckoutDataWithResponse)) {
1563
1613
  syncedOrder = persistCheckoutDataWithResponse ? {
1564
1614
  ...checkoutData,
1565
- ...fresh,
1615
+ ...this.mergeCheckoutSyncPayments(checkoutData, fresh, title),
1566
1616
  external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1567
1617
  need_sync: 0,
1568
1618
  is_draft_order: 0
1569
1619
  } : {
1570
- ...fresh,
1620
+ ...this.mergeCheckoutSyncPayments(checkoutData, fresh, title),
1571
1621
  external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
1572
1622
  need_sync: 0,
1573
1623
  is_draft_order: 0
@@ -260,6 +260,9 @@ export declare class OrderModule extends BaseModule implements Module {
260
260
  private getProductIdentityKeys;
261
261
  private mergeOrderProductLists;
262
262
  private mergeOrderPaymentLists;
263
+ private getIdentifiedPendingPayments;
264
+ private shouldProtectLocalOrderFromRemoteSnapshot;
265
+ private getUnmatchedIdentifiedPendingPayments;
263
266
  private mergeOrderRecords;
264
267
  private summarizeDuplicateOrders;
265
268
  private logDuplicateOrders;
@@ -305,7 +308,7 @@ export declare class OrderModule extends BaseModule implements Module {
305
308
  */
306
309
  private updateOrderInSQLite;
307
310
  /**
308
- * 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync 订单。
311
+ * 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync / pending 支付订单。
309
312
  * 用于 SSE 全量拉取与营业日窗口裁剪。
310
313
  *
311
314
  * @example
@@ -53,6 +53,7 @@ var ORDER_BUSINESS_WRITE_SOURCES = /* @__PURE__ */ new Set([
53
53
  "updateLocalPayment"
54
54
  ]);
55
55
  var ORDER_MERGE_SELF_CHECK = false;
56
+ var PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER = "__pisell_os_pending_payment_without_unique_number__";
56
57
  var ORDER_AUTHORITATIVE_COLLECTION_FIELDS = ["products", "bookings", "payments"];
57
58
  var ORDER_COLLECTION_KIND_BY_FIELD = {
58
59
  products: "product",
@@ -172,7 +173,35 @@ var OrderModule = class extends import_BaseModule.BaseModule {
172
173
  * 仅记录计数与订单标识,不输出商品、预约、支付或客户明细。
173
174
  */
174
175
  normalizeOrderCollectionsForIngress(order, source) {
175
- const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(order);
176
+ const sourceOrder = (0, import_lodash_es.cloneDeep)(order);
177
+ const sourceOrderRecord = sourceOrder;
178
+ if (Array.isArray(sourceOrderRecord.payments)) {
179
+ sourceOrderRecord.payments = sourceOrderRecord.payments.map((payment) => {
180
+ if (!(0, import_payment_utils.isPendingOrderPayment)(payment) || (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => key.startsWith("unique_payment_number:"))) {
181
+ return payment;
182
+ }
183
+ return {
184
+ ...payment,
185
+ [PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]: true
186
+ };
187
+ });
188
+ }
189
+ const result = (0, import_orderCollectionIdentity.normalizeOrderCollections)(sourceOrder);
190
+ const normalizedOrderRecord = result.order;
191
+ if (Array.isArray(normalizedOrderRecord.payments)) {
192
+ normalizedOrderRecord.payments = normalizedOrderRecord.payments.map(
193
+ (payment) => {
194
+ if (!(payment == null ? void 0 : payment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER]))
195
+ return payment;
196
+ const nextPayment = { ...payment };
197
+ const metadata = { ...nextPayment.metadata || {} };
198
+ delete metadata.unique_payment_number;
199
+ delete nextPayment[PENDING_PAYMENT_WITHOUT_UNIQUE_MARKER];
200
+ nextPayment.metadata = metadata;
201
+ return nextPayment;
202
+ }
203
+ );
204
+ }
176
205
  const kinds = ["product", "booking", "payment"];
177
206
  const hasChanges = kinds.some((kind) => {
178
207
  const stats = result.stats[kind];
@@ -208,9 +237,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
208
237
  /**
209
238
  * incoming 决定权威成员集合;同一持久化行仍从 existing 补齐 incoming 省略的本地展示字段。
210
239
  */
211
- mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = []) {
240
+ mergeAuthoritativeOrderCollection(field, existing, incoming, uidRemaps = [], options = {}) {
212
241
  const kind = ORDER_COLLECTION_KIND_BY_FIELD[field];
213
242
  const existingItems = Array.isArray(existing) ? existing : [];
243
+ if (field === "payments" && options.preserveIdentifiedPendingPayments) {
244
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
245
+ existingItems,
246
+ incoming,
247
+ { preserveUnmatchedExistingWhen: import_payment_utils.isIdentifiedPendingOrderPayment }
248
+ );
249
+ }
214
250
  return incoming.map((incomingItem) => {
215
251
  const existingItem = existingItems.find(
216
252
  (item) => (0, import_orderCollectionIdentity.isSameOrderCollectionItem)(kind, item, incomingItem)
@@ -695,12 +731,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
695
731
  var _a;
696
732
  let orderList = [];
697
733
  const protectedOrdersBeforeRemoteFetch = (await this.loadOrdersFromSQLite()).filter(
698
- (order) => this.isPendingSyncOrder(order) || this.isDraftOrder(order)
734
+ (order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order)
699
735
  );
700
736
  this.logInfo("loadOrdersByServer-开始", {
701
737
  hasOrderDataSource: !!this.orderDataSource,
702
738
  query: ((_a = this.store) == null ? void 0 : _a.createdAtQuery) || null,
703
- protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length
739
+ protectedLocalOrderCount: protectedOrdersBeforeRemoteFetch.length,
740
+ protectedPendingPaymentCount: protectedOrdersBeforeRemoteFetch.reduce(
741
+ (count, order) => count + this.getIdentifiedPendingPayments(order).length,
742
+ 0
743
+ )
704
744
  });
705
745
  if (this.orderDataSource) {
706
746
  try {
@@ -1745,6 +1785,21 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1745
1785
  return (0, import_lodash_es.cloneDeep)(existingList);
1746
1786
  return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(existingList, incomingList);
1747
1787
  }
1788
+ getIdentifiedPendingPayments(order) {
1789
+ const payments = Array.isArray(order == null ? void 0 : order.payments) ? order.payments : [];
1790
+ return payments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment));
1791
+ }
1792
+ shouldProtectLocalOrderFromRemoteSnapshot(order) {
1793
+ return this.isPendingSyncOrder(order) || this.isDraftOrder(order) || this.getIdentifiedPendingPayments(order).length > 0;
1794
+ }
1795
+ getUnmatchedIdentifiedPendingPayments(existing, incoming) {
1796
+ const existingPayments = Array.isArray(existing) ? existing : [];
1797
+ const incomingPayments = Array.isArray(incoming) ? incoming : [];
1798
+ const incomingIdentityKeys = new Set(
1799
+ incomingPayments.flatMap((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1800
+ );
1801
+ return existingPayments.filter((payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) && !(0, import_payment_utils.getOrderPaymentIdentityKeys)(payment).some((key) => incomingIdentityKeys.has(key)));
1802
+ }
1748
1803
  mergeOrderRecords(existing, incoming) {
1749
1804
  const preferred = this.pickPreferredOrder(existing, incoming);
1750
1805
  const secondary = preferred === existing ? incoming : existing;
@@ -1803,11 +1858,26 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1803
1858
  }
1804
1859
  for (const field of ORDER_AUTHORITATIVE_COLLECTION_FIELDS) {
1805
1860
  if (Array.isArray(incomingRecord[field])) {
1861
+ if (field === "payments") {
1862
+ const preservedPending = this.getUnmatchedIdentifiedPendingPayments(
1863
+ existingRecord[field],
1864
+ incomingRecord[field]
1865
+ );
1866
+ if (preservedPending.length > 0) {
1867
+ this.logInfo("mergeOrderRecords-保留本地 pending 支付项", {
1868
+ order_id: existing.order_id ?? incoming.order_id ?? null,
1869
+ external_sale_number: existingRecord.external_sale_number ?? incomingRecord.external_sale_number ?? null,
1870
+ preserved_pending_count: preservedPending.length,
1871
+ preserved_payment_identities: preservedPending.map((payment) => (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment))
1872
+ });
1873
+ }
1874
+ }
1806
1875
  mergedRecord[field] = this.mergeAuthoritativeOrderCollection(
1807
1876
  field,
1808
1877
  existingRecord[field],
1809
1878
  incomingRecord[field],
1810
- childUidRemaps
1879
+ childUidRemaps,
1880
+ { preserveIdentifiedPendingPayments: field === "payments" }
1811
1881
  );
1812
1882
  continue;
1813
1883
  }
@@ -2009,7 +2079,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2009
2079
  rawOrder,
2010
2080
  "mergeRemoteSnapshotWithPendingOrders.existingSQLite"
2011
2081
  );
2012
- if (!this.isPendingSyncOrder(order) && !this.isDraftOrder(order))
2082
+ if (!this.shouldProtectLocalOrderFromRemoteSnapshot(order))
2013
2083
  continue;
2014
2084
  const matchIndex = this.findOrderIndexByIdentity(merged, order);
2015
2085
  if (matchIndex >= 0) {
@@ -2170,7 +2240,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2170
2240
  }
2171
2241
  }
2172
2242
  /**
2173
- * 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync 订单。
2243
+ * 全量快照替换 orders 表(clear + bulkAdd),并保留本地 draft / need_sync / pending 支付订单。
2174
2244
  * 用于 SSE 全量拉取与营业日窗口裁剪。
2175
2245
  *
2176
2246
  * @example
@@ -2196,7 +2266,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2196
2266
  const protectedLocalOrders = protectedOrdersBeforeRemoteFetch.map((order) => this.normalizeOrderCollectionsForIngress(
2197
2267
  order,
2198
2268
  `${source}.protectedBeforeRemoteFetch`
2199
- )).filter((order) => this.isPendingSyncOrder(order) || this.isDraftOrder(order));
2269
+ )).filter((order) => this.shouldProtectLocalOrderFromRemoteSnapshot(order));
2200
2270
  for (const rawCurrentOrder of existingOrders || []) {
2201
2271
  const currentOrder = this.normalizeOrderCollectionsForIngress(
2202
2272
  rawCurrentOrder,
@@ -2206,7 +2276,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2206
2276
  protectedLocalOrders,
2207
2277
  currentOrder
2208
2278
  );
2209
- const currentNeedsProtection = this.isPendingSyncOrder(currentOrder) || this.isDraftOrder(currentOrder);
2279
+ const currentNeedsProtection = this.shouldProtectLocalOrderFromRemoteSnapshot(currentOrder);
2210
2280
  if (protectedIndex >= 0) {
2211
2281
  if (currentNeedsProtection) {
2212
2282
  protectedLocalOrders[protectedIndex] = currentOrder;
@@ -2229,7 +2299,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2229
2299
  remoteCount: remoteSnapshot.length,
2230
2300
  protectedBeforeRemoteFetchCount: protectedOrdersBeforeRemoteFetch.length,
2231
2301
  protectedLocalOrderCount: protectedLocalOrders.length,
2232
- preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length
2302
+ preservedLocalUnsyncedCount: mergedSnapshot.length - remoteSnapshot.length,
2303
+ protectedPendingPaymentCount: protectedLocalOrders.reduce(
2304
+ (count, order) => count + this.getIdentifiedPendingPayments(order).length,
2305
+ 0
2306
+ ),
2307
+ protectedPendingPaymentIdentities: protectedLocalOrders.flatMap((order) => this.getIdentifiedPendingPayments(order).map((payment) => ({
2308
+ order_id: order.order_id ?? null,
2309
+ external_sale_number: order.external_sale_number ?? null,
2310
+ payment_identities: (0, import_payment_utils.getOrderPaymentIdentityKeys)(payment)
2311
+ })))
2233
2312
  });
2234
2313
  await this.dbManager.clear(INDEXDB_STORE_NAME);
2235
2314
  this.logInfo("replaceOrdersSnapshotInSQLite-clear完成", {
@@ -157,6 +157,15 @@ function mergeBaseSalesCollectionItem(kind, currentItem, incomingItem, uidRemaps
157
157
  return kind === "product" ? mergeBaseSalesProductSnapshotFields(currentItem, mergedItem) : mergedItem;
158
158
  }
159
159
  function mergeBaseSalesOrderCollection(kind, currentValue, incomingValue, strategy, uidRemaps) {
160
+ if (kind === "payment") {
161
+ return (0, import_payment_utils.mergeOrderPaymentListsByIdentity)(
162
+ currentValue,
163
+ incomingValue,
164
+ strategy === "preserve-local" ? { preserveUnmatchedExisting: true } : {
165
+ preserveUnmatchedExistingWhen: (payment) => (0, import_payment_utils.isIdentifiedPendingOrderPayment)(payment) || !(0, import_orderCollectionIdentity.getOrderCollectionPersistentId)("payment", payment)
166
+ }
167
+ );
168
+ }
160
169
  const currentItems = (0, import_orderCollectionIdentity.normalizeOrderCollection)(kind, currentValue, {
161
170
  ensureUid: false
162
171
  }).items;