@pisell/pisellos 2.2.197 → 2.2.199

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 (45) hide show
  1. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +7 -3
  2. package/dist/modules/Cart/utils/cartProduct.js +11 -1
  3. package/dist/modules/Cart/utils/changePrice.js +11 -11
  4. package/dist/modules/Order/index.d.ts +16 -0
  5. package/dist/modules/Order/index.js +1232 -568
  6. package/dist/modules/Order/types.d.ts +1 -0
  7. package/dist/modules/Order/utils.d.ts +33 -2
  8. package/dist/modules/Order/utils.js +112 -55
  9. package/dist/modules/Payment/walletpass.js +14 -7
  10. package/dist/modules/SalesSummary/utils.js +394 -149
  11. package/dist/server/index.d.ts +3 -0
  12. package/dist/server/index.js +294 -190
  13. package/dist/server/modules/order/index.d.ts +8 -0
  14. package/dist/server/modules/order/index.js +536 -317
  15. package/dist/server/modules/order/types.d.ts +2 -0
  16. package/dist/solution/BaseSales/index.js +2 -1
  17. package/dist/solution/BaseSales/types.d.ts +1 -0
  18. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +19 -4
  19. package/dist/solution/BookingByStep/index.d.ts +1 -1
  20. package/dist/solution/ScanOrder/types.d.ts +1 -0
  21. package/dist/solution/ScanOrder/utils.js +26 -9
  22. package/dist/solution/VenueBooking/index.js +2 -1
  23. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +4 -1
  24. package/lib/modules/Cart/utils/cartProduct.js +11 -1
  25. package/lib/modules/Cart/utils/changePrice.js +12 -20
  26. package/lib/modules/Order/index.d.ts +16 -0
  27. package/lib/modules/Order/index.js +525 -18
  28. package/lib/modules/Order/types.d.ts +1 -0
  29. package/lib/modules/Order/utils.d.ts +33 -2
  30. package/lib/modules/Order/utils.js +44 -9
  31. package/lib/modules/Payment/walletpass.js +7 -3
  32. package/lib/modules/SalesSummary/utils.js +256 -46
  33. package/lib/server/index.d.ts +3 -0
  34. package/lib/server/index.js +82 -3
  35. package/lib/server/modules/order/index.d.ts +8 -0
  36. package/lib/server/modules/order/index.js +106 -4
  37. package/lib/server/modules/order/types.d.ts +2 -0
  38. package/lib/solution/BaseSales/index.js +2 -1
  39. package/lib/solution/BaseSales/types.d.ts +1 -0
  40. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +15 -1
  41. package/lib/solution/BookingByStep/index.d.ts +1 -1
  42. package/lib/solution/ScanOrder/types.d.ts +1 -0
  43. package/lib/solution/ScanOrder/utils.js +28 -10
  44. package/lib/solution/VenueBooking/index.js +2 -1
  45. package/package.json +1 -1
@@ -78,8 +78,8 @@ function getBundleUnitPrice(product, useOriginal = false) {
78
78
  const bundleItems = product.product_bundle || [];
79
79
  return bundleItems.reduce((sum, item) => {
80
80
  const quantity = getSafeNum(item == null ? void 0 : item.num);
81
- const price = useOriginal ? toDecimal((item == null ? void 0 : item.original_price) ?? (item == null ? void 0 : item.product_price) ?? (item == null ? void 0 : item.price)) : toDecimal((item == null ? void 0 : item.bundle_selling_price) ?? (item == null ? void 0 : item.price));
82
- return sum.plus(price.times(quantity));
81
+ const signedUnit = (0, import_utils2.getBundleSignedUnit)(item, { useOriginal });
82
+ return sum.plus(signedUnit.times(quantity));
83
83
  }, new import_decimal.default(0));
84
84
  }
85
85
  function getUnitPaymentTotal(product) {
@@ -107,6 +107,7 @@ function buildSurchargeServiceItems(products) {
107
107
  const quantity = getSafeNum(product.num);
108
108
  const unitTotal = getUnitPaymentTotal(product);
109
109
  const options = (0, import_utils2.getProductSkuOptions)(product);
110
+ const persistedSurchargeFee = getPersistedMainSurchargeFee(product);
110
111
  return {
111
112
  id: product.product_id,
112
113
  num: quantity,
@@ -125,7 +126,10 @@ function buildSurchargeServiceItems(products) {
125
126
  option: options,
126
127
  options,
127
128
  relation_details: [],
128
- metadata: product.metadata || {},
129
+ metadata: {
130
+ ...product.metadata || {},
131
+ __persisted_surcharge_fee: persistedSurchargeFee == null ? void 0 : persistedSurchargeFee.toFixed(2)
132
+ },
129
133
  start_date: ((_a = product.metadata) == null ? void 0 : _a.start_date) || "",
130
134
  start_time: ((_b = product.metadata) == null ? void 0 : _b.start_time) || ""
131
135
  };
@@ -133,10 +137,11 @@ function buildSurchargeServiceItems(products) {
133
137
  }
134
138
  function getRelationSurchargeIds(item) {
135
139
  var _a;
136
- const ids = (item == null ? void 0 : item.relation_surcharge_ids) ?? ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.relation_surcharge_ids);
137
- if (!Array.isArray(ids))
138
- return [];
139
- return ids.filter((id) => id !== void 0 && id !== null && id !== "");
140
+ const ids = [
141
+ ...Array.isArray(item == null ? void 0 : item.relation_surcharge_ids) ? item.relation_surcharge_ids : [],
142
+ ...Array.isArray((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.relation_surcharge_ids) ? item.metadata.relation_surcharge_ids : []
143
+ ];
144
+ return [...new Set(ids.filter((id) => id !== void 0 && id !== null && id !== ""))];
140
145
  }
141
146
  function getSurchargeConfigId(config) {
142
147
  return (config == null ? void 0 : config.id) ?? (config == null ? void 0 : config.surcharge_id);
@@ -169,6 +174,50 @@ function getBundleProductId(bundle) {
169
174
  return null;
170
175
  return parsed;
171
176
  }
177
+ function getPersistedMainSurchargeFee(product) {
178
+ var _a;
179
+ if ((product == null ? void 0 : product.order_detail_id) === void 0 || (product == null ? void 0 : product.order_detail_id) === null)
180
+ return null;
181
+ const value = (product == null ? void 0 : product.surcharge_fee) ?? (product == null ? void 0 : product.main_product_attached_bundle_surcharge_fee) ?? ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.main_product_attached_bundle_surcharge_fee);
182
+ if (value === void 0 || value === null || value === "")
183
+ return null;
184
+ return toDecimal(value);
185
+ }
186
+ function getPersistedSourceSurchargeFee(sourceItem) {
187
+ var _a;
188
+ const value = (_a = sourceItem == null ? void 0 : sourceItem.metadata) == null ? void 0 : _a.__persisted_surcharge_fee;
189
+ if (value === void 0 || value === null || value === "")
190
+ return null;
191
+ return toDecimal(value);
192
+ }
193
+ function getPersistedSurchargeRemainder(item, sourceItem) {
194
+ var _a, _b;
195
+ const value = ((_a = sourceItem == null ? void 0 : sourceItem.metadata) == null ? void 0 : _a.surcharge_rounding_remainder) ?? (item == null ? void 0 : item.surcharge_rounding_remainder) ?? ((_b = item == null ? void 0 : item.metadata) == null ? void 0 : _b.surcharge_rounding_remainder);
196
+ if (value === void 0 || value === null || value === "")
197
+ return null;
198
+ return toDecimal(value);
199
+ }
200
+ function getPersistedQuantity(item, fallbackQuantity) {
201
+ const isPersistedLine = (item == null ? void 0 : item.order_detail_id) !== void 0 && (item == null ? void 0 : item.order_detail_id) !== null;
202
+ if (!isPersistedLine)
203
+ return new import_decimal.default(0);
204
+ const value = (item == null ? void 0 : item.product_quantity) ?? (item == null ? void 0 : item.quantity);
205
+ const parsed = new import_decimal.default(value || 0);
206
+ if (parsed.lte(0))
207
+ return import_decimal.default.min(fallbackQuantity, 1);
208
+ return import_decimal.default.min(fallbackQuantity, parsed);
209
+ }
210
+ function getPersistedBundleSurchargeFee(bundle, product) {
211
+ var _a;
212
+ if ((bundle == null ? void 0 : bundle.order_detail_id) === void 0 && (product == null ? void 0 : product.order_detail_id) === void 0)
213
+ return null;
214
+ if ((bundle == null ? void 0 : bundle.order_detail_id) === null && (product == null ? void 0 : product.order_detail_id) === null)
215
+ return null;
216
+ const value = (bundle == null ? void 0 : bundle.surcharge_fee) ?? ((_a = bundle == null ? void 0 : bundle.metadata) == null ? void 0 : _a.surcharge_fee);
217
+ if (value === void 0 || value === null || value === "")
218
+ return null;
219
+ return toDecimal(value);
220
+ }
172
221
  function createSurchargeAllocationNodes(products, sourceItems) {
173
222
  var _a;
174
223
  const nodes = [];
@@ -188,7 +237,10 @@ function createSurchargeAllocationNodes(products, sourceItems) {
188
237
  productId: getBundleProductId(bundle),
189
238
  unitAmount: getBundleSurchargeUnitAmount(bundle),
190
239
  quantity: new import_decimal.default(getSafeNum((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity))).times(productQuantity),
191
- relationSurchargeIds: getRelationSurchargeIds(sourceBundle)
240
+ persistedQuantity: getPersistedQuantity(bundle, new import_decimal.default(getSafeNum((bundle == null ? void 0 : bundle.num) ?? (bundle == null ? void 0 : bundle.quantity))).times(productQuantity)),
241
+ relationSurchargeIds: getRelationSurchargeIds(sourceBundle).length ? getRelationSurchargeIds(sourceBundle) : getRelationSurchargeIds(bundle),
242
+ persistedUnitSurchargeFee: getPersistedBundleSurchargeFee(bundle, product),
243
+ persistedSurchargeRemainder: getPersistedSurchargeRemainder(bundle, sourceBundle)
192
244
  });
193
245
  }
194
246
  nodes.push({
@@ -198,7 +250,10 @@ function createSurchargeAllocationNodes(products, sourceItems) {
198
250
  productId: product.product_id ?? null,
199
251
  unitAmount: getMainSurchargeUnitAmount(product),
200
252
  quantity: productQuantity,
201
- relationSurchargeIds: getRelationSurchargeIds(sourceItem)
253
+ persistedQuantity: getPersistedQuantity(product, productQuantity),
254
+ relationSurchargeIds: getRelationSurchargeIds(sourceItem).length ? getRelationSurchargeIds(sourceItem) : getRelationSurchargeIds(product),
255
+ persistedUnitSurchargeFee: getPersistedSourceSurchargeFee(sourceItem) ?? getPersistedMainSurchargeFee(product),
256
+ persistedSurchargeRemainder: getPersistedSurchargeRemainder(product, sourceItem)
202
257
  });
203
258
  }
204
259
  return nodes;
@@ -221,6 +276,17 @@ function resetProductSurchargeFields(products) {
221
276
  }
222
277
  }
223
278
  }
279
+ function getPersistedSurchargeIds(nodes) {
280
+ const ids = /* @__PURE__ */ new Set();
281
+ for (const node of nodes) {
282
+ if (!node.persistedUnitSurchargeFee || node.persistedUnitSurchargeFee.lte(0))
283
+ continue;
284
+ for (const surchargeId of node.relationSurchargeIds) {
285
+ ids.add(surchargeId);
286
+ }
287
+ }
288
+ return ids;
289
+ }
224
290
  function buildSurchargeQuantityTotals(nodes) {
225
291
  const totals = /* @__PURE__ */ new Map();
226
292
  for (const node of nodes) {
@@ -261,6 +327,24 @@ function getBackendSurchargeState(stateMap, surchargeId, config) {
261
327
  }
262
328
  return state;
263
329
  }
330
+ function buildSurchargeResultItem(config, surchargeId, amount, index) {
331
+ const name = (config == null ? void 0 : config.name) || (config == null ? void 0 : config.label) || {};
332
+ return {
333
+ key: `custom_surcharge_${index}`,
334
+ label: name,
335
+ name,
336
+ value: amount.toNumber(),
337
+ surcharge_id: surchargeId,
338
+ description: config == null ? void 0 : config.description,
339
+ type: "default",
340
+ fixed: config == null ? void 0 : config.fixed,
341
+ amount: amount.toNumber(),
342
+ percentage: config == null ? void 0 : config.percentage,
343
+ metadata: {
344
+ open_product: config == null ? void 0 : config.open_product
345
+ }
346
+ };
347
+ }
264
348
  function applySurchargeNodeResult(node, params) {
265
349
  const { unitSurchargeFee, roundingRemainder, surchargeIds } = params;
266
350
  if (node.kind === "main") {
@@ -290,16 +374,64 @@ function calculateBackendProductSurcharges(params) {
290
374
  node.relationSurchargeIds = fallbackAllProductSurchargeIds;
291
375
  }
292
376
  }
377
+ const persistedSurchargeIds = getPersistedSurchargeIds(nodes);
293
378
  const quantityTotals = buildSurchargeQuantityTotals(nodes);
294
379
  const stateMap = /* @__PURE__ */ new Map();
295
380
  for (const node of nodes) {
296
381
  let unitSurchargeFee = new import_decimal.default(0);
297
382
  let roundingRemainder = new import_decimal.default(0);
298
383
  const appliedSurchargeIds = [];
384
+ let persistedRemainderApplied = false;
299
385
  for (const surchargeId of node.relationSurchargeIds) {
300
386
  const config = configById.get(surchargeId);
301
387
  const totalQuantity = quantityTotals.get(surchargeId) || new import_decimal.default(0);
302
- if (!config || totalQuantity.lte(0))
388
+ if (totalQuantity.lte(0))
389
+ continue;
390
+ const persistedUnitSurchargeFee = node.persistedUnitSurchargeFee;
391
+ if (persistedUnitSurchargeFee && persistedUnitSurchargeFee.gt(0)) {
392
+ const persistedQuantity = import_decimal.default.min(node.persistedQuantity, node.quantity);
393
+ const deltaQuantity = import_decimal.default.max(node.quantity.minus(persistedQuantity), 0);
394
+ const state2 = getBackendSurchargeState(
395
+ stateMap,
396
+ surchargeId,
397
+ config || { surcharge_id: surchargeId }
398
+ );
399
+ const persistedSurchargeRemainder = !persistedRemainderApplied && node.persistedSurchargeRemainder ? node.persistedSurchargeRemainder : new import_decimal.default(0);
400
+ state2.amount = bcAdd(
401
+ bcAdd(
402
+ state2.amount,
403
+ bcMul(persistedUnitSurchargeFee, persistedQuantity, 2),
404
+ 2
405
+ ),
406
+ persistedSurchargeRemainder,
407
+ 2
408
+ );
409
+ const fixed2 = new import_decimal.default((config == null ? void 0 : config.fixed) || 0);
410
+ if (fixed2.gt(0))
411
+ state2.fixedIncluded = true;
412
+ let nodeTotalSurcharge = bcAdd(
413
+ bcMul(persistedUnitSurchargeFee, persistedQuantity, 2),
414
+ persistedSurchargeRemainder,
415
+ 2
416
+ );
417
+ if (config && deltaQuantity.gt(0)) {
418
+ const percentage2 = new import_decimal.default(config.percentage || 0);
419
+ const deltaUnitPercentageFee = import_decimal.default.max(0, bcMul(node.unitAmount, percentage2, 2));
420
+ const deltaSurcharge = bcMul(deltaQuantity, deltaUnitPercentageFee, 2);
421
+ state2.amount = bcAdd(state2.amount, deltaSurcharge, 2);
422
+ nodeTotalSurcharge = bcAdd(nodeTotalSurcharge, deltaSurcharge, 2);
423
+ }
424
+ if (node.quantity.gt(0)) {
425
+ unitSurchargeFee = bcAdd(unitSurchargeFee, bcDiv(nodeTotalSurcharge, node.quantity, 2), 2);
426
+ }
427
+ if (!persistedSurchargeRemainder.eq(0)) {
428
+ roundingRemainder = bcAdd(roundingRemainder, persistedSurchargeRemainder, 2);
429
+ persistedRemainderApplied = true;
430
+ }
431
+ appliedSurchargeIds.push(surchargeId);
432
+ continue;
433
+ }
434
+ if (!config)
303
435
  continue;
304
436
  const percentage = new import_decimal.default(config.percentage || 0);
305
437
  const fixed = new import_decimal.default(config.fixed || 0);
@@ -307,7 +439,7 @@ function calculateBackendProductSurcharges(params) {
307
439
  const percentageTotalFee = bcMul(node.quantity, unitPercentageFee, 2);
308
440
  let unitFixedFee = new import_decimal.default(0);
309
441
  let fixedRemainder = new import_decimal.default(0);
310
- if (fixed.gt(0)) {
442
+ if (fixed.gt(0) && !persistedSurchargeIds.has(surchargeId)) {
311
443
  unitFixedFee = bcDiv(fixed, totalQuantity, 2);
312
444
  const distributedFixed = bcMul(unitFixedFee, totalQuantity, 2);
313
445
  fixedRemainder = bcSub(fixed, distributedFixed, 2);
@@ -328,7 +460,7 @@ function calculateBackendProductSurcharges(params) {
328
460
  6
329
461
  );
330
462
  state.calculatedQuantity = bcAdd(state.calculatedQuantity, node.quantity, 6);
331
- if (!state.fixedIncluded && fixed.gt(0)) {
463
+ if (!state.fixedIncluded && fixed.gt(0) && !persistedSurchargeIds.has(surchargeId)) {
332
464
  state.amount = bcAdd(state.amount, fixed, 2);
333
465
  state.fixedIncluded = true;
334
466
  }
@@ -351,31 +483,25 @@ function calculateBackendProductSurcharges(params) {
351
483
  surchargeIds: appliedSurchargeIds
352
484
  });
353
485
  }
354
- return (surchargeList || []).reduce((result, config, index) => {
486
+ const result = (surchargeList || []).reduce((items, config, index) => {
355
487
  const surchargeId = getSurchargeConfigId(config);
356
488
  if (surchargeId === void 0)
357
- return result;
489
+ return items;
358
490
  const state = stateMap.get(surchargeId);
359
491
  if (!state || state.amount.lte(0))
360
- return result;
361
- const name = config.name || config.label || {};
362
- result.push({
363
- key: `custom_surcharge_${index}`,
364
- label: name,
365
- name,
366
- value: state.amount.toNumber(),
367
- surcharge_id: surchargeId,
368
- description: config.description,
369
- type: "default",
370
- fixed: config.fixed,
371
- amount: state.amount.toNumber(),
372
- percentage: config.percentage,
373
- metadata: {
374
- open_product: config.open_product
375
- }
376
- });
377
- return result;
492
+ return items;
493
+ items.push(buildSurchargeResultItem(config, surchargeId, state.amount, index));
494
+ return items;
378
495
  }, []);
496
+ const includedIds = new Set(
497
+ result.map((item) => item == null ? void 0 : item.surcharge_id).filter((id) => id !== void 0)
498
+ );
499
+ for (const [surchargeId, state] of stateMap.entries()) {
500
+ if (includedIds.has(surchargeId) || state.amount.lte(0))
501
+ continue;
502
+ result.push(buildSurchargeResultItem(state.config, surchargeId, state.amount, result.length));
503
+ }
504
+ return result;
379
505
  }
380
506
  function getProductDepositData(product) {
381
507
  var _a, _b, _c;
@@ -481,20 +607,28 @@ function calculateSingleItemTax(params) {
481
607
  return new import_decimal.default(0);
482
608
  return price.dividedBy(divisor).times(rate);
483
609
  }
484
- function getMainProductPaymentTotal(product) {
610
+ function getMainAttachedBundleSellingTotal(product) {
485
611
  var _a, _b;
486
612
  const mainSelling = ((_a = product.metadata) == null ? void 0 : _a.main_product_selling_price) ?? ((_b = product.metadata) == null ? void 0 : _b.main_product_original_price) ?? 0;
487
613
  let total = toDecimal(mainSelling);
488
614
  const bundleItems = product.product_bundle || [];
489
615
  for (const bundleItem of bundleItems) {
490
616
  if (isBundleMarkupOrDiscount(bundleItem)) {
491
- const unit = toDecimal(bundleItem.bundle_selling_price ?? bundleItem.price ?? 0);
617
+ const unit = (0, import_utils2.getBundleSignedUnit)(bundleItem);
492
618
  const qty = getSafeNum(bundleItem.num ?? bundleItem.quantity);
493
619
  total = total.plus(unit.times(qty));
494
620
  }
495
621
  }
496
622
  return import_decimal.default.max(total, 0);
497
623
  }
624
+ function getMainProductPaymentTotal(product) {
625
+ var _a;
626
+ const attachedPayment = (_a = product.metadata) == null ? void 0 : _a.main_product_attached_bundle_payment_price;
627
+ if (attachedPayment !== void 0 && attachedPayment !== null && attachedPayment !== "") {
628
+ return import_decimal.default.max(toDecimal(attachedPayment), 0);
629
+ }
630
+ return getMainAttachedBundleSellingTotal(product);
631
+ }
498
632
  function getExplicitTaxRemainder(item) {
499
633
  var _a;
500
634
  const value = (item == null ? void 0 : item.tax_fee_rounding_remainder) ?? ((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.tax_fee_rounding_remainder);
@@ -508,6 +642,15 @@ function getPersistedTaxRemainder(item, parentProduct) {
508
642
  return null;
509
643
  return getExplicitTaxRemainder(item);
510
644
  }
645
+ function getPersistedMainTaxFee(product) {
646
+ var _a;
647
+ if ((product == null ? void 0 : product.order_detail_id) === void 0 || (product == null ? void 0 : product.order_detail_id) === null)
648
+ return null;
649
+ const value = ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.main_product_attached_bundle_tax_fee) ?? (product == null ? void 0 : product.main_product_attached_bundle_tax_fee) ?? (product == null ? void 0 : product.tax_fee);
650
+ if (value === void 0 || value === null || value === "")
651
+ return null;
652
+ return toDecimal(value);
653
+ }
511
654
  function writeTaxRemainder(item, roundingRemainder) {
512
655
  item.tax_fee_rounding_remainder = roundingRemainder.toNumber();
513
656
  if (item.metadata && typeof item.metadata === "object") {
@@ -517,15 +660,24 @@ function writeTaxRemainder(item, roundingRemainder) {
517
660
  function resetTaxRemainderFields(products) {
518
661
  for (const product of products) {
519
662
  const productRemainder = getPersistedTaxRemainder(product);
520
- product.tax_fee_rounding_remainder = (productRemainder == null ? void 0 : productRemainder.toNumber()) ?? 0;
663
+ if (productRemainder !== null) {
664
+ product.tax_fee_rounding_remainder = productRemainder.toNumber();
665
+ } else {
666
+ delete product.tax_fee_rounding_remainder;
667
+ }
521
668
  product.original_tax_fee_rounding_remainder = 0;
522
669
  for (const bundle of product.product_bundle || []) {
523
670
  const bundleRemainder = getPersistedTaxRemainder(bundle, product);
524
671
  bundle.metadata = {
525
- ...bundle.metadata || {},
526
- tax_fee_rounding_remainder: (bundleRemainder == null ? void 0 : bundleRemainder.toFixed(2)) ?? "0.00"
672
+ ...bundle.metadata || {}
527
673
  };
528
- bundle.tax_fee_rounding_remainder = (bundleRemainder == null ? void 0 : bundleRemainder.toNumber()) ?? 0;
674
+ if (bundleRemainder !== null) {
675
+ bundle.metadata.tax_fee_rounding_remainder = bundleRemainder.toFixed(2);
676
+ bundle.tax_fee_rounding_remainder = bundleRemainder.toNumber();
677
+ } else {
678
+ delete bundle.metadata.tax_fee_rounding_remainder;
679
+ delete bundle.tax_fee_rounding_remainder;
680
+ }
529
681
  bundle.original_tax_fee_rounding_remainder = 0;
530
682
  }
531
683
  }
@@ -617,17 +769,22 @@ function calculateProductsTax(products, taxRate, isPriceIncludeTax) {
617
769
  isChargeTax: product.is_charge_tax ?? 0
618
770
  });
619
771
  const mainTaxRounded = toBackendTaxFee(mainTaxPrecise);
620
- product.main_product_attached_bundle_tax_fee = mainTaxRounded.toFixed(2);
621
772
  const persistedMainRemainder = getPersistedTaxRemainder(product);
622
- const mainRemainder = persistedMainRemainder ?? applyBackendTaxRemainder({
773
+ const persistedMainTaxFee = getPersistedMainTaxFee(product);
774
+ const persistedQuantity = getPersistedQuantity(product, quantity);
775
+ const deltaQuantity = import_decimal.default.max(quantity.minus(persistedQuantity), 0);
776
+ const shouldUsePersistedMainTax = persistedMainTaxFee && persistedMainTaxFee.gt(0) && persistedQuantity.gte(quantity);
777
+ const shouldSplitPersistedMainTax = persistedMainTaxFee && persistedMainTaxFee.gt(0) && persistedQuantity.gt(0) && deltaQuantity.gt(0);
778
+ const mainRemainder = shouldUsePersistedMainTax || shouldSplitPersistedMainTax ? new import_decimal.default(0) : persistedMainRemainder ?? applyBackendTaxRemainder({
623
779
  target: product,
624
780
  rawTax: mainTaxPrecise,
625
781
  formattedTax: mainTaxRounded,
626
782
  quantity,
627
783
  state: taxRemainderState
628
784
  });
629
- if (persistedMainRemainder)
785
+ if (persistedMainRemainder && !shouldSplitPersistedMainTax) {
630
786
  writeTaxRemainder(product, persistedMainRemainder);
787
+ }
631
788
  const originalTotal = getUnitOriginalTotal(product);
632
789
  const originalTaxableBase = originalTotal.lte(0) ? surchargeFee : originalTotal.plus(surchargeFee);
633
790
  const originalTaxPrecise = calculateSingleItemTax({
@@ -637,18 +794,64 @@ function calculateProductsTax(products, taxRate, isPriceIncludeTax) {
637
794
  isChargeTax: product.is_charge_tax ?? 0
638
795
  });
639
796
  const originalTaxRounded = toAmountFormat(originalTaxPrecise);
640
- productUnitTax = productUnitTax.plus(mainTaxRounded);
797
+ const effectiveMainUnitTax = shouldUsePersistedMainTax ? persistedMainTaxFee : shouldSplitPersistedMainTax ? persistedMainTaxFee.times(persistedQuantity).plus(mainTaxRounded.times(deltaQuantity)).div(quantity).toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP) : mainTaxRounded;
798
+ productUnitTax = productUnitTax.plus(effectiveMainUnitTax);
641
799
  productUnitOriginTax = productUnitOriginTax.plus(originalTaxRounded);
800
+ product.main_product_attached_bundle_tax_fee = effectiveMainUnitTax.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toFixed(2);
642
801
  product.tax_fee = productUnitTax.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toFixed(2);
643
802
  product.original_tax_fee = productUnitOriginTax.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP).toNumber();
644
- totalTax = totalTax.plus(mainTaxRounded.times(quantity)).plus(mainRemainder);
803
+ totalTax = totalTax.plus(
804
+ shouldUsePersistedMainTax ? persistedMainTaxFee.times(quantity).plus(persistedMainRemainder || 0) : shouldSplitPersistedMainTax ? persistedMainTaxFee.times(persistedQuantity).plus(mainTaxRounded.times(deltaQuantity)) : mainTaxRounded.times(quantity).plus(mainRemainder)
805
+ );
645
806
  totalOriginTax = totalOriginTax.plus(originalTaxRounded.times(quantity));
807
+ if (product.tax_fee_rounding_remainder === void 0) {
808
+ product.tax_fee_rounding_remainder = 0;
809
+ }
646
810
  }
647
811
  return {
648
812
  tax: totalTax.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP),
649
813
  originTax: totalOriginTax.toDecimalPlaces(2, import_decimal.default.ROUND_HALF_UP)
650
814
  };
651
815
  }
816
+ function allocateShopDiscountToPayment(products, productAmount, shopDiscountAmount) {
817
+ const effectiveDiscount = productAmount.lte(0) ? new import_decimal.default(0) : import_decimal.default.max(import_decimal.default.min(productAmount, shopDiscountAmount), 0);
818
+ let allocatedDiscount = new import_decimal.default(0);
819
+ products.forEach((product, index) => {
820
+ const quantity = new import_decimal.default(getSafeNum(product.num));
821
+ const sellingUnit = getUnitPaymentTotal(product);
822
+ const lineSellingTotal = sellingUnit.times(quantity);
823
+ const lineDiscount = effectiveDiscount.lte(0) ? new import_decimal.default(0) : index === products.length - 1 ? import_decimal.default.max(effectiveDiscount.minus(allocatedDiscount), 0) : toAmountFormat(lineSellingTotal.div(productAmount).times(effectiveDiscount));
824
+ allocatedDiscount = allocatedDiscount.plus(lineDiscount);
825
+ const unitDiscount = quantity.lte(0) ? new import_decimal.default(0) : lineDiscount.div(quantity);
826
+ const paymentUnit = import_decimal.default.max(sellingUnit.minus(unitDiscount), 0);
827
+ const rate = sellingUnit.lte(0) ? new import_decimal.default(1) : toBcScale(paymentUnit.div(sellingUnit), 6);
828
+ const mainSellingTotal = getMainAttachedBundleSellingTotal(product);
829
+ const mainPaymentTotal = toAmountFormat(bcMul(mainSellingTotal, rate, 6));
830
+ product.metadata = {
831
+ ...product.metadata || {},
832
+ average_discount_amount_rate: rate.toString(),
833
+ main_product_attached_bundle_selling_price: mainSellingTotal.toFixed(2),
834
+ main_product_attached_bundle_payment_price: mainPaymentTotal.toFixed(2)
835
+ };
836
+ for (const bundle of product.product_bundle || []) {
837
+ if (isBundleOriginalPrice(bundle)) {
838
+ const bundleSelling = toDecimal(
839
+ bundle.bundle_selling_price ?? bundle.bundle_sum_price ?? bundle.price ?? 0
840
+ );
841
+ bundle.bundle_payment_price = toAmountFormat(bcMul(bundleSelling, rate, 6)).toFixed(2);
842
+ continue;
843
+ }
844
+ if ((0, import_utils2.isMarkdownBundle)(bundle)) {
845
+ const magnitude = (0, import_utils2.getBundleSellingMagnitude)(bundle);
846
+ bundle.custom_price = bundle.custom_price ?? bundle.price;
847
+ bundle.price = magnitude.toFixed(2);
848
+ bundle.bundle_selling_price = magnitude.toFixed(2);
849
+ bundle.bundle_payment_price = toAmountFormat(bcMul(magnitude, rate, 6)).toFixed(2);
850
+ }
851
+ }
852
+ product.payment_price = paymentUnit.toFixed(2);
853
+ });
854
+ }
652
855
  function createEmptySalesSummary() {
653
856
  return {
654
857
  product_quantity: 0,
@@ -700,6 +903,14 @@ function calculateSalesSummary(params) {
700
903
  (sum, item) => sum.plus(getUnitPaymentTotal(item).times(getSafeNum(item.num))),
701
904
  new import_decimal.default(0)
702
905
  );
906
+ const shopDiscountAmount = import_decimal.default.max(new import_decimal.default(Number(shopDiscount) || 0), 0);
907
+ const hasPersistedSurchargeSnapshot = summaryProducts.some((product) => {
908
+ var _a;
909
+ return (_a = getPersistedMainSurchargeFee(product)) == null ? void 0 : _a.gt(0);
910
+ });
911
+ if (!hasPersistedSurchargeSnapshot) {
912
+ allocateShopDiscountToPayment(summaryProducts, productAmount, shopDiscountAmount);
913
+ }
703
914
  const surchargeServiceItems = buildSurchargeServiceItems(summaryProducts);
704
915
  (0, import_utils.getSurcharge)(
705
916
  {
@@ -738,9 +949,8 @@ function calculateSalesSummary(params) {
738
949
  new import_decimal.default(0)
739
950
  );
740
951
  }
741
- const shopDiscountAmount = import_decimal.default.max(new import_decimal.default(Number(shopDiscount) || 0), 0);
742
- const preTaxExpectAmount = import_decimal.default.max(0, productAmount.plus(surchargeAmount).minus(shopDiscountAmount));
743
- const totalAmount = isPriceIncludeTax === 1 ? preTaxExpectAmount : preTaxExpectAmount.plus(productTaxFee);
952
+ const orderAmountBeforeDiscount = productAmount.plus(surchargeAmount).plus(isPriceIncludeTax === 1 ? 0 : productTaxFee);
953
+ const totalAmount = import_decimal.default.max(0, orderAmountBeforeDiscount.minus(shopDiscountAmount));
744
954
  const deposit = calculateProductsDeposit(summaryProducts);
745
955
  return {
746
956
  product_quantity: productQuantity,
@@ -287,6 +287,8 @@ declare class Server {
287
287
  private handleOrderSalesCheckout;
288
288
  private handleOrderCheckout;
289
289
  private handleOrderCheckoutSubmit;
290
+ private handlePendingSyncCheckoutOrder;
291
+ private buildPendingSyncCheckoutOrder;
290
292
  private handleOrderSalesDetail;
291
293
  /**
292
294
  * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
@@ -320,6 +322,7 @@ declare class Server {
320
322
  private extractOrderDataFromCheckoutResponse;
321
323
  private normalizeCheckoutResponse;
322
324
  private extractBackendErrorResponse;
325
+ private isExplicitBackendErrorResponse;
323
326
  /**
324
327
  * 从 url 或路由 path 解析 pathname(不含 query,去掉末尾 /)
325
328
  */
@@ -1749,7 +1749,12 @@ var Server = class {
1749
1749
  });
1750
1750
  if (!((_a = this.app) == null ? void 0 : _a.request)) {
1751
1751
  this.logError(`${title}: app.request 不可用`);
1752
- return { code: 500, status: false, message: "app.request 不可用", data: null };
1752
+ return this.handlePendingSyncCheckoutOrder({
1753
+ backendPath,
1754
+ data,
1755
+ title,
1756
+ reason: "app.request 不可用"
1757
+ });
1753
1758
  }
1754
1759
  try {
1755
1760
  const response = await this.app.request.post(backendPath, data, {
@@ -1759,7 +1764,8 @@ var Server = class {
1759
1764
  });
1760
1765
  const fresh = this.extractOrderDataFromCheckoutResponse(response);
1761
1766
  if (fresh && this.order) {
1762
- await this.order.upsertOrdersFromRemote([fresh]);
1767
+ const syncedOrder = { ...fresh, need_sync: 0 };
1768
+ await this.order.upsertOrdersFromRemote([syncedOrder]);
1763
1769
  this.logInfo(`${title}: 订单已同步到本地`, {
1764
1770
  order_id: fresh.order_id,
1765
1771
  external_sale_number: fresh.external_sale_number,
@@ -1778,9 +1784,77 @@ var Server = class {
1778
1784
  const backendError = this.extractBackendErrorResponse(error);
1779
1785
  if (backendError)
1780
1786
  return backendError;
1787
+ return this.handlePendingSyncCheckoutOrder({
1788
+ backendPath,
1789
+ data,
1790
+ title,
1791
+ reason: errorMessage
1792
+ });
1793
+ }
1794
+ }
1795
+ async handlePendingSyncCheckoutOrder(params) {
1796
+ const { backendPath, data, title, reason } = params;
1797
+ const pendingOrder = this.buildPendingSyncCheckoutOrder(data);
1798
+ if (!pendingOrder) {
1799
+ this.logError(`${title}: checkout 失败且订单缺少本地存储标识`, {
1800
+ backendPath,
1801
+ reason
1802
+ });
1803
+ return {
1804
+ code: 500,
1805
+ status: false,
1806
+ message: "订单缺少本地存储标识,无法写入待同步队列",
1807
+ data: null
1808
+ };
1809
+ }
1810
+ if (!this.order || typeof this.order.upsertPendingSyncOrders !== "function") {
1811
+ this.logError(`${title}: Order 模块不支持本地待同步写入`, {
1812
+ backendPath,
1813
+ reason
1814
+ });
1815
+ return {
1816
+ code: 500,
1817
+ status: false,
1818
+ message: "Order 模块不支持本地待同步写入",
1819
+ data: null
1820
+ };
1821
+ }
1822
+ try {
1823
+ await this.order.upsertPendingSyncOrders([pendingOrder]);
1824
+ this.logWarning(`${title}: 后端未明确报错,订单已写入本地待同步`, {
1825
+ backendPath,
1826
+ reason,
1827
+ order_id: pendingOrder.order_id,
1828
+ external_sale_number: pendingOrder.external_sale_number,
1829
+ order_number: pendingOrder.order_number
1830
+ });
1831
+ return {
1832
+ code: 200,
1833
+ status: true,
1834
+ message: "",
1835
+ data: pendingOrder
1836
+ };
1837
+ } catch (error) {
1838
+ const errorMessage = error instanceof Error ? error.message : String(error);
1839
+ this.logError(`${title}: 写入本地待同步订单失败`, {
1840
+ backendPath,
1841
+ reason,
1842
+ error: errorMessage
1843
+ });
1781
1844
  return { code: 500, status: false, message: errorMessage, data: null };
1782
1845
  }
1783
1846
  }
1847
+ buildPendingSyncCheckoutOrder(data) {
1848
+ if (!data || typeof data !== "object")
1849
+ return null;
1850
+ const hasStorageKey = data.external_sale_number !== void 0 && data.external_sale_number !== null && data.external_sale_number !== "" ? true : data.order_id !== void 0 && data.order_id !== null && data.order_id !== "";
1851
+ if (!hasStorageKey)
1852
+ return null;
1853
+ return {
1854
+ ...data,
1855
+ need_sync: 1
1856
+ };
1857
+ }
1784
1858
  /**
1785
1859
  * 解析 order_ids 入参,兼容 url query / data 字段、字符串(csv) / 数组两种形态。
1786
1860
  * 自动 trim、去空、按字符串去重,输出归一化后的字符串数组。
@@ -1993,9 +2067,14 @@ var Server = class {
1993
2067
  error == null ? void 0 : error.body
1994
2068
  ];
1995
2069
  return candidates.find(
1996
- (candidate) => candidate && typeof candidate === "object"
2070
+ (candidate) => this.isExplicitBackendErrorResponse(candidate)
1997
2071
  ) || null;
1998
2072
  }
2073
+ isExplicitBackendErrorResponse(candidate) {
2074
+ if (!candidate || typeof candidate !== "object")
2075
+ return false;
2076
+ return candidate.code !== void 0 || candidate.status !== void 0 || typeof candidate.message === "string";
2077
+ }
1999
2078
  /**
2000
2079
  * 从 url 或路由 path 解析 pathname(不含 query,去掉末尾 /)
2001
2080
  */
@@ -92,6 +92,11 @@ export declare class OrderModule extends BaseModule implements Module {
92
92
  * 供 /update/localOrder 等在「本地尚无该单」时写入新建单。
93
93
  */
94
94
  upsertOrdersFromRemote(freshOrders: OrderData[]): Promise<void>;
95
+ /**
96
+ * 将本地待同步订单按 SQLite storage key 合并进 store 并落库。
97
+ * checkout 离线兜底可能没有 order_id,但通常会有 external_sale_number。
98
+ */
99
+ upsertPendingSyncOrders(pendingOrders: OrderData[]): Promise<void>;
95
100
  /**
96
101
  * 通过 SSE 按自定义 query 拉取订单(支持 select/with 精简字段)
97
102
  */
@@ -172,6 +177,9 @@ export declare class OrderModule extends BaseModule implements Module {
172
177
  private getStorageItem;
173
178
  private setStorageItem;
174
179
  private loadOrdersFromSQLite;
180
+ private isPendingSyncOrder;
181
+ private normalizeRemoteSyncedOrder;
182
+ private mergeRemoteSnapshotWithPendingOrders;
175
183
  /**
176
184
  * 串行执行订单 SQLite 写入任务,避免快照替换与增量 upsert 并发交错。
177
185
  *