@pisell/pisellos 0.10.7 → 0.10.9
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/core/index.js +0 -1
- package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
- package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/dist/model/strategy/adapter/walletPass/type.d.ts +5 -0
- package/dist/model/strategy/adapter/walletPass/utils.js +57 -26
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +18 -12
- package/dist/modules/BookingContext/utils/productExtend.js +5 -9
- package/dist/modules/BookingContext/utils/timeSlices.js +24 -3
- package/dist/modules/Customer/index.d.ts +4 -0
- package/dist/modules/Customer/index.js +91 -59
- package/dist/modules/Customer/types.d.ts +2 -0
- package/dist/modules/Discount/index.d.ts +2 -0
- package/dist/modules/Discount/index.js +38 -5
- package/dist/modules/Discount/types.d.ts +11 -0
- package/dist/modules/Order/index.d.ts +32 -6
- package/dist/modules/Order/index.js +1165 -819
- package/dist/modules/Order/types.d.ts +32 -4
- package/dist/modules/Order/types.js +11 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.js +227 -0
- package/dist/modules/Order/utils/virtualSettlement.d.ts +56 -0
- package/dist/modules/Order/utils/virtualSettlement.js +271 -0
- package/dist/modules/Order/utils.js +89 -48
- package/dist/modules/Payment/types.d.ts +2 -0
- package/dist/modules/Payment/utils.js +4 -1
- package/dist/modules/Payment/walletpass.d.ts +11 -0
- package/dist/modules/Payment/walletpass.js +235 -60
- package/dist/modules/Product/types.d.ts +23 -0
- package/dist/modules/ProductList/index.d.ts +15 -2
- package/dist/modules/ProductList/index.js +92 -13
- package/dist/modules/Rules/index.js +125 -52
- package/dist/modules/SalesSummary/index.d.ts +1 -0
- package/dist/modules/SalesSummary/index.js +4 -3
- package/dist/modules/SalesSummary/types.d.ts +1 -0
- package/dist/modules/SalesSummary/utils.d.ts +1 -0
- package/dist/modules/SalesSummary/utils.js +28 -2
- package/dist/server/index.d.ts +15 -0
- package/dist/server/index.js +894 -781
- package/dist/server/modules/order/index.d.ts +2 -0
- package/dist/server/modules/order/index.js +261 -96
- package/dist/server/modules/order/types.d.ts +1 -1
- package/dist/server/utils/small-ticket.js +2 -1
- package/dist/solution/BaseSales/index.d.ts +41 -7
- package/dist/solution/BaseSales/index.js +1405 -974
- package/dist/solution/BaseSales/utils/cartPromotion.js +26 -3
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +79 -13
- package/dist/solution/BaseSales/utils.js +31 -20
- package/dist/solution/BookingByStep/index.d.ts +3 -3
- package/dist/solution/BookingTicket/index.d.ts +5 -1
- package/dist/solution/BookingTicket/index.js +221 -162
- package/dist/solution/BookingTicket/types.d.ts +3 -0
- package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
- package/dist/solution/BookingTicket/utils/cartView.js +44 -32
- package/dist/solution/Sales/index.d.ts +1 -0
- package/dist/solution/Sales/index.js +16 -2
- package/dist/solution/ScanOrder/index.js +25 -64
- package/dist/solution/ScanOrder/utils.js +31 -20
- package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
- package/dist/solution/UnifiedBookingSales/index.js +51 -39
- package/lib/core/index.js +0 -1
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +170 -7
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.js +0 -2
- package/lib/model/strategy/adapter/walletPass/type.d.ts +5 -0
- package/lib/model/strategy/adapter/walletPass/utils.js +62 -11
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +6 -1
- package/lib/modules/BookingContext/utils/productExtend.js +4 -3
- package/lib/modules/BookingContext/utils/timeSlices.js +18 -3
- package/lib/modules/Customer/index.d.ts +4 -0
- package/lib/modules/Customer/index.js +11 -0
- package/lib/modules/Customer/types.d.ts +2 -0
- package/lib/modules/Discount/index.d.ts +2 -0
- package/lib/modules/Discount/index.js +37 -3
- package/lib/modules/Discount/types.d.ts +11 -0
- package/lib/modules/Order/index.d.ts +32 -6
- package/lib/modules/Order/index.js +518 -148
- package/lib/modules/Order/types.d.ts +32 -4
- package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +45 -0
- package/lib/modules/Order/utils/discountProductLineIdentity.js +170 -0
- package/lib/modules/Order/utils/virtualSettlement.d.ts +56 -0
- package/lib/modules/Order/utils/virtualSettlement.js +300 -0
- package/lib/modules/Order/utils.js +65 -21
- package/lib/modules/Payment/types.d.ts +2 -0
- package/lib/modules/Payment/utils.js +5 -1
- package/lib/modules/Payment/walletpass.d.ts +11 -0
- package/lib/modules/Payment/walletpass.js +198 -17
- package/lib/modules/Product/types.d.ts +23 -0
- package/lib/modules/ProductList/index.d.ts +15 -2
- package/lib/modules/ProductList/index.js +85 -3
- package/lib/modules/Rules/index.js +100 -20
- package/lib/modules/SalesSummary/index.d.ts +1 -0
- package/lib/modules/SalesSummary/index.js +10 -2
- package/lib/modules/SalesSummary/types.d.ts +1 -0
- package/lib/modules/SalesSummary/utils.d.ts +1 -0
- package/lib/modules/SalesSummary/utils.js +30 -2
- package/lib/server/index.d.ts +15 -0
- package/lib/server/index.js +105 -14
- package/lib/server/modules/order/index.d.ts +2 -0
- package/lib/server/modules/order/index.js +75 -5
- package/lib/server/modules/order/types.d.ts +1 -1
- package/lib/server/utils/small-ticket.js +1 -1
- package/lib/solution/BaseSales/index.d.ts +41 -7
- package/lib/solution/BaseSales/index.js +325 -39
- package/lib/solution/BaseSales/utils/cartPromotion.js +26 -2
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +62 -12
- package/lib/solution/BaseSales/utils.js +29 -18
- package/lib/solution/BookingByStep/index.d.ts +3 -3
- package/lib/solution/BookingTicket/index.d.ts +5 -1
- package/lib/solution/BookingTicket/index.js +31 -6
- package/lib/solution/BookingTicket/types.d.ts +3 -0
- package/lib/solution/BookingTicket/utils/addProductDecision.js +2 -1
- package/lib/solution/BookingTicket/utils/cartView.js +43 -30
- package/lib/solution/Sales/index.d.ts +1 -0
- package/lib/solution/Sales/index.js +15 -3
- package/lib/solution/ScanOrder/index.js +17 -54
- package/lib/solution/ScanOrder/utils.js +29 -18
- package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
- package/lib/solution/UnifiedBookingSales/index.js +35 -26
- package/package.json +1 -1
|
@@ -18,6 +18,19 @@ export declare class ProductList extends BaseModule implements Module {
|
|
|
18
18
|
* productList.updateOtherParams({ channel: 'pos' });
|
|
19
19
|
*/
|
|
20
20
|
updateOtherParams(params: Record<string, any>): void;
|
|
21
|
+
/**
|
|
22
|
+
* 判断当前商品查询是否会被本地 OS Server 接管。
|
|
23
|
+
*
|
|
24
|
+
* 不能只看请求参数中的 osServer=true:H5 RequestPlugin 会透传该参数,但仍然直接请求远端接口。
|
|
25
|
+
* 这里按 RequestPlugin 实际使用的 baseUrl 检查已注册路由,避免 OS Server 与客户端重复执行
|
|
26
|
+
* Data Variant 评估。
|
|
27
|
+
*/
|
|
28
|
+
private isProductQueryHandledByOsServer;
|
|
29
|
+
/**
|
|
30
|
+
* 未启用商品 OS 路由时,在客户端补做 Data Variant 解析。
|
|
31
|
+
* OS Server 已接管时直接信任服务端结果,确保同一批商品只评估一次。
|
|
32
|
+
*/
|
|
33
|
+
private resolveClientDataVariants;
|
|
21
34
|
storeChange(path?: string, value?: any): Promise<void>;
|
|
22
35
|
/**
|
|
23
36
|
* 获取加时商品列表。
|
|
@@ -25,11 +38,11 @@ export declare class ProductList extends BaseModule implements Module {
|
|
|
25
38
|
* @example
|
|
26
39
|
* const products = await productList.getAddTimeProducts({ schedule_date: '2026-06-16' });
|
|
27
40
|
*/
|
|
28
|
-
getAddTimeProducts(params?: ProductListLoadProductsParams): Promise<
|
|
41
|
+
getAddTimeProducts(params?: ProductListLoadProductsParams): Promise<ProductData[]>;
|
|
29
42
|
loadProducts({ category_ids, product_ids, collection, menu_list_ids, customer_id: paramsCustomerId, with_count, schedule_datetime, schedule_date, cacheId, with_schedule, extension_type, status, strategy_context, }?: ProductListLoadProductsParams, options?: {
|
|
30
43
|
callback?: (result: any) => void;
|
|
31
44
|
subscriberId?: string;
|
|
32
|
-
}): Promise<
|
|
45
|
+
}): Promise<ProductData[]>;
|
|
33
46
|
loadProductsPrice({ ids, customer_id, schedule_date, channel, }: {
|
|
34
47
|
ids?: number[];
|
|
35
48
|
customer_id?: number;
|
|
@@ -67,6 +67,62 @@ var ProductList = class extends import_BaseModule.BaseModule {
|
|
|
67
67
|
updateOtherParams(params) {
|
|
68
68
|
this.otherParams = params || {};
|
|
69
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* 判断当前商品查询是否会被本地 OS Server 接管。
|
|
72
|
+
*
|
|
73
|
+
* 不能只看请求参数中的 osServer=true:H5 RequestPlugin 会透传该参数,但仍然直接请求远端接口。
|
|
74
|
+
* 这里按 RequestPlugin 实际使用的 baseUrl 检查已注册路由,避免 OS Server 与客户端重复执行
|
|
75
|
+
* Data Variant 评估。
|
|
76
|
+
*/
|
|
77
|
+
isProductQueryHandledByOsServer() {
|
|
78
|
+
var _a, _b;
|
|
79
|
+
const server = (_a = this.core) == null ? void 0 : _a.server;
|
|
80
|
+
if (!server || typeof server.hasRoute !== "function")
|
|
81
|
+
return false;
|
|
82
|
+
const requestBaseUrl = String(
|
|
83
|
+
((_b = this.request) == null ? void 0 : _b.baseUrl) || "/shop"
|
|
84
|
+
).replace(/\/+$/, "");
|
|
85
|
+
const routePath = `${requestBaseUrl}/product/query`;
|
|
86
|
+
return server.hasRoute("post", routePath) === true;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 未启用商品 OS 路由时,在客户端补做 Data Variant 解析。
|
|
90
|
+
* OS Server 已接管时直接信任服务端结果,确保同一批商品只评估一次。
|
|
91
|
+
*/
|
|
92
|
+
resolveClientDataVariants(products, queryPayload, handledByOsServer) {
|
|
93
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
94
|
+
if (handledByOsServer || products.length === 0)
|
|
95
|
+
return products;
|
|
96
|
+
const evaluator = (_b = (_a = this.core) == null ? void 0 : _a.context) == null ? void 0 : _b.dataVariantEvaluator;
|
|
97
|
+
if (!evaluator || typeof evaluator.resolveProducts !== "function") {
|
|
98
|
+
return products;
|
|
99
|
+
}
|
|
100
|
+
const strategyContext = queryPayload.strategy_context && typeof queryPayload.strategy_context === "object" ? queryPayload.strategy_context : {};
|
|
101
|
+
const fatherModule = String(((_c = this.otherParams) == null ? void 0 : _c.fatherModule) || "").trim();
|
|
102
|
+
const scheduleModule = (fatherModule ? this.core.getModule(`${fatherModule}_schedule`) : null) || this.core.getModule("schedule");
|
|
103
|
+
const scheduleList = (_d = scheduleModule == null ? void 0 : scheduleModule.getScheduleList) == null ? void 0 : _d.call(scheduleModule);
|
|
104
|
+
const contextScheduleList = (_f = (_e = this.core) == null ? void 0 : _e.context) == null ? void 0 : _f.scheduleList;
|
|
105
|
+
const contextMenuList = (_h = (_g = this.core) == null ? void 0 : _g.context) == null ? void 0 : _h.menuList;
|
|
106
|
+
const businessData = {
|
|
107
|
+
products,
|
|
108
|
+
scheduleDateTime: queryPayload.schedule_datetime || queryPayload.schedule_date,
|
|
109
|
+
scheduleList: Array.isArray(scheduleList) ? scheduleList : Array.isArray(contextScheduleList) ? contextScheduleList : [],
|
|
110
|
+
menuList: Array.isArray((_i = this.otherParams) == null ? void 0 : _i.menuList) ? this.otherParams.menuList : Array.isArray(contextMenuList) ? contextMenuList : [],
|
|
111
|
+
customerId: queryPayload.customer_id,
|
|
112
|
+
channel: strategyContext.channel,
|
|
113
|
+
orderType: strategyContext.orderType || strategyContext.order_type,
|
|
114
|
+
businessCode: strategyContext.business_code ?? strategyContext.businessCode,
|
|
115
|
+
availableWalletIds: strategyContext.available_wallet_ids,
|
|
116
|
+
custom: strategyContext
|
|
117
|
+
};
|
|
118
|
+
try {
|
|
119
|
+
const result = evaluator.resolveProducts(businessData);
|
|
120
|
+
return Array.isArray(result == null ? void 0 : result.products) ? result.products : products;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error("[ProductList] Data Variant 客户端解析失败", error);
|
|
123
|
+
return products;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
70
126
|
async storeChange(path, value) {
|
|
71
127
|
}
|
|
72
128
|
/**
|
|
@@ -151,15 +207,41 @@ var ProductList = class extends import_BaseModule.BaseModule {
|
|
|
151
207
|
is_eject: 1,
|
|
152
208
|
with_schedule,
|
|
153
209
|
schedule_datetime,
|
|
154
|
-
extension_type
|
|
210
|
+
extension_type,
|
|
211
|
+
strategy_context
|
|
155
212
|
};
|
|
213
|
+
const handledByOsServer = this.isProductQueryHandledByOsServer();
|
|
214
|
+
const callback = !handledByOsServer && typeof (options == null ? void 0 : options.callback) === "function" ? (result) => {
|
|
215
|
+
var _a2, _b2, _c;
|
|
216
|
+
const callbackList = (_a2 = result == null ? void 0 : result.data) == null ? void 0 : _a2.list;
|
|
217
|
+
if (!Array.isArray(callbackList)) {
|
|
218
|
+
(_b2 = options.callback) == null ? void 0 : _b2.call(options, result);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
(_c = options.callback) == null ? void 0 : _c.call(options, {
|
|
222
|
+
...result,
|
|
223
|
+
data: {
|
|
224
|
+
...result.data,
|
|
225
|
+
list: this.resolveClientDataVariants(
|
|
226
|
+
callbackList,
|
|
227
|
+
queryPayload,
|
|
228
|
+
false
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
} : options == null ? void 0 : options.callback;
|
|
156
233
|
const productsData = await this.request.post(
|
|
157
234
|
`/product/query`,
|
|
158
235
|
queryPayload,
|
|
159
|
-
{ osServer: true, callback
|
|
236
|
+
{ osServer: true, callback, subscriberId: options == null ? void 0 : options.subscriberId, customToast: () => {
|
|
160
237
|
} }
|
|
161
238
|
);
|
|
162
|
-
const
|
|
239
|
+
const resolvedList = this.resolveClientDataVariants(
|
|
240
|
+
productsData.data.list || [],
|
|
241
|
+
queryPayload,
|
|
242
|
+
handledByOsServer
|
|
243
|
+
);
|
|
244
|
+
const sortedList = resolvedList.slice().sort((a, b) => Number(b.sort) - Number(a.sort));
|
|
163
245
|
this.addProduct(sortedList);
|
|
164
246
|
return sortedList;
|
|
165
247
|
}
|
|
@@ -243,7 +243,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
243
243
|
const discountType = selectedDiscount.tag || selectedDiscount.type;
|
|
244
244
|
return selectedDiscount.isEditMode === true && selectedDiscount.isSelected === true && ["good_pass", "discount_card", "product_discount_card"].includes(discountType);
|
|
245
245
|
};
|
|
246
|
-
const
|
|
246
|
+
const resolveReapplyBookingDiscountPercent = (originProduct, selectedDiscount) => {
|
|
247
247
|
var _a2;
|
|
248
248
|
if (!shouldReapplyBookingDiscount(originProduct, selectedDiscount))
|
|
249
249
|
return void 0;
|
|
@@ -318,6 +318,9 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
318
318
|
bundleIndex,
|
|
319
319
|
// 虚拟商品属性
|
|
320
320
|
price: Number(bundleItem.price || 0),
|
|
321
|
+
// 新增商品运行态通常带 _bundle_product_id;订单 hydrate 后只有
|
|
322
|
+
// bundle_product_id。Change time 必须兼容两种结构,否则 bundle
|
|
323
|
+
// 子项无法命中折扣卡的 limited_relation_product_data.product_ids。
|
|
321
324
|
id: bundleItem.bundle_product_id ?? bundleItem._bundle_product_id ?? bundleItem.product_id,
|
|
322
325
|
_id: `${product._id}_bundle_${bundleIndex}`,
|
|
323
326
|
parentId: product._id,
|
|
@@ -779,13 +782,6 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
779
782
|
if (isPersistedProduct && hasExistingWalletDiscount) {
|
|
780
783
|
if (flatItem.type === "main") {
|
|
781
784
|
processedProductsMap.set(product._id, [originProduct]);
|
|
782
|
-
} else {
|
|
783
|
-
processedFlatItemsMap.set(flatItem._id, [
|
|
784
|
-
{
|
|
785
|
-
...flatItem,
|
|
786
|
-
processed: true
|
|
787
|
-
}
|
|
788
|
-
]);
|
|
789
785
|
}
|
|
790
786
|
return;
|
|
791
787
|
}
|
|
@@ -862,15 +858,46 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
862
858
|
}
|
|
863
859
|
return false;
|
|
864
860
|
});
|
|
865
|
-
const
|
|
861
|
+
const explicitlySelectedDiscount = (options == null ? void 0 : options.isSelected) === true && options.discountId !== void 0 ? applicableDiscounts.find((discount) => {
|
|
866
862
|
const discountType = discount.tag || discount.type;
|
|
867
|
-
return String(discount.id) === String(options.discountId) && ["discount_card", "product_discount_card"].includes(
|
|
863
|
+
return String(discount.id) === String(options.discountId) && ["good_pass", "discount_card", "product_discount_card"].includes(
|
|
864
|
+
discountType
|
|
865
|
+
);
|
|
868
866
|
}) : void 0;
|
|
867
|
+
const explicitlySelectedDiscountCard = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) !== "good_pass" ? explicitlySelectedDiscount : void 0;
|
|
868
|
+
const appliedDiscountCardIds = new Set(
|
|
869
|
+
(product.discount_list || []).filter(
|
|
870
|
+
(item) => ["discount_card", "product_discount_card"].includes(
|
|
871
|
+
(item == null ? void 0 : item.tag) || (item == null ? void 0 : item.type)
|
|
872
|
+
)
|
|
873
|
+
).map(
|
|
874
|
+
(item) => {
|
|
875
|
+
var _a3;
|
|
876
|
+
return ((_a3 = item == null ? void 0 : item.discount) == null ? void 0 : _a3.resource_id) ?? (item == null ? void 0 : item.resource_id) ?? (item == null ? void 0 : item.id);
|
|
877
|
+
}
|
|
878
|
+
).filter((id) => id !== void 0 && id !== null).map(String)
|
|
879
|
+
);
|
|
880
|
+
const appliedDiscountCard = (options == null ? void 0 : options.scan) ? void 0 : applicableDiscounts.find((discount) => {
|
|
881
|
+
const discountType = discount.tag || discount.type;
|
|
882
|
+
return discount.isSelected === true && ["discount_card", "product_discount_card"].includes(discountType) && appliedDiscountCardIds.has(String(discount.id));
|
|
883
|
+
});
|
|
869
884
|
const scannedSelectedDiscountCard = applicableDiscounts.find(
|
|
870
885
|
(n) => n.isScan && n.isSelected && (n.tag || n.type) !== "good_pass"
|
|
871
886
|
);
|
|
872
|
-
const selectedDiscountCard = explicitlySelectedDiscountCard || scannedSelectedDiscountCard;
|
|
873
|
-
const selectedDiscount = selectedDiscountCard || applicableDiscounts[0];
|
|
887
|
+
const selectedDiscountCard = explicitlySelectedDiscountCard || appliedDiscountCard || scannedSelectedDiscountCard;
|
|
888
|
+
const selectedDiscount = explicitlySelectedDiscount || selectedDiscountCard || applicableDiscounts[0];
|
|
889
|
+
const prioritizedApplicableDiscounts = explicitlySelectedDiscount && (explicitlySelectedDiscount.tag || explicitlySelectedDiscount.type) === "good_pass" ? [
|
|
890
|
+
explicitlySelectedDiscount,
|
|
891
|
+
...applicableDiscounts.filter(
|
|
892
|
+
(discount) => {
|
|
893
|
+
const discountType = discount.tag || discount.type;
|
|
894
|
+
return discountType === "good_pass" && String(discount.id) !== String(explicitlySelectedDiscount.id);
|
|
895
|
+
}
|
|
896
|
+
),
|
|
897
|
+
...applicableDiscounts.filter(
|
|
898
|
+
(discount) => (discount.tag || discount.type) !== "good_pass"
|
|
899
|
+
)
|
|
900
|
+
] : applicableDiscounts;
|
|
874
901
|
let isManualDiscount = false;
|
|
875
902
|
let isItemRewardProductDiscount = false;
|
|
876
903
|
if (flatItem.type === "main") {
|
|
@@ -1049,21 +1076,65 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1049
1076
|
const arr = [];
|
|
1050
1077
|
if (flatItem.type === "main") {
|
|
1051
1078
|
if (splitCount < totalQuantity && isNeedSplit) {
|
|
1079
|
+
const remainingQuantity = totalQuantity - splitCount;
|
|
1080
|
+
const applicableNonGoodPassById = new Map(
|
|
1081
|
+
applicableDiscounts.filter((discount) => (discount.tag || discount.type) !== "good_pass").map((discount) => [String(discount.id), discount])
|
|
1082
|
+
);
|
|
1083
|
+
const remainderDiscountList = (product.discount_list || []).filter((discount) => {
|
|
1084
|
+
var _a3;
|
|
1085
|
+
const discountType = discount.tag || discount.type;
|
|
1086
|
+
if (discountType === "promotion")
|
|
1087
|
+
return true;
|
|
1088
|
+
if (discountType === "good_pass")
|
|
1089
|
+
return false;
|
|
1090
|
+
const resourceId = ((_a3 = discount.discount) == null ? void 0 : _a3.resource_id) ?? discount.id;
|
|
1091
|
+
return resourceId !== void 0 && resourceId !== null && applicableNonGoodPassById.has(String(resourceId));
|
|
1092
|
+
}).map((discount) => {
|
|
1093
|
+
var _a3;
|
|
1094
|
+
if ((discount.tag || discount.type) === "promotion")
|
|
1095
|
+
return discount;
|
|
1096
|
+
const resourceId = ((_a3 = discount.discount) == null ? void 0 : _a3.resource_id) ?? discount.id;
|
|
1097
|
+
const matchedDiscount = applicableNonGoodPassById.get(String(resourceId));
|
|
1098
|
+
if (matchedDiscount) {
|
|
1099
|
+
usedDiscounts.set(matchedDiscount.id, true);
|
|
1100
|
+
const appliedProducts = appliedDiscountProducts.get(matchedDiscount.id) || [];
|
|
1101
|
+
appliedProducts.push({
|
|
1102
|
+
...discount,
|
|
1103
|
+
_num: remainingQuantity
|
|
1104
|
+
});
|
|
1105
|
+
appliedDiscountProducts.set(matchedDiscount.id, appliedProducts);
|
|
1106
|
+
}
|
|
1107
|
+
return {
|
|
1108
|
+
...discount,
|
|
1109
|
+
// _num 是 Rules 运行态的行数量;Order 写回 tempOrder 时会裁剪该字段。
|
|
1110
|
+
_num: remainingQuantity
|
|
1111
|
+
};
|
|
1112
|
+
});
|
|
1113
|
+
const hasRetainedWalletDiscount = remainderDiscountList.some(
|
|
1114
|
+
(discount) => !["promotion", "good_pass"].includes(discount.tag || discount.type)
|
|
1115
|
+
);
|
|
1052
1116
|
let total = product.origin_total ?? product.total;
|
|
1053
1117
|
if ((product.discount_list || []).some((item) => item.type === "promotion")) {
|
|
1054
1118
|
total = product.total ?? product.origin_total;
|
|
1055
1119
|
}
|
|
1056
1120
|
arr.push(
|
|
1057
1121
|
this.hooks.setProduct(originProduct, {
|
|
1058
|
-
|
|
1059
|
-
|
|
1122
|
+
// 商品券只替换被拆出的 splitCount 件。余量行原本仍有效的折扣卡
|
|
1123
|
+
// 不能随 good_pass 拆分一起清除;已取消或已失效的折扣不会进入此列表。
|
|
1124
|
+
discount_list: remainderDiscountList,
|
|
1125
|
+
quantity: remainingQuantity,
|
|
1060
1126
|
_id: product._id.split("___")[0],
|
|
1061
|
-
total
|
|
1127
|
+
total,
|
|
1128
|
+
// 保留余量行当前的折后主价;Order.applyProductDiscountPrices 随后会基于
|
|
1129
|
+
// source_product_price + discount_list 再归一化,避免出现重复折扣。
|
|
1130
|
+
...hasRetainedWalletDiscount ? {
|
|
1131
|
+
main_product_selling_price: product.main_product_selling_price ?? product.price
|
|
1132
|
+
} : {}
|
|
1062
1133
|
})
|
|
1063
1134
|
);
|
|
1064
1135
|
}
|
|
1065
1136
|
for (let i = 0; i < splitCount; i++) {
|
|
1066
|
-
const selectedDiscount2 = selectedDiscountCard || applicableDiscounts[i];
|
|
1137
|
+
const selectedDiscount2 = isNeedSplit ? prioritizedApplicableDiscounts[i] : selectedDiscountCard || applicableDiscounts[i];
|
|
1067
1138
|
usedDiscounts.set(selectedDiscount2.id, true);
|
|
1068
1139
|
if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
|
|
1069
1140
|
const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
|
|
@@ -1091,8 +1162,8 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1091
1162
|
amount = productAllocation.discountAmount;
|
|
1092
1163
|
productDiscountDifference = productAllocation.difference;
|
|
1093
1164
|
mainProductSellingPrice = Math.max(new import_decimal.default(product.price).minus(amount).toNumber(), 0);
|
|
1094
|
-
} else if (
|
|
1095
|
-
const percent =
|
|
1165
|
+
} else if (resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount2) !== void 0) {
|
|
1166
|
+
const percent = resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount2);
|
|
1096
1167
|
reapplyDiscountPercent = new import_decimal.default(percent).toFixed(2);
|
|
1097
1168
|
mainProductSellingPrice = new import_decimal.default(product.price || 0).mul(new import_decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
|
|
1098
1169
|
amount = new import_decimal.default(product.price).minus(mainProductSellingPrice).toNumber();
|
|
@@ -1190,7 +1261,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1190
1261
|
const discountNum = splitCount;
|
|
1191
1262
|
const normalNum = totalQuantity - discountNum;
|
|
1192
1263
|
for (let i = 0; i < discountNum; i++) {
|
|
1193
|
-
const selectedDiscount2 =
|
|
1264
|
+
const selectedDiscount2 = prioritizedApplicableDiscounts[i];
|
|
1194
1265
|
usedDiscounts.set(selectedDiscount2.id, true);
|
|
1195
1266
|
if ((selectedDiscount2.tag || selectedDiscount2.type) === "good_pass") {
|
|
1196
1267
|
const currentCount = usedProductIdCounts.get(selectedDiscount2.product_id) || 0;
|
|
@@ -1267,10 +1338,19 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1267
1338
|
let targetProductTotal;
|
|
1268
1339
|
let fixedAmountPerItem;
|
|
1269
1340
|
let productDiscountDifference;
|
|
1341
|
+
let reapplyDiscountPercent;
|
|
1270
1342
|
if (isOrderLevel && productAllocation) {
|
|
1271
1343
|
fixedAmountPerItem = productAllocation.discountAmount;
|
|
1272
1344
|
productDiscountDifference = productAllocation.difference;
|
|
1273
1345
|
targetProductTotal = Math.max(new import_decimal.default(productOriginTotal).minus(fixedAmountPerItem).toNumber(), 0);
|
|
1346
|
+
} else if (resolveReapplyBookingDiscountPercent(originProduct, selectedDiscount2) !== void 0) {
|
|
1347
|
+
const percent = resolveReapplyBookingDiscountPercent(
|
|
1348
|
+
originProduct,
|
|
1349
|
+
selectedDiscount2
|
|
1350
|
+
);
|
|
1351
|
+
reapplyDiscountPercent = new import_decimal.default(percent).toFixed(2);
|
|
1352
|
+
targetProductTotal = new import_decimal.default(productOriginTotal).mul(new import_decimal.default(100).minus(percent)).div(100).toDecimalPlaces(2).toNumber();
|
|
1353
|
+
fixedAmountPerItem = new import_decimal.default(productOriginTotal).minus(targetProductTotal).toNumber();
|
|
1274
1354
|
} else {
|
|
1275
1355
|
targetProductTotal = (0, import_utils.getDiscountAmount)(
|
|
1276
1356
|
selectedDiscount2,
|
|
@@ -1292,7 +1372,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
|
|
|
1292
1372
|
title: selectedDiscount2.format_title,
|
|
1293
1373
|
original_amount: product.original_price,
|
|
1294
1374
|
product_id: product.id || product.product_id,
|
|
1295
|
-
percent: selectedDiscount2.par_value,
|
|
1375
|
+
percent: reapplyDiscountPercent ?? selectedDiscount2.par_value,
|
|
1296
1376
|
discount_product_id: selectedDiscount2.product_id
|
|
1297
1377
|
},
|
|
1298
1378
|
metadata: {
|
|
@@ -30,6 +30,7 @@ export declare class SalesSummaryModule extends BaseModule implements Module, Sa
|
|
|
30
30
|
taxRate?: number;
|
|
31
31
|
shopDiscount?: string | number;
|
|
32
32
|
channel?: string;
|
|
33
|
+
virtualSettlementMode?: boolean;
|
|
33
34
|
}): Promise<{
|
|
34
35
|
tax_title: string;
|
|
35
36
|
tax_rate: number | undefined;
|
|
@@ -126,7 +126,14 @@ var SalesSummaryModule = class extends import_BaseModule.BaseModule {
|
|
|
126
126
|
}
|
|
127
127
|
async getSummary(params) {
|
|
128
128
|
var _a, _b;
|
|
129
|
-
const {
|
|
129
|
+
const {
|
|
130
|
+
products = [],
|
|
131
|
+
isPriceIncludeTax,
|
|
132
|
+
taxRate,
|
|
133
|
+
shopDiscount,
|
|
134
|
+
channel,
|
|
135
|
+
virtualSettlementMode = false
|
|
136
|
+
} = params;
|
|
130
137
|
const summaryChannel = channel || this.resolveChannel();
|
|
131
138
|
if (summaryChannel !== this.surchargeListChannel) {
|
|
132
139
|
await this.getSurchargeList(summaryChannel);
|
|
@@ -150,7 +157,8 @@ var SalesSummaryModule = class extends import_BaseModule.BaseModule {
|
|
|
150
157
|
surchargeList: this.store.surchargeList,
|
|
151
158
|
scheduleById,
|
|
152
159
|
isInScheduleByDate: import_Schedule.ScheduleModule.isInScheduleByDate,
|
|
153
|
-
shopDiscount
|
|
160
|
+
shopDiscount,
|
|
161
|
+
virtualSettlementMode
|
|
154
162
|
});
|
|
155
163
|
const summaryWithTaxMeta = {
|
|
156
164
|
...summary,
|
|
@@ -99,7 +99,11 @@ function getUnitOriginalTotal(product) {
|
|
|
99
99
|
function isGeneratedVoucherProduct(product) {
|
|
100
100
|
const record = product;
|
|
101
101
|
const metadata = (record == null ? void 0 : record.metadata) || {};
|
|
102
|
-
|
|
102
|
+
const isGeneratedChild = metadata.parent_order_detail_id !== void 0 || metadata.gift_card_type !== void 0;
|
|
103
|
+
if (isGeneratedChild)
|
|
104
|
+
return true;
|
|
105
|
+
const isPersisted = (record == null ? void 0 : record.order_detail_id) !== void 0 && (record == null ? void 0 : record.order_detail_id) !== null;
|
|
106
|
+
return (record == null ? void 0 : record.extension_type) === "product_voucher" && !isPersisted;
|
|
103
107
|
}
|
|
104
108
|
function buildSurchargeServiceItems(products) {
|
|
105
109
|
return products.map((product) => {
|
|
@@ -886,13 +890,37 @@ function calculateSalesSummary(params) {
|
|
|
886
890
|
surchargeList,
|
|
887
891
|
scheduleById = {},
|
|
888
892
|
isInScheduleByDate,
|
|
889
|
-
shopDiscount
|
|
893
|
+
shopDiscount,
|
|
894
|
+
virtualSettlementMode = false
|
|
890
895
|
} = params;
|
|
891
896
|
if (!(products == null ? void 0 : products.length))
|
|
892
897
|
return createEmptySalesSummary();
|
|
893
898
|
const summaryProducts = products.filter((product) => !isGeneratedVoucherProduct(product));
|
|
894
899
|
if (!summaryProducts.length)
|
|
895
900
|
return createEmptySalesSummary();
|
|
901
|
+
if (virtualSettlementMode) {
|
|
902
|
+
const productQuantity2 = summaryProducts.reduce(
|
|
903
|
+
(sum, item) => sum + getSafeNum(item.num),
|
|
904
|
+
0
|
|
905
|
+
);
|
|
906
|
+
const productAmount2 = summaryProducts.reduce(
|
|
907
|
+
(sum, item) => sum.plus(
|
|
908
|
+
toDecimal(item.selling_price).times(getSafeNum(item.num))
|
|
909
|
+
),
|
|
910
|
+
new import_decimal.default(0)
|
|
911
|
+
);
|
|
912
|
+
const amount = toFixed2(productAmount2);
|
|
913
|
+
return {
|
|
914
|
+
...createEmptySalesSummary(),
|
|
915
|
+
product_quantity: productQuantity2,
|
|
916
|
+
product_original_amount: amount,
|
|
917
|
+
product_amount: amount,
|
|
918
|
+
product_expect_amount: amount,
|
|
919
|
+
expect_amount: amount,
|
|
920
|
+
total_amount: amount,
|
|
921
|
+
is_price_include_tax: isPriceIncludeTax
|
|
922
|
+
};
|
|
923
|
+
}
|
|
896
924
|
const productQuantity = summaryProducts.reduce(
|
|
897
925
|
(sum, item) => sum + getSafeNum(item.num),
|
|
898
926
|
0
|
package/lib/server/index.d.ts
CHANGED
|
@@ -164,6 +164,12 @@ declare class Server {
|
|
|
164
164
|
* 不影响当前界面展示,适用于切回前台、定时刷新等场景
|
|
165
165
|
*/
|
|
166
166
|
refreshOrdersInBackground(): Promise<void>;
|
|
167
|
+
/**
|
|
168
|
+
* 编辑正式订单时强制查询 Server 最新快照并覆盖本地缓存。
|
|
169
|
+
* 商品成员增删由 OrderModule 在 SQLite/Store 更新完成后广播,
|
|
170
|
+
* UI 可复用 order:onRemoteProductMembershipChanged 处理冲突。
|
|
171
|
+
*/
|
|
172
|
+
checkRemoteOrderProductMembership(orderId: string | number): Promise<void>;
|
|
167
173
|
/**
|
|
168
174
|
* 清空所有server模块的IndexedDB缓存
|
|
169
175
|
* @returns Promise<void>
|
|
@@ -257,6 +263,11 @@ declare class Server {
|
|
|
257
263
|
* 对单个商品 query 订阅者重算并推送(定时路径;不新建 schedule timer)。
|
|
258
264
|
*/
|
|
259
265
|
private recomputeAndNotifySubscriber;
|
|
266
|
+
/**
|
|
267
|
+
* 根据餐牌 ID 获取其绑定日程中的全部时间点。
|
|
268
|
+
* 商品查询定时器与 schedule-time-points 路由共用此逻辑。
|
|
269
|
+
*/
|
|
270
|
+
private getMenuScheduleTimePoints;
|
|
260
271
|
/**
|
|
261
272
|
* query 完成后为 subscriber 同步 schedule 定时器(先 clear 再 schedule)。
|
|
262
273
|
*/
|
|
@@ -512,6 +523,10 @@ declare class Server {
|
|
|
512
523
|
private handleOrderDraftSubmit;
|
|
513
524
|
private handlePendingSyncCheckoutOrder;
|
|
514
525
|
private buildPendingSyncCheckoutOrder;
|
|
526
|
+
/**
|
|
527
|
+
* Android 结账自动小票由当前设备设置控制;其它平台保持原有行为。
|
|
528
|
+
*/
|
|
529
|
+
private shouldAutoPrintCheckoutReceipt;
|
|
515
530
|
private shouldBuildSmallTicketData;
|
|
516
531
|
private shouldPrintSyncedOrder;
|
|
517
532
|
private hasPaymentStatus;
|