@pisell/pisellos 2.2.310 → 2.2.312
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 +0 -9
- package/dist/modules/Order/utils.d.ts +5 -3
- package/dist/modules/Order/utils.js +32 -11
- package/dist/server/modules/floor-plan/index.js +34 -3
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/index.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +6 -2
- package/lib/modules/Order/utils.d.ts +5 -3
- package/lib/modules/Order/utils.js +29 -10
- package/lib/server/modules/floor-plan/index.js +29 -1
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/index.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +7 -1
- package/package.json +1 -1
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// 导出评估器
|
|
2
|
-
export { PromotionEvaluator } from "./evaluator";
|
|
3
|
-
|
|
4
|
-
// 导出适配器
|
|
5
|
-
export { PromotionAdapter } from "./adapter";
|
|
6
|
-
export { default } from "./adapter";
|
|
7
|
-
|
|
8
|
-
// 导出策略配置示例常量
|
|
9
|
-
export { X_ITEMS_FOR_Y_PRICE_STRATEGY, BUY_X_GET_Y_FREE_STRATEGY, ITEM_REWARD_STRATEGY } from "./examples";
|
|
@@ -121,8 +121,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
121
121
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
122
122
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
123
123
|
* 不含折扣。**权威源**。
|
|
124
|
-
* - `
|
|
125
|
-
* - `metadata.
|
|
124
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
125
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
126
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
126
127
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
127
128
|
*
|
|
128
129
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -131,8 +132,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
131
132
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
132
133
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
133
134
|
* total(source + option + bundle)对齐。
|
|
135
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
134
136
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
135
|
-
*
|
|
137
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
136
138
|
* 优先级:
|
|
137
139
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
138
140
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -579,8 +579,9 @@ export function getBundleSellingMagnitude(bundle) {
|
|
|
579
579
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
580
580
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
581
581
|
* 不含折扣。**权威源**。
|
|
582
|
-
* - `
|
|
583
|
-
* - `metadata.
|
|
582
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
583
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
584
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
584
585
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
585
586
|
*
|
|
586
587
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -589,8 +590,9 @@ export function getBundleSellingMagnitude(bundle) {
|
|
|
589
590
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
590
591
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
591
592
|
* total(source + option + bundle)对齐。
|
|
593
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
592
594
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
593
|
-
*
|
|
595
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
594
596
|
* 优先级:
|
|
595
597
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
596
598
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -813,6 +815,15 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
813
815
|
var effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
814
816
|
return new Decimal(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
|
|
815
817
|
};
|
|
818
|
+
|
|
819
|
+
// optionDiscountAmount 已是每件主商品内的单规格优惠合计,不再乘商品数量。
|
|
820
|
+
var getOptionDiscountAmount = function getOptionDiscountAmount(discountList) {
|
|
821
|
+
return (discountList || []).reduce(function (total, discount) {
|
|
822
|
+
var _discount$metadata, _discount$metadata2;
|
|
823
|
+
if (discount !== null && discount !== void 0 && (_discount$metadata = discount.metadata) !== null && _discount$metadata !== void 0 && _discount$metadata.custom_product_bundle_map_id) return total;
|
|
824
|
+
return total.plus(Number(discount === null || discount === void 0 || (_discount$metadata2 = discount.metadata) === null || _discount$metadata2 === void 0 ? void 0 : _discount$metadata2.optionDiscountAmount) || 0);
|
|
825
|
+
}, new Decimal(0));
|
|
826
|
+
};
|
|
816
827
|
var getBundleIdentity = function getBundleIdentity(bundle) {
|
|
817
828
|
var _ref21, _bundle$bundle_id, _ref22, _ref23, _bundle$bundle_produc, _ref24, _ref25, _bundle$bundle_varian, _ref26, _bundle$bundle_group_;
|
|
818
829
|
return [(_ref21 = (_bundle$bundle_id = bundle.bundle_id) !== null && _bundle$bundle_id !== void 0 ? _bundle$bundle_id : bundle.id) !== null && _ref21 !== void 0 ? _ref21 : '', (_ref22 = (_ref23 = (_bundle$bundle_produc = bundle.bundle_product_id) !== null && _bundle$bundle_produc !== void 0 ? _bundle$bundle_produc : bundle._bundle_product_id) !== null && _ref23 !== void 0 ? _ref23 : bundle.product_id) !== null && _ref22 !== void 0 ? _ref22 : '', (_ref24 = (_ref25 = (_bundle$bundle_varian = bundle.bundle_variant_id) !== null && _bundle$bundle_varian !== void 0 ? _bundle$bundle_varian : bundle.variant_id) !== null && _ref25 !== void 0 ? _ref25 : bundle.product_variant_id) !== null && _ref24 !== void 0 ? _ref24 : 0, (_ref26 = (_bundle$bundle_group_ = bundle.bundle_group_id) !== null && _bundle$bundle_group_ !== void 0 ? _bundle$bundle_group_ : bundle.group_id) !== null && _ref26 !== void 0 ? _ref26 : ''].join('|');
|
|
@@ -850,12 +861,14 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
850
861
|
var _product$metadata7, _product$metadata8, _product$metadata9, _metadataAny$_promoti;
|
|
851
862
|
// source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
|
|
852
863
|
var metadataAny = product.metadata || {};
|
|
853
|
-
var
|
|
864
|
+
var productOptions = getProductSkuOptions(product);
|
|
865
|
+
var optionSum = sumOptionUnitPrice(productOptions);
|
|
866
|
+
var optionSellingSum = optionSum.minus(getOptionDiscountAmount(product.discount_list));
|
|
854
867
|
var sourcePrice;
|
|
855
868
|
if (metadataAny.source_product_price !== undefined) {
|
|
856
869
|
sourcePrice = String(metadataAny.source_product_price);
|
|
857
870
|
} else if (metadataAny.main_product_selling_price !== undefined) {
|
|
858
|
-
sourcePrice = new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
871
|
+
sourcePrice = new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString();
|
|
859
872
|
} else {
|
|
860
873
|
var _product$selling_pric;
|
|
861
874
|
sourcePrice = String((_product$selling_pric = product.selling_price) !== null && _product$selling_pric !== void 0 ? _product$selling_pric : 0);
|
|
@@ -886,6 +899,12 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
886
899
|
num: product.num || 1,
|
|
887
900
|
discount_list: product.discount_list || [],
|
|
888
901
|
bundle: product.product_bundle || [],
|
|
902
|
+
// 仅在 Rules 入参中映射 price,避免折后价污染订单的 add_price。
|
|
903
|
+
options: productOptions.map(function (option) {
|
|
904
|
+
return _objectSpread(_objectSpread({}, option), {}, {
|
|
905
|
+
price: option.add_price
|
|
906
|
+
});
|
|
907
|
+
}),
|
|
889
908
|
booking_id: ((_product$metadata8 = product.metadata) === null || _product$metadata8 === void 0 ? void 0 : _product$metadata8.booking_id) || null,
|
|
890
909
|
isClient: false,
|
|
891
910
|
// 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
|
|
@@ -893,20 +912,22 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
893
912
|
isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
|
|
894
913
|
holder_id: (_product$metadata9 = product.metadata) === null || _product$metadata9 === void 0 ? void 0 : _product$metadata9.holder_id,
|
|
895
914
|
startDate: getProductStartDate(product),
|
|
896
|
-
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
915
|
+
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new Decimal(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString() : undefined,
|
|
897
916
|
inPromotion: ((_metadataAny$_promoti = metadataAny._promotion) === null || _metadataAny$_promoti === void 0 ? void 0 : _metadataAny$_promoti.inPromotion) === true,
|
|
898
917
|
_promotion: metadataAny._promotion
|
|
899
918
|
};
|
|
900
919
|
},
|
|
901
920
|
setProduct: function setProduct(product, values) {
|
|
902
|
-
var _ref32, _values$quantity, _ref33, _metadataAny$source_p,
|
|
921
|
+
var _ref32, _values$quantity, _ref33, _metadataAny$source_p, _values$discount_list, _product$product_sku, _values$quantity2;
|
|
903
922
|
var nextNum = Number((_ref32 = (_values$quantity = values.quantity) !== null && _values$quantity !== void 0 ? _values$quantity : product.num) !== null && _ref32 !== void 0 ? _ref32 : 1) || 1;
|
|
904
923
|
var metadataAny = product.metadata || {};
|
|
905
924
|
var existedSource = (_ref33 = (_metadataAny$source_p = metadataAny.source_product_price) !== null && _metadataAny$source_p !== void 0 ? _metadataAny$source_p : product.selling_price) !== null && _ref33 !== void 0 ? _ref33 : '0';
|
|
906
925
|
var nextOptions = getProductSkuOptions(product);
|
|
907
926
|
var optionSum = sumOptionUnitPrice(nextOptions);
|
|
927
|
+
var nextDiscountList = (_values$discount_list = values.discount_list) !== null && _values$discount_list !== void 0 ? _values$discount_list : product.discount_list;
|
|
928
|
+
var optionSellingSum = optionSum.minus(getOptionDiscountAmount(nextDiscountList));
|
|
908
929
|
|
|
909
|
-
// Rules 返回的 main_product_selling_price / price
|
|
930
|
+
// Rules 返回的 main_product_selling_price / price 为不含 option 的主商品价。
|
|
910
931
|
// 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
|
|
911
932
|
// total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
|
|
912
933
|
var nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
|
|
@@ -915,8 +936,8 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
915
936
|
// 缺省时保留现有 source(券前 = 当前 source)。
|
|
916
937
|
var nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
|
|
917
938
|
|
|
918
|
-
//
|
|
919
|
-
var nextMainSellingPrice = new Decimal(Number(nextSourceSellingPrice) || 0).plus(
|
|
939
|
+
// 成交价只加回 option 折后合计;原价仍使用订单中保存的 option 原价。
|
|
940
|
+
var nextMainSellingPrice = new Decimal(Number(nextSourceSellingPrice) || 0).plus(optionSellingSum).toDecimalPlaces(2).toFixed(2);
|
|
920
941
|
var nextMainOriginalPrice = new Decimal(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
921
942
|
var nextBundle = values.bundle !== undefined ? mergeRulesBundlePrices(product.product_bundle, values.bundle) : product.product_bundle;
|
|
922
943
|
var composedSellingPrice = composeLinePrice({
|
|
@@ -936,7 +957,7 @@ export function createDefaultOrderRulesHooks(getBookings) {
|
|
|
936
957
|
return _objectSpread(_objectSpread({}, product), {}, {
|
|
937
958
|
selling_price: composedSellingPrice,
|
|
938
959
|
original_price: finalOriginalPrice,
|
|
939
|
-
discount_list:
|
|
960
|
+
discount_list: nextDiscountList,
|
|
940
961
|
num: (_values$quantity2 = values.quantity) !== null && _values$quantity2 !== void 0 ? _values$quantity2 : product.num,
|
|
941
962
|
product_bundle: nextBundle,
|
|
942
963
|
metadata: _objectSpread(_objectSpread({}, metadataAny), {}, {
|
|
@@ -31,6 +31,33 @@ import { FloorPlanHooks } from "./types";
|
|
|
31
31
|
var FLOOR_PLAN_SYNC_DEBOUNCE_MS = 3000;
|
|
32
32
|
var FLOOR_PLAN_STORE_NAME = 'floor_plans';
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Request failures can be plain response objects (rather than Error instances).
|
|
36
|
+
* Keep diagnostics useful without allowing the UI bridge to stringify them as
|
|
37
|
+
* "[object Object]".
|
|
38
|
+
*/
|
|
39
|
+
function getRequestErrorInfo(error) {
|
|
40
|
+
var _ref, _ref2, _value$resData$res, _value$resData, _value$response, _response$code, _response$status, _value$response2;
|
|
41
|
+
if (error instanceof Error && error.message) return {
|
|
42
|
+
message: error.message
|
|
43
|
+
};
|
|
44
|
+
if (typeof error === 'string' && error) return {
|
|
45
|
+
message: error
|
|
46
|
+
};
|
|
47
|
+
var value = error;
|
|
48
|
+
var response = (_ref = (_ref2 = (_value$resData$res = value === null || value === void 0 || (_value$resData = value.resData) === null || _value$resData === void 0 ? void 0 : _value$resData.res) !== null && _value$resData$res !== void 0 ? _value$resData$res : value === null || value === void 0 || (_value$response = value.response) === null || _value$response === void 0 ? void 0 : _value$response.data) !== null && _ref2 !== void 0 ? _ref2 : value === null || value === void 0 ? void 0 : value.data) !== null && _ref !== void 0 ? _ref : value;
|
|
49
|
+
var candidates = [value === null || value === void 0 ? void 0 : value.message, value === null || value === void 0 ? void 0 : value.error, response === null || response === void 0 ? void 0 : response.message, response === null || response === void 0 ? void 0 : response.error];
|
|
50
|
+
var message = candidates.find(function (candidate) {
|
|
51
|
+
return typeof candidate === 'string' && candidate.trim() !== '';
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
message: message || '平面图加载失败(未提供错误详情)',
|
|
55
|
+
code: (_response$code = response === null || response === void 0 ? void 0 : response.code) !== null && _response$code !== void 0 ? _response$code : value === null || value === void 0 ? void 0 : value.code,
|
|
56
|
+
status: (_response$status = response === null || response === void 0 ? void 0 : response.status) !== null && _response$status !== void 0 ? _response$status : value === null || value === void 0 ? void 0 : value.status,
|
|
57
|
+
httpStatus: value === null || value === void 0 || (_value$response2 = value.response) === null || _value$response2 === void 0 ? void 0 : _value$response2.status
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
34
61
|
/**
|
|
35
62
|
* 平面图模块:预加载列表、pubsub 同步、供 OS Server 路由读本地 store
|
|
36
63
|
*/
|
|
@@ -230,7 +257,7 @@ export var FloorPlanModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
230
257
|
key: "loadListFromServer",
|
|
231
258
|
value: function () {
|
|
232
259
|
var _loadListFromServer = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
|
|
233
|
-
var res, body, raw, list;
|
|
260
|
+
var res, body, raw, list, errorInfo;
|
|
234
261
|
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
|
235
262
|
while (1) switch (_context2.prev = _context2.next) {
|
|
236
263
|
case 0:
|
|
@@ -248,11 +275,15 @@ export var FloorPlanModule = /*#__PURE__*/function (_BaseModule) {
|
|
|
248
275
|
case 10:
|
|
249
276
|
_context2.prev = 10;
|
|
250
277
|
_context2.t0 = _context2["catch"](0);
|
|
278
|
+
errorInfo = getRequestErrorInfo(_context2.t0);
|
|
251
279
|
this.logWarning('loadListFromServer 失败', {
|
|
252
|
-
error:
|
|
280
|
+
error: errorInfo.message,
|
|
281
|
+
code: errorInfo.code,
|
|
282
|
+
status: errorInfo.status,
|
|
283
|
+
httpStatus: errorInfo.httpStatus
|
|
253
284
|
});
|
|
254
285
|
return _context2.abrupt("return", []);
|
|
255
|
-
case
|
|
286
|
+
case 15:
|
|
256
287
|
case "end":
|
|
257
288
|
return _context2.stop();
|
|
258
289
|
}
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 1 | 2 | 5 | 3 | 4 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
345
345
|
count: number;
|
|
346
346
|
left: number;
|
|
347
347
|
summaryCount: number;
|
|
348
|
-
status: "
|
|
348
|
+
status: "sold_out" | "lots_of_space" | "filling_up_fast";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -346,7 +346,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
346
346
|
* 获取当前的客户搜索条件
|
|
347
347
|
* @returns 当前搜索条件
|
|
348
348
|
*/
|
|
349
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
349
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
|
|
350
350
|
/**
|
|
351
351
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
352
352
|
* @returns 客户状态
|
|
@@ -54,8 +54,12 @@ function _processScannedProductItem() {
|
|
|
54
54
|
}
|
|
55
55
|
return _context.abrupt("return", runRequiresDetailFlow(host, item, ctx, bridge));
|
|
56
56
|
case 5:
|
|
57
|
-
values = genScanProductValues(item, code);
|
|
58
|
-
|
|
57
|
+
values = genScanProductValues(item, code); // 条码已唯一命中某个规格时,商品目录的 price 可能是“最低规格价”。
|
|
58
|
+
// 仅在扫码预选规格的这条路径改用命中规格价,避免影响商品卡片和手工选规格。
|
|
59
|
+
itemWithSelection = values.price === undefined ? _objectSpread(_objectSpread({}, item), {}, {
|
|
60
|
+
cartDetailValue: values
|
|
61
|
+
}) : _objectSpread(_objectSpread({}, item), {}, {
|
|
62
|
+
price: values.price,
|
|
59
63
|
cartDetailValue: values
|
|
60
64
|
});
|
|
61
65
|
decision = host.decideAddProduct(itemWithSelection, ctx);
|
|
@@ -121,8 +121,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
121
121
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
122
122
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
123
123
|
* 不含折扣。**权威源**。
|
|
124
|
-
* - `
|
|
125
|
-
* - `metadata.
|
|
124
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
125
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
126
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
126
127
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
127
128
|
*
|
|
128
129
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -131,8 +132,9 @@ export declare function getBundleSellingMagnitude(bundle: Record<string, any> |
|
|
|
131
132
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
132
133
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
133
134
|
* total(source + option + bundle)对齐。
|
|
135
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
134
136
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
135
|
-
*
|
|
137
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
136
138
|
* 优先级:
|
|
137
139
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
138
140
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -632,8 +632,9 @@ function getBundleSellingMagnitude(bundle) {
|
|
|
632
632
|
* = `metadata.main_product_original_price` + Σ(bundle 原价 × num)。
|
|
633
633
|
* - `metadata.source_product_price`:主商品/variant 基础价(已应用报价单),不含 option、
|
|
634
634
|
* 不含折扣。**权威源**。
|
|
635
|
-
* - `
|
|
636
|
-
* - `metadata.
|
|
635
|
+
* - `product_sku.option[].add_price` 保留单规格折前单价;Rules 的 option.price 只用于本次计算。
|
|
636
|
+
* - `metadata.main_product_original_price` = source + Σ(option.add_price × option.num)(含 option、不含折扣)。
|
|
637
|
+
* - `metadata.main_product_selling_price` = main_original − 行内 per-unit amount(含主商品及 option 优惠)。
|
|
637
638
|
* - `payment_price`:出站 payload 中为行 composite 已减整单折扣均摊价(无折扣时与 `selling_price` 同义)。
|
|
638
639
|
*
|
|
639
640
|
* Rules 钩子契约(hook_adapt 方案,Rules 内部保持不变):
|
|
@@ -642,8 +643,9 @@ function getBundleSellingMagnitude(bundle) {
|
|
|
642
643
|
* `getProductOriginTotalPrice` 会自行叠加 option + bundle,喂 source 可避免 option 双加。
|
|
643
644
|
* - `getProduct.total` = `selling_price × num`(行 composite × num),与 Rules 内部产出的
|
|
644
645
|
* total(source + option + bundle)对齐。
|
|
646
|
+
* - `getProduct.options` 用单规格原价参与重算;主商品折后价从 main_selling 减去 option 折后合计反推。
|
|
645
647
|
* - `setProduct` 反向流程:把 Rules 返回的 source-level `main_product_selling_price` / `price`
|
|
646
|
-
*
|
|
648
|
+
* 加回单规格原价合计,再减去 optionDiscountAmount;保留订单单规格原价供取消折扣及后续重算。
|
|
647
649
|
* 优先级:
|
|
648
650
|
* 1. `values.main_product_selling_price`(券应用分支,per-unit 券后 source-level 主价)
|
|
649
651
|
* 2. `values.price`(还原分支 `restoredPrice`、good_pass 归零)
|
|
@@ -842,6 +844,14 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
842
844
|
const effectiveNum = Number(num) > 0 ? Number(num) : 1;
|
|
843
845
|
return new _decimal.default(Number(totalLike) || 0).dividedBy(effectiveNum).toDecimalPlaces(2).toString();
|
|
844
846
|
};
|
|
847
|
+
|
|
848
|
+
// optionDiscountAmount 已是每件主商品内的单规格优惠合计,不再乘商品数量。
|
|
849
|
+
const getOptionDiscountAmount = discountList => {
|
|
850
|
+
return (discountList || []).reduce((total, discount) => {
|
|
851
|
+
if (discount?.metadata?.custom_product_bundle_map_id) return total;
|
|
852
|
+
return total.plus(Number(discount?.metadata?.optionDiscountAmount) || 0);
|
|
853
|
+
}, new _decimal.default(0));
|
|
854
|
+
};
|
|
845
855
|
const getBundleIdentity = bundle => {
|
|
846
856
|
return [bundle.bundle_id ?? bundle.id ?? '', bundle.bundle_product_id ?? bundle._bundle_product_id ?? bundle.product_id ?? '', bundle.bundle_variant_id ?? bundle.variant_id ?? bundle.product_variant_id ?? 0, bundle.bundle_group_id ?? bundle.group_id ?? ''].join('|');
|
|
847
857
|
};
|
|
@@ -884,12 +894,14 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
884
894
|
getProduct: product => {
|
|
885
895
|
// source_product_price 是权威源;兜底链:source → mainSelling − options(反推)→ 行 selling_price
|
|
886
896
|
const metadataAny = product.metadata || {};
|
|
887
|
-
const
|
|
897
|
+
const productOptions = getProductSkuOptions(product);
|
|
898
|
+
const optionSum = sumOptionUnitPrice(productOptions);
|
|
899
|
+
const optionSellingSum = optionSum.minus(getOptionDiscountAmount(product.discount_list));
|
|
888
900
|
let sourcePrice;
|
|
889
901
|
if (metadataAny.source_product_price !== undefined) {
|
|
890
902
|
sourcePrice = String(metadataAny.source_product_price);
|
|
891
903
|
} else if (metadataAny.main_product_selling_price !== undefined) {
|
|
892
|
-
sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
904
|
+
sourcePrice = new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString();
|
|
893
905
|
} else {
|
|
894
906
|
sourcePrice = String(product.selling_price ?? 0);
|
|
895
907
|
}
|
|
@@ -919,6 +931,11 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
919
931
|
num: product.num || 1,
|
|
920
932
|
discount_list: product.discount_list || [],
|
|
921
933
|
bundle: product.product_bundle || [],
|
|
934
|
+
// 仅在 Rules 入参中映射 price,避免折后价污染订单的 add_price。
|
|
935
|
+
options: productOptions.map(option => ({
|
|
936
|
+
...option,
|
|
937
|
+
price: option.add_price
|
|
938
|
+
})),
|
|
922
939
|
booking_id: product.metadata?.booking_id || null,
|
|
923
940
|
isClient: false,
|
|
924
941
|
// 勿写死 false:否则 Rules 不会走 total≠origin_total 的手动价推断,
|
|
@@ -926,7 +943,7 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
926
943
|
isManualDiscount: resolveRulesManualDiscountFlag(metadataAny),
|
|
927
944
|
holder_id: product.metadata?.holder_id,
|
|
928
945
|
startDate: getProductStartDate(product),
|
|
929
|
-
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(
|
|
946
|
+
main_product_selling_price: metadataAny.main_product_selling_price !== undefined ? new _decimal.default(Number(metadataAny.main_product_selling_price) || 0).minus(optionSellingSum).toDecimalPlaces(2).toString() : undefined,
|
|
930
947
|
inPromotion: metadataAny._promotion?.inPromotion === true,
|
|
931
948
|
_promotion: metadataAny._promotion
|
|
932
949
|
};
|
|
@@ -937,8 +954,10 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
937
954
|
const existedSource = metadataAny.source_product_price ?? product.selling_price ?? '0';
|
|
938
955
|
const nextOptions = getProductSkuOptions(product);
|
|
939
956
|
const optionSum = sumOptionUnitPrice(nextOptions);
|
|
957
|
+
const nextDiscountList = values.discount_list ?? product.discount_list;
|
|
958
|
+
const optionSellingSum = optionSum.minus(getOptionDiscountAmount(nextDiscountList));
|
|
940
959
|
|
|
941
|
-
// Rules 返回的 main_product_selling_price / price
|
|
960
|
+
// Rules 返回的 main_product_selling_price / price 为不含 option 的主商品价。
|
|
942
961
|
// 优先级:main_product_selling_price(per-unit 券后 source)> price(还原/good_pass 分支)>
|
|
943
962
|
// total/num(仅当 Rules 只给 total 时的兜底)> 保留当前 source。
|
|
944
963
|
const nextSourceSellingPrice = values.main_product_selling_price !== undefined ? String(values.main_product_selling_price) : values.price !== undefined ? String(values.price) : values.total !== undefined ? toUnitPriceString(values.total, nextNum) : String(existedSource);
|
|
@@ -947,8 +966,8 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
947
966
|
// 缺省时保留现有 source(券前 = 当前 source)。
|
|
948
967
|
const nextSourceOriginalPrice = values.original_price !== undefined ? String(values.original_price) : String(existedSource);
|
|
949
968
|
|
|
950
|
-
//
|
|
951
|
-
const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(
|
|
969
|
+
// 成交价只加回 option 折后合计;原价仍使用订单中保存的 option 原价。
|
|
970
|
+
const nextMainSellingPrice = new _decimal.default(Number(nextSourceSellingPrice) || 0).plus(optionSellingSum).toDecimalPlaces(2).toFixed(2);
|
|
952
971
|
const nextMainOriginalPrice = new _decimal.default(Number(nextSourceOriginalPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
|
|
953
972
|
const nextBundle = values.bundle !== undefined ? mergeRulesBundlePrices(product.product_bundle, values.bundle) : product.product_bundle;
|
|
954
973
|
const composedSellingPrice = composeLinePrice({
|
|
@@ -969,7 +988,7 @@ function createDefaultOrderRulesHooks(getBookings) {
|
|
|
969
988
|
...product,
|
|
970
989
|
selling_price: composedSellingPrice,
|
|
971
990
|
original_price: finalOriginalPrice,
|
|
972
|
-
discount_list:
|
|
991
|
+
discount_list: nextDiscountList,
|
|
973
992
|
num: values.quantity ?? product.num,
|
|
974
993
|
product_bundle: nextBundle,
|
|
975
994
|
metadata: {
|
|
@@ -9,6 +9,30 @@ var _types = require("./types");
|
|
|
9
9
|
const FLOOR_PLAN_SYNC_DEBOUNCE_MS = 3000;
|
|
10
10
|
const FLOOR_PLAN_STORE_NAME = 'floor_plans';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Request failures can be plain response objects (rather than Error instances).
|
|
14
|
+
* Keep diagnostics useful without allowing the UI bridge to stringify them as
|
|
15
|
+
* "[object Object]".
|
|
16
|
+
*/
|
|
17
|
+
function getRequestErrorInfo(error) {
|
|
18
|
+
if (error instanceof Error && error.message) return {
|
|
19
|
+
message: error.message
|
|
20
|
+
};
|
|
21
|
+
if (typeof error === 'string' && error) return {
|
|
22
|
+
message: error
|
|
23
|
+
};
|
|
24
|
+
const value = error;
|
|
25
|
+
const response = value?.resData?.res ?? value?.response?.data ?? value?.data ?? value;
|
|
26
|
+
const candidates = [value?.message, value?.error, response?.message, response?.error];
|
|
27
|
+
const message = candidates.find(candidate => typeof candidate === 'string' && candidate.trim() !== '');
|
|
28
|
+
return {
|
|
29
|
+
message: message || '平面图加载失败(未提供错误详情)',
|
|
30
|
+
code: response?.code ?? value?.code,
|
|
31
|
+
status: response?.status ?? value?.status,
|
|
32
|
+
httpStatus: value?.response?.status
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
12
36
|
/**
|
|
13
37
|
* 平面图模块:预加载列表、pubsub 同步、供 OS Server 路由读本地 store
|
|
14
38
|
*/
|
|
@@ -144,8 +168,12 @@ class FloorPlanModule extends _BaseModule.BaseModule {
|
|
|
144
168
|
const list = Array.isArray(raw) ? raw : [];
|
|
145
169
|
return list;
|
|
146
170
|
} catch (e) {
|
|
171
|
+
const errorInfo = getRequestErrorInfo(e);
|
|
147
172
|
this.logWarning('loadListFromServer 失败', {
|
|
148
|
-
error:
|
|
173
|
+
error: errorInfo.message,
|
|
174
|
+
code: errorInfo.code,
|
|
175
|
+
status: errorInfo.status,
|
|
176
|
+
httpStatus: errorInfo.httpStatus
|
|
149
177
|
});
|
|
150
178
|
return [];
|
|
151
179
|
}
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 1 | 2 | 5 | 3 | 4 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
345
345
|
count: number;
|
|
346
346
|
left: number;
|
|
347
347
|
summaryCount: number;
|
|
348
|
-
status: "
|
|
348
|
+
status: "sold_out" | "lots_of_space" | "filling_up_fast";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -346,7 +346,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
346
346
|
* 获取当前的客户搜索条件
|
|
347
347
|
* @returns 当前搜索条件
|
|
348
348
|
*/
|
|
349
|
-
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "
|
|
349
|
+
getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
|
|
350
350
|
/**
|
|
351
351
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
352
352
|
* @returns 客户状态
|
|
@@ -32,9 +32,15 @@ async function processScannedProductItem(host, item, code, bridge) {
|
|
|
32
32
|
return runRequiresDetailFlow(host, item, ctx, bridge);
|
|
33
33
|
}
|
|
34
34
|
const values = (0, _scanProductValues.genScanProductValues)(item, code);
|
|
35
|
-
|
|
35
|
+
// 条码已唯一命中某个规格时,商品目录的 price 可能是“最低规格价”。
|
|
36
|
+
// 仅在扫码预选规格的这条路径改用命中规格价,避免影响商品卡片和手工选规格。
|
|
37
|
+
const itemWithSelection = values.price === undefined ? {
|
|
36
38
|
...item,
|
|
37
39
|
cartDetailValue: values
|
|
40
|
+
} : {
|
|
41
|
+
...item,
|
|
42
|
+
price: values.price,
|
|
43
|
+
cartDetailValue: values
|
|
38
44
|
};
|
|
39
45
|
const decision = host.decideAddProduct(itemWithSelection, ctx);
|
|
40
46
|
return runAddProductDecision(host, item, decision, ctx, bridge);
|