@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.
- package/dist/solution/Checkout/index.js +22 -26
- package/dist/solution/Sales/index.js +24 -2
- package/dist/solution/Sales/types.d.ts +1 -0
- package/lib/model/strategy/adapter/promotion/index.js +49 -0
- package/lib/solution/Checkout/index.js +15 -15
- package/lib/solution/Sales/index.js +30 -6
- package/lib/solution/Sales/types.d.ts +1 -0
- package/package.json +1 -1
|
@@ -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 =
|
|
2772
|
+
_context28.next = 12;
|
|
2772
2773
|
break;
|
|
2773
2774
|
}
|
|
2774
2775
|
return _context28.abrupt("return", paymentItem);
|
|
2775
|
-
case
|
|
2776
|
-
//
|
|
2777
|
-
|
|
2778
|
-
if (!(
|
|
2779
|
-
_context28.next =
|
|
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
|
|
2788
|
-
//
|
|
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:
|
|
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
|
-
|
|
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
|
|
2816
|
-
_context28.prev =
|
|
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
|
|
2817
|
+
case 25:
|
|
2822
2818
|
case "end":
|
|
2823
2819
|
return _context28.stop();
|
|
2824
2820
|
}
|
|
2825
|
-
}, _callee28, this, [[3,
|
|
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 === '
|
|
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
|
-
|
|
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
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
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:
|
|
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
|
-
|
|
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 === "
|
|
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
|
-
|
|
330
|
+
let bookingStatus = this.getBookingStatus(appointmentStatus);
|
|
328
331
|
const startAt = this.toBookingDateTime(booking.start_date, booking.start_time);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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;
|