@pisell/pisellos 2.2.314 → 2.2.315
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/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
- package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
- package/dist/model/strategy/adapter/itemRule/type.js +10 -0
- package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/dist/modules/BookingContext/utils/productExtend.js +62 -18
- package/dist/modules/BookingContext/utils/resources.js +1 -1
- package/dist/modules/BusinessAvailability/index.d.ts +30 -0
- package/dist/modules/BusinessAvailability/index.js +204 -0
- package/dist/modules/Cart/index.js +4 -3
- package/dist/modules/Cart/types.d.ts +2 -0
- package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
- package/dist/modules/Cart/utils/cartProduct.js +59 -32
- package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
- package/dist/modules/FulfillmentTiming/index.js +407 -0
- package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
- package/dist/modules/FulfillmentTiming/types.js +1 -0
- package/dist/modules/OpenData/types.d.ts +14 -0
- package/dist/modules/Order/index.d.ts +14 -2
- package/dist/modules/Order/index.js +856 -486
- package/dist/modules/Order/localEftposState.d.ts +13 -0
- package/dist/modules/Order/localEftposState.js +39 -0
- package/dist/modules/Order/pickupTiming.d.ts +46 -0
- package/dist/modules/Order/pickupTiming.js +53 -0
- package/dist/modules/Order/types.d.ts +30 -2
- package/dist/modules/Order/utils.js +25 -7
- package/dist/modules/Payment/index.js +9 -10
- package/dist/modules/Product/types.d.ts +11 -0
- package/dist/modules/ProductList/index.js +1 -1
- package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
- package/dist/modules/ResourcePlanner/planner.js +332 -23
- package/dist/modules/ResourcePlanner/types.d.ts +29 -0
- package/dist/modules/Schedule/index.d.ts +8 -0
- package/dist/modules/Schedule/index.js +141 -39
- package/dist/modules/index.d.ts +1 -0
- package/dist/modules/index.js +1 -0
- package/dist/plugins/request.d.ts +7 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1536 -1309
- package/dist/server/modules/form/index.d.ts +19 -0
- package/dist/server/modules/form/index.js +205 -0
- package/dist/server/modules/form/types.d.ts +13 -0
- package/dist/server/modules/form/types.js +3 -0
- package/dist/server/modules/index.d.ts +3 -0
- package/dist/server/modules/index.js +4 -0
- package/dist/server/modules/order/index.d.ts +15 -0
- package/dist/server/modules/order/index.js +920 -688
- package/dist/server/modules/order/types.d.ts +1 -0
- package/dist/server/test.json +1 -1
- package/dist/server/utils/small-ticket.d.ts +1 -85
- package/dist/server/utils/small-ticket.js +2 -2542
- package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
- package/dist/shared/payment/loadPaymentMethods.js +66 -0
- package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
- package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
- package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
- package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
- package/dist/shared/receipt/small-ticket.d.ts +96 -0
- package/dist/shared/receipt/small-ticket.js +2751 -0
- package/dist/shared/receipt/templateVisibility.d.ts +23 -0
- package/dist/shared/receipt/templateVisibility.js +64 -0
- package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
- package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
- package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
- package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
- package/dist/solution/BaseSales/index.d.ts +39 -16
- package/dist/solution/BaseSales/index.js +1754 -1154
- package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
- package/dist/solution/BaseSales/pickupTiming.js +616 -0
- package/dist/solution/BaseSales/types.d.ts +11 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +3 -0
- package/dist/solution/BookingByStep/index.d.ts +3 -1
- package/dist/solution/BookingByStep/index.js +8 -3
- package/dist/solution/BookingTicket/index.d.ts +8 -2
- package/dist/solution/BookingTicket/index.js +513 -436
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/dist/solution/BookingTicket/utils/cartView.js +3 -1
- package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
- package/dist/solution/OrderInvoicePreview/index.js +340 -0
- package/dist/solution/RegisterAndLogin/config.js +54 -11
- package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
- package/dist/solution/RegisterAndLogin/index.js +1 -1
- package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
- package/dist/solution/RegisterAndLogin/utils.js +36 -16
- package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
- package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
- package/dist/solution/UnifiedBookingSales/index.js +1714 -905
- package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
- package/dist/solution/VenueBooking/index.d.ts +15 -2
- package/dist/solution/VenueBooking/index.js +1062 -785
- package/dist/solution/VenueBooking/types.d.ts +2 -1
- package/dist/solution/VenueBooking/types.js +1 -0
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
- package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
- package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
- package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
- package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
- package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
- package/dist/solution/index.d.ts +1 -0
- package/dist/solution/index.js +2 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +21 -1
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
- package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
- package/lib/model/strategy/adapter/itemRule/type.js +10 -0
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
- package/lib/modules/BookingContext/utils/productExtend.js +45 -2
- package/lib/modules/BookingContext/utils/resources.js +1 -1
- package/lib/modules/BusinessAvailability/index.d.ts +30 -0
- package/lib/modules/BusinessAvailability/index.js +146 -0
- package/lib/modules/Cart/index.js +4 -2
- package/lib/modules/Cart/types.d.ts +2 -0
- package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
- package/lib/modules/Cart/utils/cartProduct.js +39 -20
- package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
- package/lib/modules/FulfillmentTiming/index.js +359 -0
- package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
- package/lib/modules/FulfillmentTiming/types.js +5 -0
- package/lib/modules/OpenData/types.d.ts +14 -0
- package/lib/modules/Order/index.d.ts +14 -2
- package/lib/modules/Order/index.js +240 -38
- package/lib/modules/Order/localEftposState.d.ts +13 -0
- package/lib/modules/Order/localEftposState.js +44 -0
- package/lib/modules/Order/pickupTiming.d.ts +46 -0
- package/lib/modules/Order/pickupTiming.js +61 -0
- package/lib/modules/Order/types.d.ts +30 -2
- package/lib/modules/Order/utils.js +21 -5
- package/lib/modules/Payment/index.js +3 -4
- package/lib/modules/Product/types.d.ts +11 -0
- package/lib/modules/ProductList/index.js +1 -1
- package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
- package/lib/modules/ResourcePlanner/planner.js +252 -8
- package/lib/modules/ResourcePlanner/types.d.ts +29 -0
- package/lib/modules/Schedule/index.d.ts +8 -0
- package/lib/modules/Schedule/index.js +68 -12
- package/lib/modules/index.d.ts +1 -0
- package/lib/modules/index.js +11 -0
- package/lib/plugins/request.d.ts +7 -0
- package/lib/server/index.d.ts +1 -0
- package/lib/server/index.js +158 -37
- package/lib/server/modules/form/index.d.ts +19 -0
- package/lib/server/modules/form/index.js +73 -0
- package/lib/server/modules/form/types.d.ts +13 -0
- package/lib/server/modules/form/types.js +9 -0
- package/lib/server/modules/index.d.ts +3 -0
- package/lib/server/modules/index.js +15 -1
- package/lib/server/modules/order/index.d.ts +15 -0
- package/lib/server/modules/order/index.js +114 -3
- package/lib/server/modules/order/types.d.ts +1 -0
- package/lib/server/test.json +1 -1
- package/lib/server/utils/small-ticket.d.ts +1 -85
- package/lib/server/utils/small-ticket.js +9 -2305
- package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
- package/lib/shared/payment/loadPaymentMethods.js +40 -0
- package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
- package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
- package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
- package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
- package/lib/shared/receipt/small-ticket.d.ts +96 -0
- package/lib/shared/receipt/small-ticket.js +2546 -0
- package/lib/shared/receipt/templateVisibility.d.ts +23 -0
- package/lib/shared/receipt/templateVisibility.js +63 -0
- package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
- package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
- package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
- package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
- package/lib/solution/BaseSales/index.d.ts +39 -16
- package/lib/solution/BaseSales/index.js +333 -31
- package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
- package/lib/solution/BaseSales/pickupTiming.js +290 -0
- package/lib/solution/BaseSales/types.d.ts +11 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +3 -0
- package/lib/solution/BookingByStep/index.d.ts +3 -1
- package/lib/solution/BookingByStep/index.js +7 -3
- package/lib/solution/BookingTicket/index.d.ts +8 -2
- package/lib/solution/BookingTicket/index.js +65 -6
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
- package/lib/solution/BookingTicket/utils/cartView.js +3 -1
- package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
- package/lib/solution/OrderInvoicePreview/index.js +246 -0
- package/lib/solution/RegisterAndLogin/config.js +57 -11
- package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
- package/lib/solution/RegisterAndLogin/index.js +9 -1
- package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
- package/lib/solution/RegisterAndLogin/utils.js +24 -17
- package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
- package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
- package/lib/solution/UnifiedBookingSales/index.js +561 -74
- package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
- package/lib/solution/VenueBooking/index.d.ts +15 -2
- package/lib/solution/VenueBooking/index.js +243 -96
- package/lib/solution/VenueBooking/types.d.ts +2 -1
- package/lib/solution/VenueBooking/types.js +1 -0
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
- package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
- package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
- package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
- package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
- package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
- package/lib/solution/index.d.ts +1 -0
- package/lib/solution/index.js +11 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StrategyConfig } from '../../type';
|
|
2
|
-
import { type ItemRuleBusinessData, type ItemRuleEvaluationResult, type QuantityCheckResult, type QuantityLimitResult, type PrefillItemResult, type AllergyRequirement } from './type';
|
|
2
|
+
import { type ItemRuleBusinessData, type ItemRuleEvaluationResult, type QuantityCheckResult, type QuantityLimitResult, type PrefillItemResult, type ItemRuleCartAction, type AllergyRequirement } from './type';
|
|
3
3
|
/**
|
|
4
4
|
* ItemRule 评估器
|
|
5
5
|
*
|
|
@@ -47,4 +47,6 @@ export declare class ItemRuleEvaluator {
|
|
|
47
47
|
* 便捷方法:仅获取需要预填到购物车的商品
|
|
48
48
|
*/
|
|
49
49
|
getPrefillItems(businessData: ItemRuleBusinessData): PrefillItemResult[];
|
|
50
|
+
/** 获取按优先级排序的购物车动作,交由销售业务层执行。 */
|
|
51
|
+
getCartActions(businessData: ItemRuleBusinessData): ItemRuleCartAction[];
|
|
50
52
|
}
|
|
@@ -43,6 +43,7 @@ class ItemRuleEvaluator {
|
|
|
43
43
|
const configs = businessData.strategyConfigs ? businessData.strategyConfigs.filter(c => c.metadata.type === 'item_rule') : this.strategyConfigs;
|
|
44
44
|
const allQuantityChecks = [];
|
|
45
45
|
const allPrefillItems = [];
|
|
46
|
+
const allCartActions = [];
|
|
46
47
|
const allAllergyRequirements = [];
|
|
47
48
|
const rawResults = [];
|
|
48
49
|
const context = this.adapter.prepareContext(businessData);
|
|
@@ -52,16 +53,19 @@ class ItemRuleEvaluator {
|
|
|
52
53
|
const {
|
|
53
54
|
quantityChecks,
|
|
54
55
|
prefillItems,
|
|
56
|
+
cartActions,
|
|
55
57
|
allergyRequirements
|
|
56
58
|
} = this.adapter.transformResult(evalResult, businessData);
|
|
57
59
|
allQuantityChecks.push(...quantityChecks);
|
|
58
60
|
allPrefillItems.push(...prefillItems);
|
|
61
|
+
allCartActions.push(...cartActions);
|
|
59
62
|
allAllergyRequirements.push(...allergyRequirements);
|
|
60
63
|
}
|
|
61
64
|
const failedChecks = allQuantityChecks.filter(c => !c.passed);
|
|
62
65
|
return {
|
|
63
66
|
quantityChecks: allQuantityChecks,
|
|
64
67
|
prefillItems: allPrefillItems,
|
|
68
|
+
cartActions: allCartActions.sort((left, right) => right.priority - left.priority),
|
|
65
69
|
allergyRequirements: allAllergyRequirements,
|
|
66
70
|
allPassed: failedChecks.length === 0,
|
|
67
71
|
failedChecks,
|
|
@@ -130,5 +134,10 @@ class ItemRuleEvaluator {
|
|
|
130
134
|
const result = this.evaluate(businessData);
|
|
131
135
|
return result.prefillItems;
|
|
132
136
|
}
|
|
137
|
+
|
|
138
|
+
/** 获取按优先级排序的购物车动作,交由销售业务层执行。 */
|
|
139
|
+
getCartActions(businessData) {
|
|
140
|
+
return this.evaluate(businessData).cartActions;
|
|
141
|
+
}
|
|
133
142
|
}
|
|
134
143
|
exports.ItemRuleEvaluator = ItemRuleEvaluator;
|
|
@@ -4,6 +4,8 @@ export declare const ITEM_RULE_ACTION_TYPES: {
|
|
|
4
4
|
readonly QUANTITY_CHECK: "QUANTITY_CHECK";
|
|
5
5
|
/** 预填购物车 */
|
|
6
6
|
readonly PREFILL_CART: "PREFILL_CART";
|
|
7
|
+
/** 按商品 ID 删除购物车商品 */
|
|
8
|
+
readonly DELETE_PRODUCT: "DELETE_PRODUCT";
|
|
7
9
|
/** 加购前过敏信息确认 */
|
|
8
10
|
readonly ALLERGY_CHECK: "ALLERGY_CHECK";
|
|
9
11
|
};
|
|
@@ -101,6 +103,10 @@ export interface AllergyRequirement {
|
|
|
101
103
|
promptScope: AllergyPromptScope;
|
|
102
104
|
allowNote: boolean;
|
|
103
105
|
}
|
|
106
|
+
/** 购物车动作触发时机,与数量校验的提交范围相互独立。 */
|
|
107
|
+
export type ItemRuleExecutionScope = 'set_handover';
|
|
108
|
+
/** 预填数量来源;主商品数量不扩展到 QUANTITY_CHECK。 */
|
|
109
|
+
export type PrefillQuantitySource = QuantitySource | 'main_product_number';
|
|
104
110
|
/**
|
|
105
111
|
* 预填商品项
|
|
106
112
|
*/
|
|
@@ -110,9 +116,11 @@ export interface PrefillProduct {
|
|
|
110
116
|
/** 变体 ID(可选,0 或不填表示无变体/默认) */
|
|
111
117
|
product_variant_id?: number;
|
|
112
118
|
/** 数量来源 */
|
|
113
|
-
quantityFrom:
|
|
119
|
+
quantityFrom: PrefillQuantitySource;
|
|
114
120
|
/** 固定数量(当 quantityFrom 为 'fixed' 时使用) */
|
|
115
121
|
quantity?: number;
|
|
122
|
+
/** 设置取餐方式时同步自动附加行的数量,重复执行不累加。 */
|
|
123
|
+
repeat_skip?: boolean;
|
|
116
124
|
}
|
|
117
125
|
/**
|
|
118
126
|
* Prefill Cart Action 的详细配置
|
|
@@ -120,9 +128,18 @@ export interface PrefillProduct {
|
|
|
120
128
|
* 存储在 ActionEffect.config 中
|
|
121
129
|
*/
|
|
122
130
|
export interface PrefillCartConfig {
|
|
131
|
+
/** 不填时保持原有预填时机;set_handover 仅在设置取餐方式时执行。 */
|
|
132
|
+
scope?: ItemRuleExecutionScope;
|
|
123
133
|
/** 要预填的商品列表 */
|
|
124
134
|
products: PrefillProduct[];
|
|
125
135
|
}
|
|
136
|
+
/** 删除指定商品的全部购物车行,不区分变体或是否为自动添加。 */
|
|
137
|
+
export interface DeleteProductConfig {
|
|
138
|
+
scope: ItemRuleExecutionScope;
|
|
139
|
+
products: Array<{
|
|
140
|
+
product_id: number;
|
|
141
|
+
}>;
|
|
142
|
+
}
|
|
126
143
|
/**
|
|
127
144
|
* 购物车商品摘要
|
|
128
145
|
*/
|
|
@@ -157,6 +174,10 @@ export interface ItemRuleBusinessData {
|
|
|
157
174
|
historicalItems?: CartItemSummary[];
|
|
158
175
|
/** 服务类型(如 'dine-in', 'takeaway') */
|
|
159
176
|
serviceType?: string;
|
|
177
|
+
/** 当前购物车动作触发时机;未填时不评估 set_handover 动作。 */
|
|
178
|
+
executionScope?: ItemRuleExecutionScope;
|
|
179
|
+
/** 由销售业务层提供的主商品总数量,不包含附加费用商品。 */
|
|
180
|
+
mainProductNumber?: number;
|
|
160
181
|
/** 当前业务渠道(如 'kiosk', 'pos', 'online_store') */
|
|
161
182
|
channel?: string;
|
|
162
183
|
/** 当前正在加入购物车的商品;ALLERGY_CHECK 只读取该商品的 Target。 */
|
|
@@ -209,7 +230,23 @@ export interface PrefillItemResult {
|
|
|
209
230
|
product_variant_id?: number;
|
|
210
231
|
/** 应添加的数量 */
|
|
211
232
|
quantity: number;
|
|
233
|
+
/** true 时执行器同步自动附加行数量;quantity=0 表示移除该自动行。 */
|
|
234
|
+
repeat_skip?: boolean;
|
|
212
235
|
}
|
|
236
|
+
/** 保留不同购物车动作之间的优先级与执行顺序。 */
|
|
237
|
+
export type ItemRuleCartAction = {
|
|
238
|
+
strategyId: string;
|
|
239
|
+
ruleId: string;
|
|
240
|
+
priority: number;
|
|
241
|
+
} & ({
|
|
242
|
+
type: 'PREFILL_CART';
|
|
243
|
+
products: PrefillItemResult[];
|
|
244
|
+
} | {
|
|
245
|
+
type: 'DELETE_PRODUCT';
|
|
246
|
+
products: Array<{
|
|
247
|
+
product_id: number;
|
|
248
|
+
}>;
|
|
249
|
+
});
|
|
213
250
|
/**
|
|
214
251
|
* 单条规则的数量限制(不含校验结果,仅描述配置中的约束)
|
|
215
252
|
*/
|
|
@@ -258,6 +295,8 @@ export interface ItemRuleEvaluationResult {
|
|
|
258
295
|
quantityChecks: QuantityCheckResult[];
|
|
259
296
|
/** 需要预填的商品列表 */
|
|
260
297
|
prefillItems: PrefillItemResult[];
|
|
298
|
+
/** 按 priority 降序排列的购物车动作;同优先级保持策略与动作顺序。 */
|
|
299
|
+
cartActions: ItemRuleCartAction[];
|
|
261
300
|
/** 当前商品命中的过敏门禁要求;不同 Action/商品不会合并。 */
|
|
262
301
|
allergyRequirements: AllergyRequirement[];
|
|
263
302
|
/** 所有校验是否全部通过 */
|
|
@@ -13,6 +13,8 @@ const ITEM_RULE_ACTION_TYPES = exports.ITEM_RULE_ACTION_TYPES = {
|
|
|
13
13
|
QUANTITY_CHECK: 'QUANTITY_CHECK',
|
|
14
14
|
/** 预填购物车 */
|
|
15
15
|
PREFILL_CART: 'PREFILL_CART',
|
|
16
|
+
/** 按商品 ID 删除购物车商品 */
|
|
17
|
+
DELETE_PRODUCT: 'DELETE_PRODUCT',
|
|
16
18
|
/** 加购前过敏信息确认 */
|
|
17
19
|
ALLERGY_CHECK: 'ALLERGY_CHECK'
|
|
18
20
|
};
|
|
@@ -78,6 +80,10 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
|
|
|
78
80
|
// Prefill Cart 相关类型
|
|
79
81
|
// ============================================
|
|
80
82
|
|
|
83
|
+
/** 购物车动作触发时机,与数量校验的提交范围相互独立。 */
|
|
84
|
+
|
|
85
|
+
/** 预填数量来源;主商品数量不扩展到 QUANTITY_CHECK。 */
|
|
86
|
+
|
|
81
87
|
/**
|
|
82
88
|
* 预填商品项
|
|
83
89
|
*/
|
|
@@ -88,6 +94,8 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
|
|
|
88
94
|
* 存储在 ActionEffect.config 中
|
|
89
95
|
*/
|
|
90
96
|
|
|
97
|
+
/** 删除指定商品的全部购物车行,不区分变体或是否为自动添加。 */
|
|
98
|
+
|
|
91
99
|
// ============================================
|
|
92
100
|
// 业务数据类型(Evaluator 输入)
|
|
93
101
|
// ============================================
|
|
@@ -116,6 +124,8 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
|
|
|
116
124
|
* 单个 Prefill Cart 的预填结果
|
|
117
125
|
*/
|
|
118
126
|
|
|
127
|
+
/** 保留不同购物车动作之间的优先级与执行顺序。 */
|
|
128
|
+
|
|
119
129
|
/**
|
|
120
130
|
* 单条规则的数量限制(不含校验结果,仅描述配置中的约束)
|
|
121
131
|
*/
|
|
@@ -1 +1,46 @@
|
|
|
1
|
-
"use strict";
|
|
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; }
|
|
@@ -7,6 +7,13 @@ import { TimeSlicesResult, TimeSlice, DurationSlice } from './timeSlices';
|
|
|
7
7
|
* 让 OS 这层完全可在 Node 单测下运行(dayjs 在 Node 也是纯函数)。
|
|
8
8
|
*/
|
|
9
9
|
export interface BookingCalcContext {
|
|
10
|
+
/** Sales channel; remembered duration starts are accepted only by POS. */
|
|
11
|
+
channel?: string;
|
|
12
|
+
/** Start-only device preference for this decision; never reuse a cached end/resource. */
|
|
13
|
+
rememberedTime?: {
|
|
14
|
+
businessDate: string;
|
|
15
|
+
startAt: string;
|
|
16
|
+
};
|
|
10
17
|
/** 来自 `/core/board/management/config` 的整套配置;常用路径见 sliceTimeSlices / appointmentTimingPreference。 */
|
|
11
18
|
bookingConfig?: any;
|
|
12
19
|
/** 资源 origin map(id → resource origin)。 */
|
|
@@ -28,6 +28,44 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
28
28
|
* 让 OS 这层完全可在 Node 单测下运行(dayjs 在 Node 也是纯函数)。
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
/** Rebuild only the derived booking fields; SKU, quantity, notes and Holder stay intact. */
|
|
32
|
+
function seedRememberedBookingStart(cacheItem, ctx) {
|
|
33
|
+
const remembered = ctx.rememberedTime;
|
|
34
|
+
const invalid = () => Object.assign(new Error('Remembered time requires a valid POS duration start.'), {
|
|
35
|
+
code: 'INVALID_REMEMBERED_TIME'
|
|
36
|
+
});
|
|
37
|
+
const duration = cacheItem?.duration;
|
|
38
|
+
const durationType = typeof duration === 'object' && duration ? String(duration.type || '').toLowerCase() : '';
|
|
39
|
+
const durationValue = typeof duration === 'object' && duration ? duration.value : duration;
|
|
40
|
+
const isDuration = (0, _flexible.isProductFlexibleDuration)(duration) || ['', 'fixed', 'minute', 'minutes', 'hour', 'hours'].includes(durationType) && Number.isFinite(Number(durationValue)) && Number(durationValue) > 0;
|
|
41
|
+
const isCalendarDate = value => {
|
|
42
|
+
if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return false;
|
|
43
|
+
const date = new Date(`${value}T00:00:00.000Z`);
|
|
44
|
+
return Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value;
|
|
45
|
+
};
|
|
46
|
+
const parts = typeof remembered?.startAt === 'string' ? /^(\d{4}-\d{2}-\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,3})?)?(?:Z|[+-](\d{2}):(\d{2}))?$/.exec(remembered.startAt) : null;
|
|
47
|
+
if (String(ctx.channel || '').trim().toLowerCase() !== 'pos' || !isDuration || (0, _serviceTimes.isMultiDayProduct)(cacheItem) || (0, _serviceTimes.isSessionProduct)(cacheItem) || cacheItem?.cartDetailValue?.session || cacheItem?._extend?.other?.session || !isCalendarDate(remembered?.businessDate) || !parts || !isCalendarDate(parts[1]) || Number(parts[2]) > 23 || Number(parts[3]) > 59 || Number(parts[4] || 0) > 59 || Number(parts[5] || 0) > 23 || Number(parts[6] || 0) > 59) throw invalid();
|
|
48
|
+
// Parse the actual instant with the same runtime clock used by the legacy booking helpers.
|
|
49
|
+
// The business-day label must not replace the calendar date of an overnight start.
|
|
50
|
+
const start = (0, _dayjs.default)(remembered.startAt);
|
|
51
|
+
if (!start.isValid()) throw invalid();
|
|
52
|
+
const extend = {
|
|
53
|
+
...(cacheItem?._extend || {})
|
|
54
|
+
};
|
|
55
|
+
for (const key of ['start_date', 'startDate', 'start_time', 'end_date', 'endDate', 'end_time', 'duration', 'resource', 'resources', 'capacity', 'booking', 'availabilitySelection']) delete extend[key];
|
|
56
|
+
return {
|
|
57
|
+
...cacheItem,
|
|
58
|
+
new: 1,
|
|
59
|
+
autoClose: false,
|
|
60
|
+
_data: {},
|
|
61
|
+
_extend: {
|
|
62
|
+
...extend,
|
|
63
|
+
start_date: start.format('YYYY-MM-DD'),
|
|
64
|
+
start_time: start.format(start.millisecond() ? 'HH:mm:ss.SSS' : start.second() ? 'HH:mm:ss' : 'HH:mm')
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
31
69
|
/** 从 BookingContext.date 提取 HH:mm(仅当日期带有效时分时)。 */
|
|
32
70
|
function derivePresetStartTimeFromDate(date) {
|
|
33
71
|
if (date == null) return undefined;
|
|
@@ -195,10 +233,15 @@ function getServiceStartTimeAndEndTime(params) {
|
|
|
195
233
|
*/
|
|
196
234
|
function getProductExtend(params) {
|
|
197
235
|
const {
|
|
198
|
-
cacheItem,
|
|
199
|
-
ctx,
|
|
200
236
|
isDisabledTime
|
|
201
237
|
} = params;
|
|
238
|
+
const hasRememberedTime = params.ctx.rememberedTime !== undefined;
|
|
239
|
+
const cacheItem = hasRememberedTime ? seedRememberedBookingStart(params.cacheItem, params.ctx) : params.cacheItem;
|
|
240
|
+
const ctx = hasRememberedTime ? {
|
|
241
|
+
...params.ctx,
|
|
242
|
+
previousService: undefined,
|
|
243
|
+
presetStartTime: undefined
|
|
244
|
+
} : params.ctx;
|
|
202
245
|
const isNew = cacheItem.new || !cacheItem._extend?.endDate;
|
|
203
246
|
const _cacheItem = {
|
|
204
247
|
...cacheItem
|
|
@@ -241,7 +241,7 @@ function getResourceMaxFreeTime(resource, isAutoAllocationOn) {
|
|
|
241
241
|
if (!isAutoAllocationOn(form_id)) return [];
|
|
242
242
|
const usableList = (renderList || []).filter(d => d.usable && d.id !== 0);
|
|
243
243
|
let defaultResource = [];
|
|
244
|
-
let maxFreeTime =
|
|
244
|
+
let maxFreeTime = -1;
|
|
245
245
|
usableList.forEach(d => {
|
|
246
246
|
const {
|
|
247
247
|
times = []
|
|
@@ -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
|
+
}
|
|
@@ -89,7 +89,8 @@ class CartModule extends _BaseModule.BaseModule {
|
|
|
89
89
|
bundle,
|
|
90
90
|
options,
|
|
91
91
|
date,
|
|
92
|
-
quantity = 1
|
|
92
|
+
quantity = 1,
|
|
93
|
+
isLegacyOrder
|
|
93
94
|
} = params;
|
|
94
95
|
// 生成一个唯一的 ID
|
|
95
96
|
let cartItem = {
|
|
@@ -108,7 +109,8 @@ class CartModule extends _BaseModule.BaseModule {
|
|
|
108
109
|
bundle,
|
|
109
110
|
options,
|
|
110
111
|
product_variant_id: newProduct.product_variant_id,
|
|
111
|
-
quantity
|
|
112
|
+
quantity,
|
|
113
|
+
isLegacyOrder
|
|
112
114
|
});
|
|
113
115
|
}
|
|
114
116
|
if (account) {
|
|
@@ -21,6 +21,7 @@ export declare const formatProductToCartItem: (params: {
|
|
|
21
21
|
product_variant_id?: number;
|
|
22
22
|
quantity?: number;
|
|
23
23
|
discounts?: any[];
|
|
24
|
+
isLegacyOrder?: boolean;
|
|
24
25
|
}) => CartItem;
|
|
25
26
|
export declare const formatProductToCartItemOrigin: (params: {
|
|
26
27
|
cartItem: CartItem;
|
|
@@ -29,6 +30,7 @@ export declare const formatProductToCartItemOrigin: (params: {
|
|
|
29
30
|
options?: any;
|
|
30
31
|
product_variant_id?: number;
|
|
31
32
|
quantity?: number;
|
|
33
|
+
isLegacyOrder?: boolean;
|
|
32
34
|
}) => any;
|
|
33
35
|
/**
|
|
34
36
|
* 获取商品总价
|
|
@@ -61,7 +63,7 @@ export declare const getProductOriginTotalPrice: (params: {
|
|
|
61
63
|
* @param options 套餐规格信息
|
|
62
64
|
* @returns 格式化后的套餐规格信息
|
|
63
65
|
*/
|
|
64
|
-
export declare const formatOptions: (options: any) => any;
|
|
66
|
+
export declare const formatOptions: (options: any, product?: ProductData) => any;
|
|
65
67
|
export declare const formatOptionsToOrigin: (options: any) => any;
|
|
66
68
|
/**
|
|
67
69
|
* 格式化商品套餐信息
|
|
@@ -106,7 +106,7 @@ const formatProductToCartItem = params => {
|
|
|
106
106
|
cartItem.bundle = formatBundle(bundle);
|
|
107
107
|
}
|
|
108
108
|
if (options?.length) {
|
|
109
|
-
cartItem.options = formatOptions(options);
|
|
109
|
+
cartItem.options = formatOptions(options, product);
|
|
110
110
|
}
|
|
111
111
|
// 拼装出 product_option_string
|
|
112
112
|
if (product_variant_id) {
|
|
@@ -148,22 +148,32 @@ const formatProductToCartItemOrigin = params => {
|
|
|
148
148
|
bundle,
|
|
149
149
|
options,
|
|
150
150
|
product_variant_id,
|
|
151
|
-
quantity = 1
|
|
151
|
+
quantity = 1,
|
|
152
|
+
isLegacyOrder = false
|
|
152
153
|
} = params;
|
|
153
154
|
let origin = cartItem._origin;
|
|
154
155
|
const product_discount_difference = (origin.product?.discount_list || []).filter(item => !item?.metadata?.custom_product_bundle_map_id).reduce((pre, cur) => {
|
|
155
156
|
return pre + (cur?.metadata?.product_discount_difference || 0);
|
|
156
157
|
}, 0);
|
|
157
158
|
if (product) {
|
|
159
|
+
const {
|
|
160
|
+
option: _option,
|
|
161
|
+
...legacyProductSku
|
|
162
|
+
} = origin.product?.product_sku || {};
|
|
158
163
|
origin.product = {
|
|
159
164
|
...(origin.product || {}),
|
|
160
165
|
num: quantity,
|
|
161
166
|
product_id: product.id,
|
|
162
167
|
product_variant_id: product_variant_id || 0,
|
|
163
168
|
product_bundle: origin.product?.product_bundle || [],
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
...(isLegacyOrder ? {
|
|
170
|
+
product_sku: legacyProductSku,
|
|
171
|
+
product_option_item: origin.product?.product_option_item || []
|
|
172
|
+
} : {
|
|
173
|
+
product_sku: origin.product?.product_sku || {
|
|
174
|
+
option: []
|
|
175
|
+
}
|
|
176
|
+
}),
|
|
167
177
|
metadata: {
|
|
168
178
|
product_discount_difference
|
|
169
179
|
}
|
|
@@ -176,17 +186,22 @@ const formatProductToCartItemOrigin = params => {
|
|
|
176
186
|
origin.product.product_bundle = formatBundleToOrigin(bundle);
|
|
177
187
|
}
|
|
178
188
|
if (options?.length) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
189
|
+
const formattedOptions = formatOptionsToOrigin(options);
|
|
190
|
+
if (isLegacyOrder) {
|
|
191
|
+
origin.product.product_option_item = formattedOptions;
|
|
192
|
+
} else {
|
|
193
|
+
origin.product.product_sku = {
|
|
194
|
+
...(origin.product.product_sku || {}),
|
|
195
|
+
option: formattedOptions.map(option => {
|
|
196
|
+
const next = {
|
|
197
|
+
...option,
|
|
198
|
+
add_price: option.add_price ?? option.price
|
|
199
|
+
};
|
|
200
|
+
delete next.price;
|
|
201
|
+
return next;
|
|
202
|
+
})
|
|
203
|
+
};
|
|
204
|
+
}
|
|
190
205
|
}
|
|
191
206
|
}
|
|
192
207
|
return origin;
|
|
@@ -299,12 +314,16 @@ const getProductOriginTotalPrice = params => {
|
|
|
299
314
|
* @returns 格式化后的套餐规格信息
|
|
300
315
|
*/
|
|
301
316
|
exports.getProductOriginTotalPrice = getProductOriginTotalPrice;
|
|
302
|
-
const formatOptions = options => {
|
|
317
|
+
const formatOptions = (options, product) => {
|
|
303
318
|
if (!options?.length) return [];
|
|
304
319
|
return options.map(item => {
|
|
320
|
+
const optionGroupId = item?.option_group_id;
|
|
321
|
+
const optionItemId = item?.id ?? item?.option_group_item_id ?? item?.product_option_item_id;
|
|
322
|
+
const optionGroup = product?.option_group?.find(group => String(group?.id) === String(optionGroupId));
|
|
323
|
+
const optionItem = optionGroup?.option_item?.find(candidate => String(candidate?.id) === String(optionItemId));
|
|
305
324
|
return {
|
|
306
|
-
id:
|
|
307
|
-
name: item?.name,
|
|
325
|
+
id: optionItemId,
|
|
326
|
+
name: item?.name ?? item?.title ?? optionItem?.name ?? optionItem?.title,
|
|
308
327
|
num: item?.num,
|
|
309
328
|
price: item?.price,
|
|
310
329
|
total: item?.price,
|
|
@@ -320,7 +339,7 @@ const formatOptionsToOrigin = options => {
|
|
|
320
339
|
return options.map(d => {
|
|
321
340
|
return {
|
|
322
341
|
num: d.num,
|
|
323
|
-
option_group_item_id: d
|
|
342
|
+
option_group_item_id: d?.option_group_item_id || d?.product_option_item_id,
|
|
324
343
|
option_group_id: d.option_group_id
|
|
325
344
|
};
|
|
326
345
|
});
|