@pisell/pisellos 0.10.54 → 0.10.55
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/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/BusinessAvailability/index.d.ts +30 -0
- package/dist/modules/BusinessAvailability/index.js +204 -0
- package/dist/modules/OpenData/types.d.ts +2 -0
- package/dist/modules/Order/index.d.ts +5 -2
- package/dist/modules/Order/index.js +315 -241
- package/dist/modules/Order/types.d.ts +8 -0
- package/dist/solution/BaseSales/index.d.ts +4 -15
- package/dist/solution/BaseSales/index.js +131 -86
- package/dist/solution/BaseSales/types.d.ts +11 -0
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.js +41 -13
- package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
- package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +11 -0
- package/dist/solution/UnifiedBookingSales/index.js +154 -75
- package/dist/solution/UnifiedBookingSales/types.d.ts +2 -0
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/BusinessAvailability/index.d.ts +30 -0
- package/lib/modules/BusinessAvailability/index.js +146 -0
- package/lib/modules/OpenData/types.d.ts +2 -0
- package/lib/modules/Order/index.d.ts +5 -2
- package/lib/modules/Order/index.js +62 -6
- package/lib/modules/Order/types.d.ts +8 -0
- package/lib/solution/BaseSales/index.d.ts +4 -15
- package/lib/solution/BaseSales/index.js +45 -24
- package/lib/solution/BaseSales/types.d.ts +11 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.js +37 -4
- package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
- package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +11 -0
- package/lib/solution/UnifiedBookingSales/index.js +54 -0
- package/lib/solution/UnifiedBookingSales/types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -216,6 +216,8 @@ export interface UnifiedBookingSalesDiscountResult {
|
|
|
216
216
|
summaryAfter?: unknown;
|
|
217
217
|
}
|
|
218
218
|
export interface UnifiedBookingSalesApi {
|
|
219
|
+
/** Uses cached business settings and evaluates the current store-local clock. */
|
|
220
|
+
getBusinessAvailability: () => Promise<import('../../modules/BusinessAvailability').BusinessAvailability>;
|
|
219
221
|
loadOpenData: (params: UnifiedBookingSalesLoadOpenDataParams) => Promise<OpenDataConfig>;
|
|
220
222
|
/** Returns the latest OpenData payload cached by this solution instance. */
|
|
221
223
|
getOpenData: () => Promise<OpenDataConfig | null>;
|
|
@@ -1,46 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function () {
|
|
9
|
-
return _examples.BUY_X_GET_Y_FREE_STRATEGY;
|
|
10
|
-
}
|
|
11
|
-
});
|
|
12
|
-
Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
get: function () {
|
|
15
|
-
return _examples.ITEM_REWARD_STRATEGY;
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
Object.defineProperty(exports, "PromotionAdapter", {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
get: function () {
|
|
21
|
-
return _adapter.PromotionAdapter;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
Object.defineProperty(exports, "PromotionEvaluator", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
get: function () {
|
|
27
|
-
return _evaluator.PromotionEvaluator;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
|
|
31
|
-
enumerable: true,
|
|
32
|
-
get: function () {
|
|
33
|
-
return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
Object.defineProperty(exports, "default", {
|
|
37
|
-
enumerable: true,
|
|
38
|
-
get: function () {
|
|
39
|
-
return _adapter.default;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
var _evaluator = require("./evaluator");
|
|
43
|
-
var _adapter = _interopRequireWildcard(require("./adapter"));
|
|
44
|
-
var _examples = require("./examples");
|
|
45
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
46
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { MultiLangObject } from '../OpenData/types';
|
|
2
|
+
import type { ScheduleItem } from '../Schedule/types';
|
|
3
|
+
export type BusinessClosedBehavior = 'show_menu_disabled' | 'hide_all';
|
|
4
|
+
export interface BusinessAvailability {
|
|
5
|
+
status: 'open' | 'paused' | 'closed' | 'error';
|
|
6
|
+
behavior: BusinessClosedBehavior | null;
|
|
7
|
+
message: string | MultiLangObject | null;
|
|
8
|
+
/** Epoch milliseconds. Re-evaluate the cached configuration at this time. */
|
|
9
|
+
nextChangeAt: number;
|
|
10
|
+
requirePaymentOnSubmit: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface BusinessAvailabilityConfig {
|
|
14
|
+
paused: boolean;
|
|
15
|
+
pauseBehavior: BusinessClosedBehavior;
|
|
16
|
+
closedBehavior: BusinessClosedBehavior;
|
|
17
|
+
pauseMessage: BusinessAvailability['message'];
|
|
18
|
+
closedMessage: BusinessAvailability['message'];
|
|
19
|
+
scheduleIds: number[];
|
|
20
|
+
invalidScheduleIds: boolean;
|
|
21
|
+
requirePaymentOnSubmit: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function normalizeBusinessAvailabilityConfig(data: Record<string, unknown>): BusinessAvailabilityConfig;
|
|
24
|
+
/** Business ordering is independent of reservation switches and Pickup slot availability. */
|
|
25
|
+
export declare function computeBusinessAvailability(input: {
|
|
26
|
+
config: BusinessAvailabilityConfig;
|
|
27
|
+
schedules: ScheduleItem[];
|
|
28
|
+
timezone: string;
|
|
29
|
+
now: Date;
|
|
30
|
+
}): BusinessAvailability;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.computeBusinessAvailability = computeBusinessAvailability;
|
|
7
|
+
exports.normalizeBusinessAvailabilityConfig = normalizeBusinessAvailabilityConfig;
|
|
8
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
9
|
+
var _isSameOrAfter = _interopRequireDefault(require("dayjs/plugin/isSameOrAfter"));
|
|
10
|
+
var _isSameOrBefore = _interopRequireDefault(require("dayjs/plugin/isSameOrBefore"));
|
|
11
|
+
var _getDateIsInSchedule = require("../Schedule/getDateIsInSchedule");
|
|
12
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
13
|
+
_dayjs.default.extend(_isSameOrAfter.default);
|
|
14
|
+
_dayjs.default.extend(_isSameOrBefore.default);
|
|
15
|
+
const DAY = 86_400_000;
|
|
16
|
+
const behavior = value => value === 'show_menu_disabled' ? value : 'hide_all';
|
|
17
|
+
const message = value => typeof value === 'string' || value !== null && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
18
|
+
function normalizeBusinessAvailabilityConfig(data) {
|
|
19
|
+
const rawIds = data['availability.operating_hours'];
|
|
20
|
+
const ids = Array.isArray(rawIds) ? rawIds.map(id => typeof id === 'number' || typeof id === 'string' ? Number(id) : NaN) : [];
|
|
21
|
+
const validIds = ids.filter(id => Number.isInteger(id) && id > 0);
|
|
22
|
+
const paused = data['availability.paused'];
|
|
23
|
+
return {
|
|
24
|
+
paused: paused === true || paused === 1 || paused === 'true' || paused === '1',
|
|
25
|
+
pauseBehavior: behavior(data['availability.pause_behavior']),
|
|
26
|
+
closedBehavior: behavior(data['availability.closed_behavior']),
|
|
27
|
+
pauseMessage: message(data['availability.pause_message']),
|
|
28
|
+
closedMessage: message(data['availability.closed_message']),
|
|
29
|
+
scheduleIds: [...new Set(validIds)],
|
|
30
|
+
invalidScheduleIds: rawIds != null && (!Array.isArray(rawIds) || validIds.length !== ids.length),
|
|
31
|
+
// Only an explicitly disabled setting changes the existing payment flow.
|
|
32
|
+
requirePaymentOnSubmit: data['sale.require_payment_on_submit'] !== false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function createClock(timezone) {
|
|
36
|
+
if (!timezone) throw new Error('Store timezone is unavailable.');
|
|
37
|
+
const formatter = new Intl.DateTimeFormat('en-GB', {
|
|
38
|
+
timeZone: timezone,
|
|
39
|
+
year: 'numeric',
|
|
40
|
+
month: '2-digit',
|
|
41
|
+
day: '2-digit',
|
|
42
|
+
hour: '2-digit',
|
|
43
|
+
minute: '2-digit',
|
|
44
|
+
second: '2-digit',
|
|
45
|
+
hourCycle: 'h23'
|
|
46
|
+
});
|
|
47
|
+
const local = timestamp => {
|
|
48
|
+
const parts = {};
|
|
49
|
+
formatter.formatToParts(timestamp).forEach(part => {
|
|
50
|
+
parts[part.type] = part.value;
|
|
51
|
+
});
|
|
52
|
+
const date = `${parts.year}-${parts.month}-${parts.day}`;
|
|
53
|
+
return {
|
|
54
|
+
date,
|
|
55
|
+
scalar: Date.parse(`${date}T${parts.hour}:${parts.minute}:${parts.second}Z`)
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
const offsets = new Set();
|
|
59
|
+
const instants = scalar => {
|
|
60
|
+
offsets.clear();
|
|
61
|
+
for (let hours = -36; hours <= 36; hours += 6) {
|
|
62
|
+
const sample = scalar + hours * 3_600_000;
|
|
63
|
+
offsets.add(local(sample).scalar - sample);
|
|
64
|
+
}
|
|
65
|
+
return [...offsets].map(offset => scalar - offset).filter(instant => local(instant).scalar === scalar).sort((a, b) => a - b);
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
local,
|
|
69
|
+
instants
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Business ordering is independent of reservation switches and Pickup slot availability. */
|
|
74
|
+
function computeBusinessAvailability(input) {
|
|
75
|
+
const {
|
|
76
|
+
config,
|
|
77
|
+
schedules,
|
|
78
|
+
timezone,
|
|
79
|
+
now
|
|
80
|
+
} = input;
|
|
81
|
+
const nowAt = now.getTime();
|
|
82
|
+
const base = {
|
|
83
|
+
requirePaymentOnSubmit: config.requirePaymentOnSubmit,
|
|
84
|
+
nextChangeAt: nowAt + DAY
|
|
85
|
+
};
|
|
86
|
+
if (config.paused) {
|
|
87
|
+
return {
|
|
88
|
+
...base,
|
|
89
|
+
status: 'paused',
|
|
90
|
+
behavior: config.pauseBehavior,
|
|
91
|
+
message: config.pauseMessage
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (config.invalidScheduleIds) throw new Error('Business operating-hours configuration is invalid.');
|
|
95
|
+
if (!config.scheduleIds.length) return {
|
|
96
|
+
...base,
|
|
97
|
+
status: 'open',
|
|
98
|
+
behavior: null,
|
|
99
|
+
message: null
|
|
100
|
+
};
|
|
101
|
+
const selected = schedules.filter(schedule => config.scheduleIds.includes(Number(schedule.id)));
|
|
102
|
+
if (config.scheduleIds.some(id => !selected.some(schedule => Number(schedule.id) === id))) {
|
|
103
|
+
throw new Error('A configured business operating-hours schedule is unavailable.');
|
|
104
|
+
}
|
|
105
|
+
const clock = createClock(timezone);
|
|
106
|
+
const current = clock.local(nowAt);
|
|
107
|
+
const today = Date.parse(`${current.date}T00:00:00Z`);
|
|
108
|
+
const nextMidnight = clock.instants(today + DAY).find(instant => instant > nowAt);
|
|
109
|
+
let nextChangeAt = nextMidnight ?? nowAt + 60_000;
|
|
110
|
+
let open = false;
|
|
111
|
+
// Yesterday contributes the tail of overnight windows; today supplies the next boundary.
|
|
112
|
+
for (const dateAt of [today - DAY, today]) {
|
|
113
|
+
const date = new Date(dateAt).toISOString().slice(0, 10);
|
|
114
|
+
// Schedule's resolver merges by time-of-day, so resolve each schedule independently.
|
|
115
|
+
for (const schedule of selected) {
|
|
116
|
+
for (const window of (0, _getDateIsInSchedule.getScheduleStartEndTimePoints)(date, [schedule])) {
|
|
117
|
+
const toMinutes = value => {
|
|
118
|
+
if (!/^(?:[01]\d|2[0-3]):[0-5]\d$/.test(value) && value !== '24:00') {
|
|
119
|
+
throw new Error('Business operating-hours schedule contains an invalid time.');
|
|
120
|
+
}
|
|
121
|
+
const [hours, minutes] = value.split(':').map(Number);
|
|
122
|
+
return hours * 60 + minutes;
|
|
123
|
+
};
|
|
124
|
+
const start = dateAt + toMinutes(window.start_time) * 60_000;
|
|
125
|
+
let end = dateAt + toMinutes(window.end_time) * 60_000;
|
|
126
|
+
if (end <= start) end += DAY;
|
|
127
|
+
if (current.scalar >= start && current.scalar < end) open = true;
|
|
128
|
+
for (const boundary of [start, end]) {
|
|
129
|
+
for (const instant of clock.instants(boundary)) {
|
|
130
|
+
if (instant > nowAt) nextChangeAt = Math.min(nextChangeAt, instant);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// A timezone offset change can repeat/skip a wall-clock boundary. A local-only safety
|
|
137
|
+
// check also covers throttled timers; it does not fetch either configuration source.
|
|
138
|
+
nextChangeAt = Math.min(nextChangeAt, nowAt + 60_000);
|
|
139
|
+
return {
|
|
140
|
+
...base,
|
|
141
|
+
nextChangeAt,
|
|
142
|
+
status: open ? 'open' : 'closed',
|
|
143
|
+
behavior: open ? null : config.closedBehavior,
|
|
144
|
+
message: open ? null : config.closedMessage
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -69,6 +69,8 @@ export interface OpenDataConfig {
|
|
|
69
69
|
'reservation.time_slice'?: number | string;
|
|
70
70
|
'sale.allow_item_notes'?: boolean;
|
|
71
71
|
'sale.allow_order_notes'?: boolean;
|
|
72
|
+
/** False submits an order without starting or confirming payment. */
|
|
73
|
+
'sale.require_payment_on_submit'?: boolean | null;
|
|
72
74
|
'sale.enable_item_rules'?: boolean;
|
|
73
75
|
'sale.enable_short_number'?: boolean;
|
|
74
76
|
'sale.short_number_daily_reset'?: boolean;
|
|
@@ -4,7 +4,7 @@ import { OrderModuleAPI, CommitOrderParams, UpdateOrderBookingParams, UpdateOrde
|
|
|
4
4
|
import { CartItem } from '../Cart/types';
|
|
5
5
|
import { type SubmitPayloadEnhancer } from './utils';
|
|
6
6
|
import { type PickupTimingBooking, type PickupTimingBookingInput } from './pickupTiming';
|
|
7
|
-
import type { OrderAmountSnapshot, AddProductBookingInput, AddProductToOrderOptions, OrderIdentitySnapshot, OrderPaymentSource, OrderSnapshot, OrderSyncState, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, SubmitSalesOrderParams, OrderProduct, OrderProductIdentity, OrderSummary, OrderTempOrder, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, SendCustomerPayLinkParams, UpdateTempOrderCustomerInput, OrderCustomerPatch, OrderCustomerView, ReplaceTempOrderOptions, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, PointCardSnapshotMergeContext, PointCardSnapshotItem, ShopServiceData, ShopServiceType } from './types';
|
|
7
|
+
import type { OrderAmountSnapshot, AddProductBookingInput, AddProductToOrderOptions, OrderIdentitySnapshot, OrderPaymentSource, OrderSnapshot, OrderSyncState, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, SubmitSalesOrderParams, OrderProduct, OrderProductIdentity, OrderSummary, OrderTempOrder, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, SendCustomerPayLinkParams, UpdateTempOrderCustomerInput, OrderCustomerPatch, OrderCustomerView, OrderCartIntentCommitContext, ReplaceTempOrderOptions, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, PointCardSnapshotMergeContext, PointCardSnapshotItem, ShopServiceData, ShopServiceType } from './types';
|
|
8
8
|
import type { ICustomer } from '../AccountList/types';
|
|
9
9
|
import type { Discount } from '../Discount/types';
|
|
10
10
|
import { UnavailableReason } from '../Rules/types';
|
|
@@ -67,6 +67,8 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
67
67
|
* orderModule.updateOtherParams({ cacheId: 'cache-2', channel: 'pos' });
|
|
68
68
|
*/
|
|
69
69
|
updateOtherParams(params: Record<string, any>): void;
|
|
70
|
+
/** Internal intent boundary shared with asynchronous scanner/detail flows. */
|
|
71
|
+
createCartIntentCommitGuard(action: OrderCartIntentCommitContext['action'], tempOrder?: OrderTempOrder | null): () => void;
|
|
70
72
|
/** PC/H5 属于在线店铺;其它或缺失平台统一沿用 POS 行为。 */
|
|
71
73
|
isOnlineStorePlatform(): boolean;
|
|
72
74
|
/**
|
|
@@ -501,6 +503,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
501
503
|
private hasSameEntitlementMergePriceConfig;
|
|
502
504
|
private getBundleRuntimeIdentity;
|
|
503
505
|
private preservePersistedBundlePriceFields;
|
|
506
|
+
private isRestrictedCartProductUpdate;
|
|
504
507
|
private applyOrderProductUpdateToTempOrder;
|
|
505
508
|
updateOrderProduct(params: UpdateOrderProductParams): Promise<OrderProduct[]>;
|
|
506
509
|
updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<OrderProduct[]>;
|
|
@@ -588,7 +591,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
588
591
|
generateIdempotencyToken(): string;
|
|
589
592
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|
|
590
593
|
createOrder(params: CommitOrderParams['query']): {
|
|
591
|
-
type: "
|
|
594
|
+
type: "virtual" | "appointment_booking";
|
|
592
595
|
platform: string;
|
|
593
596
|
sales_channel: string;
|
|
594
597
|
order_sales_channel: string;
|
|
@@ -440,6 +440,29 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
440
440
|
this.otherParams = otherParams;
|
|
441
441
|
}
|
|
442
442
|
|
|
443
|
+
/** Internal intent boundary shared with asynchronous scanner/detail flows. */
|
|
444
|
+
createCartIntentCommitGuard(action, tempOrder = this.store.tempOrder) {
|
|
445
|
+
const hook = this.orderHooks?.beforeCartIntentCommit;
|
|
446
|
+
if (!hook) return () => {};
|
|
447
|
+
const getScope = this.orderHooks?.getCartIntentScope;
|
|
448
|
+
const scope = getScope?.();
|
|
449
|
+
const otherParams = this.otherParams;
|
|
450
|
+
let committed = false;
|
|
451
|
+
return () => {
|
|
452
|
+
if (this.store.tempOrder !== tempOrder || this.otherParams !== otherParams || this.orderHooks?.beforeCartIntentCommit !== hook || this.orderHooks?.getCartIntentScope !== getScope || getScope?.() !== scope) {
|
|
453
|
+
throw new Error('[Order] Cart intent belongs to a previous order or business');
|
|
454
|
+
}
|
|
455
|
+
// Derived gifts, discounts and persistence belong to the accepted intent,
|
|
456
|
+
// but an asynchronous continuation must never target a different cart.
|
|
457
|
+
if (committed) return;
|
|
458
|
+
hook({
|
|
459
|
+
action,
|
|
460
|
+
tempOrder
|
|
461
|
+
});
|
|
462
|
+
committed = true;
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
443
466
|
/** PC/H5 属于在线店铺;其它或缺失平台统一沿用 POS 行为。 */
|
|
444
467
|
isOnlineStorePlatform() {
|
|
445
468
|
const platform = String(this.otherParams?.platform || '').trim().toLowerCase();
|
|
@@ -668,6 +691,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
668
691
|
});
|
|
669
692
|
}
|
|
670
693
|
async scanCode(code, customerId) {
|
|
694
|
+
const beforeCommit = this.createCartIntentCommitGuard('scan_promotion');
|
|
671
695
|
if (this.isActiveVirtualSettlementOrder(this.store.tempOrder)) {
|
|
672
696
|
return {
|
|
673
697
|
type: 'clientCalc',
|
|
@@ -715,6 +739,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
715
739
|
}));
|
|
716
740
|
const currentSelected = this.getDiscountList().filter(n => n.isSelected);
|
|
717
741
|
if (currentSelected.length && currentSelected.some(n => withScanList.some(m => m.id === n.id))) {
|
|
742
|
+
beforeCommit();
|
|
718
743
|
await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
|
|
719
744
|
return {
|
|
720
745
|
type: 'clientCalc',
|
|
@@ -748,6 +773,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
748
773
|
const normalizedNewDiscountList = newDiscountList ? markScannedDiscounts(newDiscountList, withScanList) : undefined;
|
|
749
774
|
let resolvedDiscountList = normalizedNewDiscountList || this.getDiscountList();
|
|
750
775
|
if (isAvailable && normalizedNewDiscountList) {
|
|
776
|
+
beforeCommit();
|
|
751
777
|
await this.store.discount?.setDiscountList(normalizedNewDiscountList);
|
|
752
778
|
// 实际写回商品时沿用扫码试算的优先级,避免旧商品行的选卡覆盖本次扫码。
|
|
753
779
|
this.applyDiscount({
|
|
@@ -756,6 +782,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
756
782
|
await this.syncScannedDiscountsToOriginalDiscountList(this.getDiscountList());
|
|
757
783
|
resolvedDiscountList = this.getDiscountList();
|
|
758
784
|
} else if (shouldRetainForLater) {
|
|
785
|
+
beforeCommit();
|
|
759
786
|
// 只合并本次识别的卡券;不把试算产生的其他选券状态写回订单。
|
|
760
787
|
const retainedDiscounts = new Map(this.getDiscountList().map(discount => [String(discount.id), discount]));
|
|
761
788
|
evaluatedScannedDiscounts.forEach(discount => {
|
|
@@ -3462,7 +3489,6 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3462
3489
|
}) : null;
|
|
3463
3490
|
const productToAdd = linked?.product || product;
|
|
3464
3491
|
const disableMerge = options?.disableMerge === true;
|
|
3465
|
-
this.assertAndLockProductSettlement(tempOrder, productToAdd);
|
|
3466
3492
|
const incomingFingerprint = disableMerge ? '' : (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(productToAdd), productToAdd.product_bundle);
|
|
3467
3493
|
const normalizedIncoming = this.normalizeVirtualSettlementProductIfEnabled((0, _utils.mergeOrderProductDisplayFields)(productToAdd, (0, _utils3.normalizeOrderProduct)(productToAdd)));
|
|
3468
3494
|
if (disableMerge) {
|
|
@@ -3523,6 +3549,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3523
3549
|
const matchedProduct = matchedIndex === -1 ? null : tempOrder.products[matchedIndex];
|
|
3524
3550
|
const existedFingerprint = matchedProduct ? (0, _utils3.buildProductLineFingerprint)((0, _utils.getProductSkuOptions)(matchedProduct), matchedProduct.product_bundle) : '';
|
|
3525
3551
|
const commitProductLine = shouldMerge => {
|
|
3552
|
+
options?.beforeCommit?.();
|
|
3553
|
+
this.assertAndLockProductSettlement(tempOrder, productToAdd);
|
|
3526
3554
|
let committedProduct;
|
|
3527
3555
|
if (matchedIndex === -1 || !matchedProduct || !shouldMerge) {
|
|
3528
3556
|
this.captureProductRuntime(tempOrder, productToAdd, normalizedIncoming);
|
|
@@ -3675,6 +3703,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3675
3703
|
*/
|
|
3676
3704
|
async addProductToOrder(product, booking, options) {
|
|
3677
3705
|
const tempOrder = this.ensureTempOrder();
|
|
3706
|
+
const beforeCommit = this.createCartIntentCommitGuard('add_product', tempOrder);
|
|
3678
3707
|
const salesNoteDrafts = (options?.salesNotes || []).map(draft => ({
|
|
3679
3708
|
note_type: String(draft.note_type || '').trim(),
|
|
3680
3709
|
text: {
|
|
@@ -3745,7 +3774,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3745
3774
|
}
|
|
3746
3775
|
const committedProduct = await this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking, {
|
|
3747
3776
|
insertAtIndex,
|
|
3748
|
-
disableMerge: options?.disableMerge
|
|
3777
|
+
disableMerge: options?.disableMerge,
|
|
3778
|
+
beforeCommit
|
|
3749
3779
|
});
|
|
3750
3780
|
attachSalesNoteDrafts(committedProduct);
|
|
3751
3781
|
if (insertAtIndex !== undefined) insertAtIndex += 1;
|
|
@@ -3753,14 +3783,16 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3753
3783
|
} else {
|
|
3754
3784
|
const committedProduct = await this.appendProductLineToTempOrder(tempOrder, product, (0, _lodashEs.cloneDeep)(booking), {
|
|
3755
3785
|
insertAtIndex,
|
|
3756
|
-
disableMerge: options?.disableMerge
|
|
3786
|
+
disableMerge: options?.disableMerge,
|
|
3787
|
+
beforeCommit
|
|
3757
3788
|
});
|
|
3758
3789
|
attachSalesNoteDrafts(committedProduct);
|
|
3759
3790
|
}
|
|
3760
3791
|
} else {
|
|
3761
3792
|
const committedProduct = await this.appendProductLineToTempOrder(tempOrder, product, undefined, {
|
|
3762
3793
|
insertAtIndex,
|
|
3763
|
-
disableMerge: options?.disableMerge
|
|
3794
|
+
disableMerge: options?.disableMerge,
|
|
3795
|
+
beforeCommit
|
|
3764
3796
|
});
|
|
3765
3797
|
attachSalesNoteDrafts(committedProduct);
|
|
3766
3798
|
}
|
|
@@ -3788,6 +3820,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3788
3820
|
async addProductsToOrder(items, options) {
|
|
3789
3821
|
const tempOrder = this.ensureTempOrder();
|
|
3790
3822
|
if (!Array.isArray(items) || items.length === 0) return tempOrder.products;
|
|
3823
|
+
const beforeCommit = this.createCartIntentCommitGuard('add_product', tempOrder);
|
|
3791
3824
|
for (const item of items || []) {
|
|
3792
3825
|
const {
|
|
3793
3826
|
product,
|
|
@@ -3800,13 +3833,17 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3800
3833
|
if (splitCount > 1) {
|
|
3801
3834
|
for (let i = 0; i < splitCount; i += 1) {
|
|
3802
3835
|
const splitLine = this.createSplitBookingLine(productRecord, booking, i, splitCount);
|
|
3803
|
-
const appendResult = this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking
|
|
3836
|
+
const appendResult = this.appendProductLineToTempOrder(tempOrder, splitLine.product, splitLine.booking, {
|
|
3837
|
+
beforeCommit
|
|
3838
|
+
});
|
|
3804
3839
|
if (appendResult) await appendResult;
|
|
3805
3840
|
}
|
|
3806
3841
|
continue;
|
|
3807
3842
|
}
|
|
3808
3843
|
}
|
|
3809
|
-
const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking
|
|
3844
|
+
const appendResult = this.appendProductLineToTempOrder(tempOrder, product, booking, {
|
|
3845
|
+
beforeCommit
|
|
3846
|
+
});
|
|
3810
3847
|
if (appendResult) await appendResult;
|
|
3811
3848
|
}
|
|
3812
3849
|
await this.finalizeProductOrderMutation(tempOrder, options);
|
|
@@ -3891,6 +3928,16 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3891
3928
|
};
|
|
3892
3929
|
});
|
|
3893
3930
|
}
|
|
3931
|
+
isRestrictedCartProductUpdate(tempOrder, params) {
|
|
3932
|
+
if (!this.orderHooks?.beforeCartIntentCommit) return false;
|
|
3933
|
+
if (params.booking || Object.keys(params.updates || {}).some(key => key !== 'num')) {
|
|
3934
|
+
return true;
|
|
3935
|
+
}
|
|
3936
|
+
if (params.updates?.num === undefined) return false;
|
|
3937
|
+
const uid = params.unique_identification_number;
|
|
3938
|
+
const product = uid !== undefined ? tempOrder.products.find(item => String(item.metadata?.unique_identification_number || item.unique_identification_number || '') === String(uid)) : tempOrder.products[(0, _utils3.getProductIdentityIndex)(tempOrder.products, params)];
|
|
3939
|
+
return !product || (0, _utils3.getSafeProductNum)(params.updates.num) > product.num;
|
|
3940
|
+
}
|
|
3894
3941
|
applyOrderProductUpdateToTempOrder(tempOrder, params) {
|
|
3895
3942
|
const {
|
|
3896
3943
|
product_id,
|
|
@@ -4089,6 +4136,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4089
4136
|
}
|
|
4090
4137
|
async updateOrderProduct(params) {
|
|
4091
4138
|
const tempOrder = this.ensureTempOrder();
|
|
4139
|
+
if (this.isRestrictedCartProductUpdate(tempOrder, params)) {
|
|
4140
|
+
this.createCartIntentCommitGuard('update_product', tempOrder)();
|
|
4141
|
+
}
|
|
4092
4142
|
const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
4093
4143
|
const promotionPayload = await this.evaluatePromotion();
|
|
4094
4144
|
this.applyDiscount({
|
|
@@ -4110,6 +4160,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4110
4160
|
if (!paramsList.length) {
|
|
4111
4161
|
return tempOrder.products;
|
|
4112
4162
|
}
|
|
4163
|
+
if (paramsList.some(params => this.isRestrictedCartProductUpdate(tempOrder, params))) {
|
|
4164
|
+
this.createCartIntentCommitGuard('update_product', tempOrder)();
|
|
4165
|
+
}
|
|
4113
4166
|
const reapplyBookingDiscountProductUids = paramsList.reduce((acc, params) => {
|
|
4114
4167
|
const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
4115
4168
|
// 批量改预约时间时,延迟到最后一次折扣计算里统一恢复已选预约折扣卡。
|
|
@@ -4192,6 +4245,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4192
4245
|
throw new _virtualSettlement.VirtualCurrencyBalanceError(balance.toFixed(2), requiredAmount.toFixed(2));
|
|
4193
4246
|
}
|
|
4194
4247
|
}
|
|
4248
|
+
if (normalizedProduct.num > targetProduct.num) {
|
|
4249
|
+
this.createCartIntentCommitGuard('increase_quantity', tempOrder)();
|
|
4250
|
+
}
|
|
4195
4251
|
tempOrder.products[productIndex] = normalizedProduct;
|
|
4196
4252
|
this.prepareVirtualSettlementTempOrder(tempOrder);
|
|
4197
4253
|
const isVirtualSettlement = this.isActiveVirtualSettlementOrder(tempOrder);
|
|
@@ -517,7 +517,15 @@ export type OrderProductMergeDecisionResult = boolean | {
|
|
|
517
517
|
reason?: string;
|
|
518
518
|
[key: string]: any;
|
|
519
519
|
};
|
|
520
|
+
export interface OrderCartIntentCommitContext {
|
|
521
|
+
action: 'add_product' | 'update_product' | 'increase_quantity' | 'scan_promotion';
|
|
522
|
+
tempOrder: OrderTempOrder | null;
|
|
523
|
+
}
|
|
520
524
|
export interface OrderHooksConfig {
|
|
525
|
+
/** Optional customer-order guard; called synchronously before the first cart write. */
|
|
526
|
+
beforeCartIntentCommit?: (context: OrderCartIntentCommitContext) => void;
|
|
527
|
+
/** Captures tenant/business runtime identity for asynchronous cart intents. */
|
|
528
|
+
getCartIntentScope?: () => unknown;
|
|
521
529
|
onBeforeMergeProductToOrder?: (context: OrderProductMergeDecisionContext) => OrderProductMergeDecisionResult | Promise<OrderProductMergeDecisionResult>;
|
|
522
530
|
}
|
|
523
531
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
|
-
import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
|
|
3
|
+
import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesSubmitSalesOrderParams, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
|
|
4
4
|
import { OrderModule } from '../../modules/Order';
|
|
5
5
|
import { type PickupTimingBookingInput } from '../../modules/Order/pickupTiming';
|
|
6
6
|
import type { PickupTimingAvailability, PickupTimingSelection, PickupTimingValidationResult } from '../../modules/FulfillmentTiming';
|
|
@@ -337,13 +337,8 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
337
337
|
productList?: Record<string, any>[];
|
|
338
338
|
discountList?: Discount[];
|
|
339
339
|
}): Promise<void>;
|
|
340
|
-
submitScanOrder<T = any>(params?:
|
|
341
|
-
|
|
342
|
-
paymentStatus?: BaseSalesPaymentStatus;
|
|
343
|
-
smallTicketDataFlag?: number;
|
|
344
|
-
confirmPendingVoucherPayments?: boolean;
|
|
345
|
-
enhancePayload?: SubmitPayloadEnhancer;
|
|
346
|
-
}): Promise<T>;
|
|
340
|
+
submitScanOrder<T = any>(params?: BaseSalesSubmitSalesOrderParams): Promise<T>;
|
|
341
|
+
private buildVirtualSettlementOrderData;
|
|
347
342
|
private buildVirtualSettlementSubmitData;
|
|
348
343
|
/**
|
|
349
344
|
* 提交当前 Sales 订单。
|
|
@@ -351,13 +346,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
351
346
|
* PaymentModal 场景通过 smallTicketDataFlag=1 请求 B 端小票数据;
|
|
352
347
|
* payments 会交给 OrderModule 统一映射为 Sales 协议支付项。
|
|
353
348
|
*/
|
|
354
|
-
submitSalesOrder<T = any>(params?:
|
|
355
|
-
payments?: OrderPaymentSource[];
|
|
356
|
-
paymentStatus?: BaseSalesPaymentStatus;
|
|
357
|
-
smallTicketDataFlag?: number;
|
|
358
|
-
confirmPendingVoucherPayments?: boolean;
|
|
359
|
-
enhancePayload?: SubmitPayloadEnhancer;
|
|
360
|
-
}): Promise<T>;
|
|
349
|
+
submitSalesOrder<T = any>(params?: BaseSalesSubmitSalesOrderParams): Promise<T>;
|
|
361
350
|
saveSalesOrderDraft<T = any>(params?: {
|
|
362
351
|
platform?: string;
|
|
363
352
|
businessCode?: string;
|
|
@@ -2432,7 +2432,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2432
2432
|
// Deprecated compatibility alias. New BaseSales callers should use submitSalesOrder.
|
|
2433
2433
|
return this.submitSalesOrder(params);
|
|
2434
2434
|
}
|
|
2435
|
-
|
|
2435
|
+
buildVirtualSettlementOrderData() {
|
|
2436
2436
|
if (!this.store.order) return null;
|
|
2437
2437
|
const tempOrder = this.store.order.getTempOrder();
|
|
2438
2438
|
if (!this.isActiveVirtualSettlementOrder(tempOrder)) return null;
|
|
@@ -2441,6 +2441,21 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2441
2441
|
if (!snapshot || !Number.isFinite(currencyProductId) || currencyProductId <= 0) {
|
|
2442
2442
|
throw new Error('Virtual currency settlement configuration is invalid.');
|
|
2443
2443
|
}
|
|
2444
|
+
return {
|
|
2445
|
+
snapshot,
|
|
2446
|
+
currencyProductId,
|
|
2447
|
+
currencyCode: String(tempOrder?.currency_code || ''),
|
|
2448
|
+
currencySymbol: String(tempOrder?.currency_symbol || ''),
|
|
2449
|
+
currencyFormat: String(tempOrder?.currency_format || 'symbol_first')
|
|
2450
|
+
};
|
|
2451
|
+
}
|
|
2452
|
+
async buildVirtualSettlementSubmitData() {
|
|
2453
|
+
const settlement = this.buildVirtualSettlementOrderData();
|
|
2454
|
+
if (!settlement || !this.store.order) return null;
|
|
2455
|
+
const tempOrder = this.store.order.getTempOrder();
|
|
2456
|
+
const {
|
|
2457
|
+
currencyProductId
|
|
2458
|
+
} = settlement;
|
|
2444
2459
|
const summary = await this.store.order.recalculateSummary({
|
|
2445
2460
|
createIfMissing: true
|
|
2446
2461
|
});
|
|
@@ -2455,17 +2470,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2455
2470
|
});
|
|
2456
2471
|
}
|
|
2457
2472
|
const asset = this.store.order.getVirtualCurrencyList().find(item => Number(item?.product_id) === currencyProductId);
|
|
2458
|
-
const currencyCode = String(tempOrder?.currency_code || '');
|
|
2459
|
-
const currencySymbol = String(tempOrder?.currency_symbol || '');
|
|
2460
|
-
const currencyFormat = String(tempOrder?.currency_format || 'symbol_first');
|
|
2461
2473
|
if (amount.lte(0)) {
|
|
2462
2474
|
return {
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
currencyProductId,
|
|
2466
|
-
currencyCode,
|
|
2467
|
-
currencySymbol,
|
|
2468
|
-
currencyFormat
|
|
2475
|
+
...settlement,
|
|
2476
|
+
payments: []
|
|
2469
2477
|
};
|
|
2470
2478
|
}
|
|
2471
2479
|
if (!asset) {
|
|
@@ -2519,12 +2527,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2519
2527
|
};
|
|
2520
2528
|
}
|
|
2521
2529
|
return {
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
currencyProductId,
|
|
2525
|
-
currencyCode,
|
|
2526
|
-
currencySymbol,
|
|
2527
|
-
currencyFormat
|
|
2530
|
+
...settlement,
|
|
2531
|
+
payments: [payment]
|
|
2528
2532
|
};
|
|
2529
2533
|
}
|
|
2530
2534
|
|
|
@@ -2541,9 +2545,11 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2541
2545
|
if (this.isPickupTimingEnabled()) await this.preparePickupTimingForCheckout({
|
|
2542
2546
|
freeze: true
|
|
2543
2547
|
});
|
|
2544
|
-
const
|
|
2548
|
+
const isDeferredPayment = params?.paymentExecution === 'deferred';
|
|
2549
|
+
const virtualPaymentSettlement = isDeferredPayment ? null : await this.buildVirtualSettlementSubmitData();
|
|
2550
|
+
const virtualSettlement = isDeferredPayment ? this.buildVirtualSettlementOrderData() : virtualPaymentSettlement;
|
|
2545
2551
|
// this.store.order.persistTempOrder();
|
|
2546
|
-
const inferredPaymentStatus = this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2552
|
+
const inferredPaymentStatus = isDeferredPayment ? undefined : this.getSubmitPaymentStatus(params?.paymentStatus);
|
|
2547
2553
|
const smallTicketDataFlag = params?.smallTicketDataFlag ?? this.getDefaultCheckoutSmallTicketDataFlag();
|
|
2548
2554
|
const virtualSettlementEnhancePayload = virtualSettlement ? (payload, ctx) => {
|
|
2549
2555
|
const callerPayload = params?.enhancePayload ? params.enhancePayload(payload, ctx) : payload;
|
|
@@ -2564,7 +2570,20 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2564
2570
|
currency_format: virtualSettlement.currencyFormat
|
|
2565
2571
|
};
|
|
2566
2572
|
} : params?.enhancePayload;
|
|
2567
|
-
const
|
|
2573
|
+
const configuredEnhancePayload = this.buildSubmitPayloadEnhancerWithOpenDataConfig(virtualSettlementEnhancePayload);
|
|
2574
|
+
// Apply this last so neither a stale draft status nor a caller enhancer can
|
|
2575
|
+
// turn deferred submission into payment. The live wallet selection is untouched.
|
|
2576
|
+
const enhancePayload = isDeferredPayment ? (payload, ctx) => {
|
|
2577
|
+
const enhancedPayload = configuredEnhancePayload ? configuredEnhancePayload(payload, ctx) : payload;
|
|
2578
|
+
const {
|
|
2579
|
+
payment_status: _paymentStatus,
|
|
2580
|
+
...orderPayload
|
|
2581
|
+
} = enhancedPayload;
|
|
2582
|
+
return {
|
|
2583
|
+
...orderPayload,
|
|
2584
|
+
payments: []
|
|
2585
|
+
};
|
|
2586
|
+
} : configuredEnhancePayload;
|
|
2568
2587
|
const submitParams = {
|
|
2569
2588
|
cacheId: this.cacheId,
|
|
2570
2589
|
platform: this.otherParams?.platform,
|
|
@@ -2572,8 +2591,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2572
2591
|
channel: this.getSubmitOrderSalesChannel(),
|
|
2573
2592
|
type: this.otherParams?.type,
|
|
2574
2593
|
request_unique_idempotency_token: this.store.order.generateIdempotencyToken(),
|
|
2575
|
-
...(
|
|
2576
|
-
payments:
|
|
2594
|
+
...(isDeferredPayment ? {
|
|
2595
|
+
payments: []
|
|
2596
|
+
} : virtualPaymentSettlement ? {
|
|
2597
|
+
payments: virtualPaymentSettlement.payments
|
|
2577
2598
|
} : params?.payments !== undefined ? {
|
|
2578
2599
|
payments: params.payments
|
|
2579
2600
|
} : {}),
|
|
@@ -2583,7 +2604,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
2583
2604
|
...(smallTicketDataFlag !== undefined ? {
|
|
2584
2605
|
smallTicketDataFlag
|
|
2585
2606
|
} : {}),
|
|
2586
|
-
...(virtualSettlement ? {
|
|
2607
|
+
...(isDeferredPayment || virtualSettlement ? {
|
|
2587
2608
|
confirmPendingVoucherPayments: false
|
|
2588
2609
|
} : params?.confirmPendingVoucherPayments !== undefined ? {
|
|
2589
2610
|
confirmPendingVoucherPayments: params.confirmPendingVoucherPayments
|
|
@@ -3921,7 +3942,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3921
3942
|
async addProductToOrder(product, booking, options) {
|
|
3922
3943
|
try {
|
|
3923
3944
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3924
|
-
const products = await this.store.order.addProductToOrder(product, booking, options);
|
|
3945
|
+
const products = options === undefined ? await this.store.order.addProductToOrder(product, booking) : await this.store.order.addProductToOrder(product, booking, options);
|
|
3925
3946
|
// // 需要叠加
|
|
3926
3947
|
// if (this.hooks.onAddProductOverlay) {
|
|
3927
3948
|
// const res = this.hooks.onAddProductOverlay(是否叠加, product)
|
|
@@ -4010,7 +4031,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
4010
4031
|
async removeProductsFromOrder(identities, options) {
|
|
4011
4032
|
try {
|
|
4012
4033
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
4013
|
-
return await this.store.order.removeProductsFromOrder(identities, options);
|
|
4034
|
+
return options === undefined ? await this.store.order.removeProductsFromOrder(identities) : await this.store.order.removeProductsFromOrder(identities, options);
|
|
4014
4035
|
} catch (error) {
|
|
4015
4036
|
throw error;
|
|
4016
4037
|
}
|