@pisell/pisellos 2.2.108 → 2.2.110

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.
@@ -2748,7 +2748,7 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
2748
2748
  key: "processCashPaymentItem",
2749
2749
  value: (function () {
2750
2750
  var _processCashPaymentItem = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee28(paymentItem) {
2751
- var cashPayment, remainingAmountStr, remainingAmount, cashAmount, changeAmount, processedPaymentItem;
2751
+ var cashPayment, remainingAmountStr, remainingAmount, cashAmount, roundingAmount, chargeAmount, changeAmount, processedPaymentItem;
2752
2752
  return _regeneratorRuntime().wrap(function _callee28$(_context28) {
2753
2753
  while (1) switch (_context28.prev = _context28.next) {
2754
2754
  case 0:
@@ -2766,41 +2766,35 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
2766
2766
  case 6:
2767
2767
  remainingAmountStr = _context28.sent;
2768
2768
  remainingAmount = new Decimal(remainingAmountStr);
2769
- cashAmount = new Decimal(String(paymentItem.amount)); // 如果现金金额小于等于剩余待付金额,无需找零
2769
+ cashAmount = new Decimal(String(paymentItem.amount));
2770
+ roundingAmount = new Decimal(String(paymentItem.rounding_amount || '0')); // 如果现金金额小于等于剩余待付金额,无需找零
2770
2771
  if (!cashAmount.lte(remainingAmount)) {
2771
- _context28.next = 11;
2772
+ _context28.next = 12;
2772
2773
  break;
2773
2774
  }
2774
2775
  return _context28.abrupt("return", paymentItem);
2775
- case 11:
2776
- // 使用 Decimal.js 安全计算找零金额
2777
- changeAmount = cashAmount.sub(remainingAmount); // 如果还有 rounding_amount 的配置,要判断是否和 changeAmount 相等
2778
- if (!(Number(paymentItem.rounding_amount) > 0)) {
2779
- _context28.next = 18;
2780
- break;
2781
- }
2782
- if (!(Number(paymentItem.rounding_amount) === changeAmount.toNumber())) {
2783
- _context28.next = 17;
2776
+ case 12:
2777
+ // 超付场景使用 rounding 回算应收金额(兼容 UI 已做抹零 + 允许超付)
2778
+ chargeAmount = Decimal.max(remainingAmount.add(roundingAmount), new Decimal(0));
2779
+ if (!cashAmount.lte(chargeAmount)) {
2780
+ _context28.next = 15;
2784
2781
  break;
2785
2782
  }
2786
2783
  return _context28.abrupt("return", paymentItem);
2787
- case 17:
2788
- // 如果不等于,则remainingAmount需要加上 rounding_amount,避免这里被改为未舍入金额
2789
- remainingAmount = remainingAmount.add(new Decimal(paymentItem.rounding_amount || '0'));
2790
- case 18:
2791
- // 创建包含找零信息的支付项
2784
+ case 15:
2785
+ changeAmount = cashAmount.sub(chargeAmount); // 创建包含找零信息的支付项
2792
2786
  processedPaymentItem = _objectSpread(_objectSpread({}, paymentItem), {}, {
2793
- amount: remainingAmount.toFixed(2),
2794
- // 将 amount 设置为剩余待付金额,保留2位小数
2787
+ amount: chargeAmount.toFixed(2),
2795
2788
  metadata: _objectSpread(_objectSpread({}, paymentItem.metadata), {}, {
2796
2789
  actual_paid_amount: cashAmount.toNumber(),
2797
- // 实付金额
2798
- change_given_amount: changeAmount.toNumber() // 找零金额
2790
+ change_given_amount: changeAmount.toNumber()
2799
2791
  })
2800
2792
  });
2801
2793
  this.logInfo('Cash payment with change processed', {
2802
2794
  originalAmount: cashAmount.toFixed(2),
2803
- chargedAmount: remainingAmount.toFixed(2),
2795
+ remainingAmount: remainingAmount.toFixed(2),
2796
+ roundingAmount: roundingAmount.toFixed(2),
2797
+ chargedAmount: chargeAmount.toFixed(2),
2804
2798
  changeAmount: changeAmount.toFixed(2),
2805
2799
  paymentCode: paymentItem.code,
2806
2800
  paymentType: paymentItem.type,
@@ -2808,21 +2802,23 @@ export var CheckoutImpl = /*#__PURE__*/function (_BaseModule) {
2808
2802
  decimalPrecisionCheck: {
2809
2803
  cashAmountPrecise: cashAmount.toString(),
2810
2804
  remainingAmountPrecise: remainingAmount.toString(),
2805
+ roundingAmountPrecise: roundingAmount.toString(),
2806
+ chargeAmountPrecise: chargeAmount.toString(),
2811
2807
  changeAmountPrecise: changeAmount.toString()
2812
2808
  }
2813
2809
  });
2814
2810
  return _context28.abrupt("return", processedPaymentItem);
2815
- case 23:
2816
- _context28.prev = 23;
2811
+ case 21:
2812
+ _context28.prev = 21;
2817
2813
  _context28.t0 = _context28["catch"](3);
2818
2814
  this.logError('处理现金支付项时出错:', _context28.t0);
2819
2815
  // 出错时返回原始支付项,避免中断支付流程
2820
2816
  return _context28.abrupt("return", paymentItem);
2821
- case 27:
2817
+ case 25:
2822
2818
  case "end":
2823
2819
  return _context28.stop();
2824
2820
  }
2825
- }, _callee28, this, [[3, 23]]);
2821
+ }, _callee28, this, [[3, 21]]);
2826
2822
  }));
2827
2823
  function processCashPaymentItem(_x27) {
2828
2824
  return _processCashPaymentItem.apply(this, arguments);
@@ -321,7 +321,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
321
321
  key: "getBookingStatus",
322
322
  value: function getBookingStatus(appointmentStatus) {
323
323
  if (appointmentStatus === 'started') return 'occupied';
324
- if (appointmentStatus === 'new' || appointmentStatus === 'confirmed' || appointmentStatus === 'arrived') {
324
+ if (appointmentStatus === 'confirmed' || appointmentStatus === 'arrived') {
325
325
  return 'reserved';
326
326
  }
327
327
  // TODO: locked 的业务规则后续补充。
@@ -383,6 +383,9 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
383
383
  return startAt.isValid() && startAt.valueOf() === nextStartAt;
384
384
  });
385
385
  if (nextStartGroup.length === 0) return selectedBookings;
386
+ nextStartGroup.forEach(function (booking) {
387
+ booking.isNext = true;
388
+ });
386
389
  return [].concat(_toConsumableArray(selectedBookings), _toConsumableArray(nextStartGroup));
387
390
  };
388
391
 
@@ -431,7 +434,7 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
431
434
  value: function normalizeMatchedBooking(current, deviceCurrent, booking) {
432
435
  var _ref3, _booking$appointment_;
433
436
  var appointmentStatus = String((_ref3 = (_booking$appointment_ = booking.appointment_status) !== null && _booking$appointment_ !== void 0 ? _booking$appointment_ : booking.status) !== null && _ref3 !== void 0 ? _ref3 : '');
434
- if (appointmentStatus === 'rejected' || appointmentStatus === 'cancelled' || appointmentStatus === 'completed') {
437
+ if (appointmentStatus === 'new' || appointmentStatus === 'rejected' || appointmentStatus === 'cancelled' || appointmentStatus === 'completed') {
435
438
  return null;
436
439
  }
437
440
  var endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
@@ -463,6 +466,25 @@ export var SalesImpl = /*#__PURE__*/function (_BaseModule) {
463
466
  lateTime = Math.max(current.diff(startAt, 'minute'), 0);
464
467
  }
465
468
  }
469
+
470
+ // 未来查询投影:查询时间晚于设备时间时,预留+迟到且 end_time 仍在查询时间之后的预约强制视为占用
471
+ if (current.isAfter(deviceCurrent) && bookingStatus === 'reserved' && reservedStatus === 'late' && endAt.isValid() && endAt.isAfter(current)) {
472
+ bookingStatus = 'occupied';
473
+ reservedStatus = undefined;
474
+ lateTime = undefined;
475
+ remainingReserveTime = undefined;
476
+ isTimeout = false;
477
+ timeoutTime = undefined;
478
+ progressPercent = function () {
479
+ if (!startAt.isValid() || !endAt.isValid()) return 0;
480
+ var totalMinutes = endAt.diff(startAt, 'minute');
481
+ if (totalMinutes <= 0) return 0;
482
+ var elapsedMinutes = current.diff(startAt, 'minute');
483
+ if (elapsedMinutes <= 0) return 0;
484
+ if (elapsedMinutes >= totalMinutes) return 100;
485
+ return Math.floor(elapsedMinutes / totalMinutes * 100);
486
+ }();
487
+ }
466
488
  return _objectSpread(_objectSpread({}, booking), {}, {
467
489
  status: bookingStatus,
468
490
  isTimeout: isTimeout,
@@ -20,6 +20,7 @@ export type SalesBookingStatus = 'reserved' | 'occupied' | 'locked' | undefined;
20
20
  export type SalesReservedStatus = 'not_arrived' | 'late' | undefined;
21
21
  export interface SalesResourceMatchedBooking extends Omit<BookingData, 'status'> {
22
22
  status: SalesBookingStatus;
23
+ isNext?: boolean;
23
24
  isTimeout: boolean;
24
25
  timeoutTime?: number;
25
26
  progressPercent?: number;
@@ -0,0 +1,49 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/model/strategy/adapter/promotion/index.ts
30
+ var promotion_exports = {};
31
+ __export(promotion_exports, {
32
+ BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
33
+ PromotionAdapter: () => import_adapter.PromotionAdapter,
34
+ PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
35
+ X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
36
+ default: () => import_adapter2.default
37
+ });
38
+ module.exports = __toCommonJS(promotion_exports);
39
+ var import_evaluator = require("./evaluator");
40
+ var import_adapter = require("./adapter");
41
+ var import_adapter2 = __toESM(require("./adapter"));
42
+ var import_examples = require("./examples");
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ BUY_X_GET_Y_FREE_STRATEGY,
46
+ PromotionAdapter,
47
+ PromotionEvaluator,
48
+ X_ITEMS_FOR_Y_PRICE_STRATEGY
49
+ });
@@ -1835,36 +1835,34 @@ var CheckoutImpl = class extends import_BaseModule.BaseModule {
1835
1835
  }
1836
1836
  try {
1837
1837
  const remainingAmountStr = await this.calculateRemainingAmountAsync();
1838
- let remainingAmount = new import_decimal.default(remainingAmountStr);
1838
+ const remainingAmount = new import_decimal.default(remainingAmountStr);
1839
1839
  const cashAmount = new import_decimal.default(String(paymentItem.amount));
1840
+ const roundingAmount = new import_decimal.default(String(paymentItem.rounding_amount || "0"));
1840
1841
  if (cashAmount.lte(remainingAmount)) {
1841
1842
  return paymentItem;
1842
1843
  }
1843
- const changeAmount = cashAmount.sub(remainingAmount);
1844
- if (Number(paymentItem.rounding_amount) > 0) {
1845
- if (Number(paymentItem.rounding_amount) === changeAmount.toNumber()) {
1846
- return paymentItem;
1847
- } else {
1848
- remainingAmount = remainingAmount.add(
1849
- new import_decimal.default(paymentItem.rounding_amount || "0")
1850
- );
1851
- }
1844
+ const chargeAmount = import_decimal.default.max(
1845
+ remainingAmount.add(roundingAmount),
1846
+ new import_decimal.default(0)
1847
+ );
1848
+ if (cashAmount.lte(chargeAmount)) {
1849
+ return paymentItem;
1852
1850
  }
1851
+ const changeAmount = cashAmount.sub(chargeAmount);
1853
1852
  const processedPaymentItem = {
1854
1853
  ...paymentItem,
1855
- amount: remainingAmount.toFixed(2),
1856
- // 将 amount 设置为剩余待付金额,保留2位小数
1854
+ amount: chargeAmount.toFixed(2),
1857
1855
  metadata: {
1858
1856
  ...paymentItem.metadata,
1859
1857
  actual_paid_amount: cashAmount.toNumber(),
1860
- // 实付金额
1861
1858
  change_given_amount: changeAmount.toNumber()
1862
- // 找零金额
1863
1859
  }
1864
1860
  };
1865
1861
  this.logInfo("Cash payment with change processed", {
1866
1862
  originalAmount: cashAmount.toFixed(2),
1867
- chargedAmount: remainingAmount.toFixed(2),
1863
+ remainingAmount: remainingAmount.toFixed(2),
1864
+ roundingAmount: roundingAmount.toFixed(2),
1865
+ chargedAmount: chargeAmount.toFixed(2),
1868
1866
  changeAmount: changeAmount.toFixed(2),
1869
1867
  paymentCode: paymentItem.code,
1870
1868
  paymentType: paymentItem.type,
@@ -1872,6 +1870,8 @@ var CheckoutImpl = class extends import_BaseModule.BaseModule {
1872
1870
  decimalPrecisionCheck: {
1873
1871
  cashAmountPrecise: cashAmount.toString(),
1874
1872
  remainingAmountPrecise: remainingAmount.toString(),
1873
+ roundingAmountPrecise: roundingAmount.toString(),
1874
+ chargeAmountPrecise: chargeAmount.toString(),
1875
1875
  changeAmountPrecise: changeAmount.toString()
1876
1876
  }
1877
1877
  });
@@ -218,7 +218,7 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
218
218
  getBookingStatus(appointmentStatus) {
219
219
  if (appointmentStatus === "started")
220
220
  return "occupied";
221
- if (appointmentStatus === "new" || appointmentStatus === "confirmed" || appointmentStatus === "arrived") {
221
+ if (appointmentStatus === "confirmed" || appointmentStatus === "arrived") {
222
222
  return "reserved";
223
223
  }
224
224
  if (appointmentStatus === "locked")
@@ -278,6 +278,9 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
278
278
  });
279
279
  if (nextStartGroup.length === 0)
280
280
  return selectedBookings;
281
+ nextStartGroup.forEach((booking) => {
282
+ booking.isNext = true;
283
+ });
281
284
  return [...selectedBookings, ...nextStartGroup];
282
285
  };
283
286
  const activeBookings = dayScopedBookings.filter((booking) => {
@@ -317,18 +320,18 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
317
320
  */
318
321
  normalizeMatchedBooking(current, deviceCurrent, booking) {
319
322
  const appointmentStatus = String(booking.appointment_status ?? booking.status ?? "");
320
- if (appointmentStatus === "rejected" || appointmentStatus === "cancelled" || appointmentStatus === "completed") {
323
+ if (appointmentStatus === "new" || appointmentStatus === "rejected" || appointmentStatus === "cancelled" || appointmentStatus === "completed") {
321
324
  return null;
322
325
  }
323
326
  const endAt = this.toBookingDateTime(booking.end_date, booking.end_time);
324
327
  const shouldFilterHistoryByCurrent = deviceCurrent.isBefore(current);
325
328
  if (shouldFilterHistoryByCurrent && endAt.isValid() && endAt.isBefore(current))
326
329
  return null;
327
- const bookingStatus = this.getBookingStatus(appointmentStatus);
330
+ let bookingStatus = this.getBookingStatus(appointmentStatus);
328
331
  const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
329
- const isTimeout = bookingStatus === "occupied" && endAt.isValid() && current.isAfter(endAt);
330
- const timeoutTime = isTimeout ? current.diff(endAt, "minute") : void 0;
331
- const progressPercent = (() => {
332
+ let isTimeout = bookingStatus === "occupied" && endAt.isValid() && current.isAfter(endAt);
333
+ let timeoutTime = isTimeout ? current.diff(endAt, "minute") : void 0;
334
+ let progressPercent = (() => {
332
335
  if (bookingStatus !== "occupied")
333
336
  return 0;
334
337
  if (!startAt.isValid() || !endAt.isValid())
@@ -355,6 +358,27 @@ var SalesImpl = class extends import_BaseModule.BaseModule {
355
358
  lateTime = Math.max(current.diff(startAt, "minute"), 0);
356
359
  }
357
360
  }
361
+ if (current.isAfter(deviceCurrent) && bookingStatus === "reserved" && reservedStatus === "late" && endAt.isValid() && endAt.isAfter(current)) {
362
+ bookingStatus = "occupied";
363
+ reservedStatus = void 0;
364
+ lateTime = void 0;
365
+ remainingReserveTime = void 0;
366
+ isTimeout = false;
367
+ timeoutTime = void 0;
368
+ progressPercent = (() => {
369
+ if (!startAt.isValid() || !endAt.isValid())
370
+ return 0;
371
+ const totalMinutes = endAt.diff(startAt, "minute");
372
+ if (totalMinutes <= 0)
373
+ return 0;
374
+ const elapsedMinutes = current.diff(startAt, "minute");
375
+ if (elapsedMinutes <= 0)
376
+ return 0;
377
+ if (elapsedMinutes >= totalMinutes)
378
+ return 100;
379
+ return Math.floor(elapsedMinutes / totalMinutes * 100);
380
+ })();
381
+ }
358
382
  return {
359
383
  ...booking,
360
384
  status: bookingStatus,
@@ -20,6 +20,7 @@ export type SalesBookingStatus = 'reserved' | 'occupied' | 'locked' | undefined;
20
20
  export type SalesReservedStatus = 'not_arrived' | 'late' | undefined;
21
21
  export interface SalesResourceMatchedBooking extends Omit<BookingData, 'status'> {
22
22
  status: SalesBookingStatus;
23
+ isNext?: boolean;
23
24
  isTimeout: boolean;
24
25
  timeoutTime?: number;
25
26
  progressPercent?: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.2.108",
4
+ "version": "2.2.110",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",