@pisell/pisellos 0.10.59 → 0.10.61
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/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +25 -2
- package/dist/modules/Discount/index.js +1 -0
- package/dist/modules/Order/holderRelations.d.ts +14 -0
- package/dist/modules/Order/holderRelations.js +154 -0
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +92 -47
- package/dist/modules/Order/types.d.ts +19 -1
- package/dist/modules/Order/types.js +2 -0
- package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
- package/dist/modules/Order/utils/discountProductLineIdentity.js +142 -7
- package/dist/modules/Order/utils/orderCollectionIdentity.js +24 -10
- package/dist/modules/Order/utils.d.ts +1 -1
- package/dist/modules/Order/utils.js +35 -9
- package/dist/server/index.js +18 -12
- package/dist/server/modules/order/index.d.ts +4 -0
- package/dist/server/modules/order/index.js +255 -190
- package/dist/server/modules/order/types.d.ts +3 -0
- package/dist/shared/receipt/small-ticket.js +17 -0
- package/dist/shared/sales/loadSalesOrderSnapshot.js +1 -1
- package/dist/solution/BaseSales/index.js +97 -27
- package/dist/solution/BaseSales/types.d.ts +2 -1
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +7 -3
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +12 -3
- package/dist/solution/BookingTicket/index.js +7 -4
- package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
- package/dist/solution/BookingTicket/utils/addProductDecision.js +4 -3
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +6 -2
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +1 -0
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +2 -1
- package/dist/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/dist/solution/UnifiedBookingSales/index.js +4 -4
- package/dist/utils/platform.d.ts +2 -0
- package/dist/utils/platform.js +6 -0
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +16 -1
- package/lib/modules/Discount/index.js +1 -0
- package/lib/modules/Order/holderRelations.d.ts +14 -0
- package/lib/modules/Order/holderRelations.js +98 -0
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +44 -12
- package/lib/modules/Order/types.d.ts +19 -1
- package/lib/modules/Order/types.js +1 -0
- package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
- package/lib/modules/Order/utils/discountProductLineIdentity.js +51 -2
- package/lib/modules/Order/utils/orderCollectionIdentity.js +5 -0
- package/lib/modules/Order/utils.d.ts +1 -1
- package/lib/modules/Order/utils.js +27 -6
- package/lib/server/index.js +6 -0
- package/lib/server/modules/order/index.d.ts +4 -0
- package/lib/server/modules/order/index.js +46 -4
- package/lib/server/modules/order/types.d.ts +3 -0
- package/lib/shared/receipt/small-ticket.js +15 -0
- package/lib/shared/sales/loadSalesOrderSnapshot.js +1 -1
- package/lib/solution/BaseSales/index.js +39 -2
- package/lib/solution/BaseSales/types.d.ts +2 -1
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +7 -0
- package/lib/solution/BookingTicket/index.js +4 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +1 -1
- package/lib/solution/BookingTicket/utils/addProductDecision.js +4 -3
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +7 -1
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +1 -0
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +2 -1
- package/lib/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/lib/solution/UnifiedBookingSales/index.js +3 -3
- package/lib/utils/platform.d.ts +2 -0
- package/lib/utils/platform.js +7 -0
- package/package.json +1 -1
package/dist/utils/platform.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var CUSTOMER_USER_PLATFORMS = new Set(['pc', 'h5']);
|
|
2
|
+
var SELF_SERVICE_PLATFORMS = new Set(['kiosk', 'vending']);
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Normalize the runtime platform passed through solution/module otherParams.
|
|
@@ -12,4 +13,9 @@ export function normalizeRuntimePlatform(platform) {
|
|
|
12
13
|
*/
|
|
13
14
|
export function isCustomerUserPlatform(platform) {
|
|
14
15
|
return CUSTOMER_USER_PLATFORMS.has(normalizeRuntimePlatform(platform));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Kiosk and vending retain distinct channels but share self-service checkout behavior. */
|
|
19
|
+
export function isSelfServicePlatform(platform) {
|
|
20
|
+
return SELF_SERVICE_PLATFORMS.has(normalizeRuntimePlatform(platform));
|
|
15
21
|
}
|
|
@@ -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; }
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { OrderProduct } from '../../Order/types';
|
|
1
|
+
import type { OrderHolderRelation, OrderProduct } from '../../Order/types';
|
|
2
2
|
export interface BuildNormalProductCacheItemFromOrderLineInput {
|
|
3
3
|
/** tempOrder.products 中的一行(普通商品,无关联 booking) */
|
|
4
4
|
product: OrderProduct;
|
|
5
5
|
/** 商品 catalog / 详情,用于 variant / option / bundle 模板字段 */
|
|
6
6
|
sourceProduct?: Record<string, any> | null;
|
|
7
|
+
/** 整单关系集合,按商品行 UID 回填。 */
|
|
8
|
+
holder_relations?: OrderHolderRelation[];
|
|
7
9
|
}
|
|
8
10
|
export declare function buildNormalProductCacheItemFromOrderLine(input: BuildNormalProductCacheItemFromOrderLineInput): Record<string, any>;
|
|
@@ -4,13 +4,15 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.buildNormalProductCacheItemFromOrderLine = buildNormalProductCacheItemFromOrderLine;
|
|
7
|
+
var _lodashEs = require("lodash-es");
|
|
8
|
+
var _holderRelations = require("../../Order/holderRelations");
|
|
7
9
|
var _utils = require("../../Order/utils");
|
|
8
10
|
var _entitlementPass = require("../../Discount/entitlementPass");
|
|
9
11
|
var _orderLineDisplay = require("./orderLineDisplay");
|
|
10
12
|
/**
|
|
11
13
|
* 从已加车的普通商品 order line 反查 SkuDetailModal edit 所需的 cacheItem。
|
|
12
14
|
*
|
|
13
|
-
* 与 `buildCacheItemFromOrderLine`(预约行 + booking
|
|
15
|
+
* 与 `buildCacheItemFromOrderLine`(预约行 + booking)并列;Holder 从订单关系回填,不生成预约字段。
|
|
14
16
|
*/
|
|
15
17
|
/**
|
|
16
18
|
* 解析 v2 主商品 source 价(不含 option、不含 bundle),供 SkuDetailModal / transform 使用。
|
|
@@ -84,6 +86,15 @@ function buildNormalProductCacheItemFromOrderLine(input) {
|
|
|
84
86
|
const original = Number(product.original_price ?? selling);
|
|
85
87
|
const uid = product.metadata?.unique_identification_number;
|
|
86
88
|
const originExtend = product.metadata?.origin?._extend;
|
|
89
|
+
const holderRelations = (0, _lodashEs.cloneDeep)((0, _holderRelations.getProductHolderRelations)(input, product));
|
|
90
|
+
const formRelations = holderRelations.filter(relation => relation.holder_type === 'form');
|
|
91
|
+
const holderIds = formRelations.map(relation => relation.holder_id);
|
|
92
|
+
const holderNames = formRelations.map(relation => relation.metadata?.name).filter(name => typeof name === 'string' && name.length > 0);
|
|
93
|
+
const holder = formRelations.length > 0 ? {
|
|
94
|
+
...(formRelations[0].metadata || {}),
|
|
95
|
+
form_record: holderIds,
|
|
96
|
+
name: holderNames.join(',')
|
|
97
|
+
} : null;
|
|
87
98
|
const shouldPreserveEntitlementPriceOverride = hasEntitlementPassDiscount(product) && (originExtend?.priceOverride !== undefined || product.metadata?.price_override != null);
|
|
88
99
|
const hasPriceOverride = originExtend?.priceOverride !== undefined || shouldPreserveEntitlementPriceOverride;
|
|
89
100
|
const option = (0, _utils.getProductSkuOptions)(product);
|
|
@@ -115,6 +126,9 @@ function buildNormalProductCacheItemFromOrderLine(input) {
|
|
|
115
126
|
skuValue: JSON.parse(JSON.stringify(skuValue)),
|
|
116
127
|
_skuValue: JSON.parse(JSON.stringify(skuValue)),
|
|
117
128
|
isNormalProduct: true,
|
|
129
|
+
holder_relations: holderRelations,
|
|
130
|
+
holder,
|
|
131
|
+
holder_id: holderIds,
|
|
118
132
|
metadata: {
|
|
119
133
|
product_add_schedule_time: product.metadata?.product_add_schedule_time
|
|
120
134
|
},
|
|
@@ -134,6 +148,7 @@ function buildNormalProductCacheItemFromOrderLine(input) {
|
|
|
134
148
|
}
|
|
135
149
|
return {
|
|
136
150
|
...(sourceProduct || {}),
|
|
151
|
+
holder_config: sourceProduct?.holder_config !== undefined ? sourceProduct.holder_config : product.metadata?.holder_config,
|
|
137
152
|
id: resolvedId,
|
|
138
153
|
product_id: resolvedId,
|
|
139
154
|
_id: uid,
|
|
@@ -142,6 +142,7 @@ class DiscountModule extends _BaseModule.BaseModule {
|
|
|
142
142
|
} = options || {};
|
|
143
143
|
const result = await this.request.get(`/machinecode/batch-search`, {
|
|
144
144
|
code,
|
|
145
|
+
resolve_ticket_order: 1,
|
|
145
146
|
translate_flag: 1,
|
|
146
147
|
tags: ['entitlement_pass', 'good_pass', 'product_discount_card'],
|
|
147
148
|
// available: 1,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OrderHolderRelation, OrderTempOrder } from './types';
|
|
2
|
+
/** 在原订单上补齐关系身份,让缓存、提交和重试共用同一个 UUID。 */
|
|
3
|
+
export declare function ensureHolderRelationUuids(order: {
|
|
4
|
+
holder_relations?: OrderHolderRelation[];
|
|
5
|
+
}): void;
|
|
6
|
+
export declare function hasProductBooking(product: Record<string, any>): boolean;
|
|
7
|
+
export declare function getProductHolderRelations(order: {
|
|
8
|
+
holder_relations?: OrderHolderRelation[];
|
|
9
|
+
}, product: Record<string, any>): OrderHolderRelation[];
|
|
10
|
+
export declare function replaceProductHolderRelations(order: OrderTempOrder, product: Record<string, any>, patch: OrderHolderRelation[] | undefined): void;
|
|
11
|
+
/** 只删除明确被用户删除的行,不从稀疏远端快照推断删除。 */
|
|
12
|
+
export declare function removeProductHolderRelations(order: OrderTempOrder, products: Array<Record<string, any>>): void;
|
|
13
|
+
/** 仅兼容尚无新字段的旧测试草稿;显式 [] 永远不恢复旧 product 数据。 */
|
|
14
|
+
export declare function restoreLegacyHolderRelations(order: Record<string, any>): OrderHolderRelation[] | undefined;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ensureHolderRelationUuids = ensureHolderRelationUuids;
|
|
7
|
+
exports.getProductHolderRelations = getProductHolderRelations;
|
|
8
|
+
exports.hasProductBooking = hasProductBooking;
|
|
9
|
+
exports.removeProductHolderRelations = removeProductHolderRelations;
|
|
10
|
+
exports.replaceProductHolderRelations = replaceProductHolderRelations;
|
|
11
|
+
exports.restoreLegacyHolderRelations = restoreLegacyHolderRelations;
|
|
12
|
+
var _orderCollectionIdentity = require("./utils/orderCollectionIdentity");
|
|
13
|
+
function getHolderRelationUuid(relation) {
|
|
14
|
+
return typeof relation?.uuid === 'string' && relation.uuid.trim() ? relation.uuid : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** 在原订单上补齐关系身份,让缓存、提交和重试共用同一个 UUID。 */
|
|
18
|
+
function ensureHolderRelationUuids(order) {
|
|
19
|
+
if (!Array.isArray(order.holder_relations)) return;
|
|
20
|
+
for (const relation of order.holder_relations) {
|
|
21
|
+
if (relation && typeof relation === 'object' && !getHolderRelationUuid(relation)) {
|
|
22
|
+
relation.uuid = (0, _orderCollectionIdentity.createUuidV4)();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function hasProductBooking(product) {
|
|
27
|
+
const bookingIds = [product.booking_id, product.metadata?.booking_id, product.schedule_event_id];
|
|
28
|
+
return Boolean(product.booking_uid || product.metadata?.booking_uid) || bookingIds.some(id => id !== undefined && id !== null && String(id) !== '' && String(id) !== '0');
|
|
29
|
+
}
|
|
30
|
+
function getProductHolderRelations(order, product) {
|
|
31
|
+
const uid = product.metadata?.unique_identification_number ?? product.unique_identification_number;
|
|
32
|
+
if (uid === undefined || uid === null || uid === '') return [];
|
|
33
|
+
return (order.holder_relations || []).filter(relation => relation.relation_model === 'order_detail' && String(relation.relation_uuid) === String(uid));
|
|
34
|
+
}
|
|
35
|
+
function replaceProductHolderRelations(order, product, patch) {
|
|
36
|
+
if (patch === undefined || hasProductBooking(product)) return;
|
|
37
|
+
const uid = product.metadata?.unique_identification_number ?? product.unique_identification_number;
|
|
38
|
+
if (uid === undefined || uid === null || uid === '') return;
|
|
39
|
+
const existing = getProductHolderRelations(order, product);
|
|
40
|
+
const next = new Map();
|
|
41
|
+
for (const relation of patch) {
|
|
42
|
+
const key = `${relation.holder_type}:${relation.holder_id}`;
|
|
43
|
+
const previous = existing.find(item => item.holder_type === relation.holder_type && String(item.holder_id) === String(relation.holder_id));
|
|
44
|
+
next.set(key, {
|
|
45
|
+
...previous,
|
|
46
|
+
...relation,
|
|
47
|
+
uuid: getHolderRelationUuid(previous) || getHolderRelationUuid(relation) || (0, _orderCollectionIdentity.createUuidV4)(),
|
|
48
|
+
relation_model: 'order_detail',
|
|
49
|
+
relation_uuid: String(uid),
|
|
50
|
+
...(previous?.metadata || relation.metadata ? {
|
|
51
|
+
metadata: {
|
|
52
|
+
...previous?.metadata,
|
|
53
|
+
...relation.metadata
|
|
54
|
+
}
|
|
55
|
+
} : {})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
order.holder_relations = [...(order.holder_relations || []).filter(relation => relation.relation_model !== 'order_detail' || String(relation.relation_uuid) !== String(uid)), ...next.values()];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 只删除明确被用户删除的行,不从稀疏远端快照推断删除。 */
|
|
62
|
+
function removeProductHolderRelations(order, products) {
|
|
63
|
+
if (!Array.isArray(order.holder_relations)) return;
|
|
64
|
+
const removedUids = new Set(products.map(product => String(product.metadata?.unique_identification_number ?? product.unique_identification_number ?? '')));
|
|
65
|
+
order.holder_relations = order.holder_relations.filter(relation => relation.relation_model !== 'order_detail' || !removedUids.has(String(relation.relation_uuid)));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** 仅兼容尚无新字段的旧测试草稿;显式 [] 永远不恢复旧 product 数据。 */
|
|
69
|
+
function restoreLegacyHolderRelations(order) {
|
|
70
|
+
if (Object.prototype.hasOwnProperty.call(order, 'holder_relations')) {
|
|
71
|
+
return Array.isArray(order.holder_relations) ? order.holder_relations : undefined;
|
|
72
|
+
}
|
|
73
|
+
const relations = [];
|
|
74
|
+
const bookingProductUids = new Set((order.bookings || []).map(booking => String(booking.product_uid ?? booking.metadata?.product_uid ?? '')));
|
|
75
|
+
for (const product of order.products || []) {
|
|
76
|
+
if (hasProductBooking(product)) continue;
|
|
77
|
+
const uid = product.metadata?.unique_identification_number ?? product.unique_identification_number;
|
|
78
|
+
if (uid === undefined || uid === null || uid === '' || bookingProductUids.has(String(uid))) continue;
|
|
79
|
+
const holder = product.metadata?.holder || {};
|
|
80
|
+
const rawIds = product.metadata?.holder_id ?? holder.form_record;
|
|
81
|
+
const ids = (Array.isArray(rawIds) ? rawIds : [rawIds]).filter(id => id !== undefined && id !== null && id !== '' && Number.isInteger(Number(id)) && Number(id) >= 0);
|
|
82
|
+
for (const id of ids) {
|
|
83
|
+
const metadata = {
|
|
84
|
+
...holder,
|
|
85
|
+
form_record: [Number(id)]
|
|
86
|
+
};
|
|
87
|
+
if (ids.length !== 1) delete metadata.name;
|
|
88
|
+
relations.push({
|
|
89
|
+
relation_model: 'order_detail',
|
|
90
|
+
relation_uuid: String(uid),
|
|
91
|
+
holder_type: 'form',
|
|
92
|
+
holder_id: Number(id),
|
|
93
|
+
metadata
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return relations.length ? relations : undefined;
|
|
98
|
+
}
|
|
@@ -687,6 +687,6 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
687
687
|
getOrderInfo(order_id: number): Promise<any>;
|
|
688
688
|
getVouchers(): any[];
|
|
689
689
|
}
|
|
690
|
-
export type { AddProductToOrderOptions, OrderMetaList, PointCardSnapshotItem, VirtualCurrencySnapshotItem, RemoveProductsFromOrderOptions, SalesNote, SalesNoteDraftInput, SalesNoteLocalizedSelection, SalesNoteLocalizedText, SalesNoteRelation, SalesNoteTextInput, SetSalesNoteInput, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, } from './types';
|
|
690
|
+
export type { OrderHolderRelation, AddProductToOrderOptions, OrderMetaList, PointCardSnapshotItem, VirtualCurrencySnapshotItem, RemoveProductsFromOrderOptions, SalesNote, SalesNoteDraftInput, SalesNoteLocalizedSelection, SalesNoteLocalizedText, SalesNoteRelation, SalesNoteTextInput, SetSalesNoteInput, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, } from './types';
|
|
691
691
|
export { isFulfillmentTimingBooking } from './pickupTiming';
|
|
692
692
|
export type { PickupTimingBooking, PickupTimingBookingInput, PickupTimingBookingMetadata, PickupTimingSelectionMode, PickupTimingSource, } from './pickupTiming';
|
|
@@ -15,6 +15,7 @@ var _BaseModule = require("../BaseModule");
|
|
|
15
15
|
var _types = require("./types");
|
|
16
16
|
var _utils = require("./utils");
|
|
17
17
|
var _utils2 = require("../Product/utils");
|
|
18
|
+
var _holderRelations = require("./holderRelations");
|
|
18
19
|
var _weighedProduct = require("./utils/weighedProduct");
|
|
19
20
|
var _pickupTiming = require("./pickupTiming");
|
|
20
21
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
@@ -602,7 +603,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
602
603
|
this.store.rules = rules;
|
|
603
604
|
}
|
|
604
605
|
createDefaultRulesHooks() {
|
|
605
|
-
return (0, _utils.createDefaultOrderRulesHooks)(() => this.store.tempOrder?.bookings || []);
|
|
606
|
+
return (0, _utils.createDefaultOrderRulesHooks)(() => this.store.tempOrder?.bookings || [], () => this.store.tempOrder?.holder_relations);
|
|
606
607
|
}
|
|
607
608
|
|
|
608
609
|
/**
|
|
@@ -916,7 +917,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
916
917
|
discount_list: (0, _utils.normalizeOrderProductDiscountList)((0, _manualProductDiscount.syncManualProductDiscountProductNum)(mergedProduct.discount_list, mergedProduct.num))
|
|
917
918
|
};
|
|
918
919
|
}));
|
|
919
|
-
(0, _discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
|
|
920
|
+
(0, _discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder, discountList);
|
|
920
921
|
(0, _discountProductLineIdentity.consolidateDiscountFreeProductLines)(tempOrder);
|
|
921
922
|
}
|
|
922
923
|
if (result?.discountList) {
|
|
@@ -1161,7 +1162,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1161
1162
|
* sessionStorage 的 cacheId 分桶。写入失败由 BaseModule 静默降级。
|
|
1162
1163
|
*/
|
|
1163
1164
|
persistTempOrder() {
|
|
1164
|
-
if (!this.
|
|
1165
|
+
if (!this.store.tempOrder) return;
|
|
1166
|
+
(0, _holderRelations.ensureHolderRelationUuids)(this.store.tempOrder);
|
|
1167
|
+
if (!this.sessionStoragePersistEnabled) return;
|
|
1165
1168
|
this.checkSaveCache({
|
|
1166
1169
|
cacheId: this.cacheId,
|
|
1167
1170
|
fatherModule: this.fatherModule,
|
|
@@ -1870,7 +1873,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1870
1873
|
source_product_price: this.normalizeFingerprintMoney(metadata.source_product_price),
|
|
1871
1874
|
main_product_selling_price: this.normalizeFingerprintMoney(metadata.main_product_selling_price),
|
|
1872
1875
|
main_product_original_price: this.normalizeFingerprintMoney(metadata.main_product_original_price),
|
|
1873
|
-
product_discount_difference: this.normalizeFingerprintMoney(metadata.product_discount_difference)
|
|
1876
|
+
product_discount_difference: this.normalizeFingerprintMoney(metadata.product_discount_difference),
|
|
1877
|
+
...(!(0, _holderRelations.hasProductBooking)(product) ? {
|
|
1878
|
+
holder_relations: this.normalizeFingerprintValue((0, _holderRelations.getProductHolderRelations)(this.store.tempOrder || {}, product))
|
|
1879
|
+
} : {})
|
|
1874
1880
|
},
|
|
1875
1881
|
product_sku: this.normalizeFingerprintValue({
|
|
1876
1882
|
code: sku.code ?? '',
|
|
@@ -1906,7 +1912,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1906
1912
|
items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
|
|
1907
1913
|
return JSON.stringify(items);
|
|
1908
1914
|
}
|
|
1909
|
-
buildProductStructuralFingerprintItem(product) {
|
|
1915
|
+
buildProductStructuralFingerprintItem(product, order = this.store.tempOrder || {}) {
|
|
1910
1916
|
const sku = product?.product_sku || {};
|
|
1911
1917
|
const metadata = product?.metadata || {};
|
|
1912
1918
|
const discountTypes = (product?.discount_list || []).map(discount => discount?.type ?? discount?.tag);
|
|
@@ -1921,7 +1927,10 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1921
1927
|
unique_identification_number: metadata.unique_identification_number ?? product?.unique_identification_number ?? '',
|
|
1922
1928
|
price_override: metadata.price_override ?? '',
|
|
1923
1929
|
is_manual_discount: metadata.is_manual_discount ?? '',
|
|
1924
|
-
product_discount_reason: metadata.product_discount_reason ?? ''
|
|
1930
|
+
product_discount_reason: metadata.product_discount_reason ?? '',
|
|
1931
|
+
...(!(0, _holderRelations.hasProductBooking)(product) ? {
|
|
1932
|
+
holder_relations: this.normalizeFingerprintValue((0, _holderRelations.getProductHolderRelations)(order, product))
|
|
1933
|
+
} : {})
|
|
1925
1934
|
},
|
|
1926
1935
|
product_sku: this.normalizeFingerprintValue({
|
|
1927
1936
|
code: sku.code ?? '',
|
|
@@ -1959,8 +1968,8 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
1959
1968
|
})))
|
|
1960
1969
|
};
|
|
1961
1970
|
}
|
|
1962
|
-
buildOrderProductsStructuralFingerprint(products) {
|
|
1963
|
-
const items = (products || []).map(product => this.buildProductStructuralFingerprintItem(product));
|
|
1971
|
+
buildOrderProductsStructuralFingerprint(products, order = this.store.tempOrder || {}) {
|
|
1972
|
+
const items = (products || []).map(product => this.buildProductStructuralFingerprintItem(product, order));
|
|
1964
1973
|
items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
|
|
1965
1974
|
return JSON.stringify(items);
|
|
1966
1975
|
}
|
|
@@ -2027,7 +2036,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2027
2036
|
const manualDepositOverride = this.getManualDepositOverride(tempOrder);
|
|
2028
2037
|
if (currentFingerprint !== snapshot.productFingerprint) {
|
|
2029
2038
|
const currentStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(tempOrder.products);
|
|
2030
|
-
const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(Array.isArray(snapshot.products) ? snapshot.products : []);
|
|
2039
|
+
const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(Array.isArray(snapshot.products) ? snapshot.products : [], snapshot);
|
|
2031
2040
|
if (currentStructuralFingerprint !== snapshotStructuralFingerprint) return null;
|
|
2032
2041
|
}
|
|
2033
2042
|
let summary = {
|
|
@@ -2248,9 +2257,16 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
2248
2257
|
product.metadata = metadata;
|
|
2249
2258
|
return String(uid);
|
|
2250
2259
|
}
|
|
2251
|
-
sanitizeOrderProductForTempOrder(product) {
|
|
2260
|
+
sanitizeOrderProductForTempOrder(product, deferHolderCleanup = false) {
|
|
2252
2261
|
if (product.metadata && typeof product.metadata === 'object') {
|
|
2253
2262
|
delete product.metadata.origin;
|
|
2263
|
+
if (!deferHolderCleanup && !(0, _holderRelations.hasProductBooking)(product)) {
|
|
2264
|
+
delete product.metadata.holder;
|
|
2265
|
+
delete product.metadata.holder_id;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
if (product._extend?.holder_relations !== undefined) {
|
|
2269
|
+
delete product._extend.holder_relations;
|
|
2254
2270
|
}
|
|
2255
2271
|
return product;
|
|
2256
2272
|
}
|
|
@@ -3039,6 +3055,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3039
3055
|
const nextCustomerId = tempOrder.customer_id ?? null;
|
|
3040
3056
|
if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '')) {
|
|
3041
3057
|
this.clearCustomerWalletState(tempOrder);
|
|
3058
|
+
(0, _holderRelations.removeProductHolderRelations)(tempOrder, tempOrder.products.filter(product => !(0, _holderRelations.hasProductBooking)(product)));
|
|
3042
3059
|
}
|
|
3043
3060
|
this.persistTempOrder();
|
|
3044
3061
|
return {
|
|
@@ -3580,10 +3597,13 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3580
3597
|
const hasIncomingProductNote = this.hasOrderProductLineNote(normalizedIncoming);
|
|
3581
3598
|
const hasIncomingManualProductDiscount = isManualProductDiscountProduct(normalizedIncoming);
|
|
3582
3599
|
const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
|
|
3600
|
+
const holderRelationsPatch = !hasIncomingBookingUid ? productToAdd._extend?.holder_relations : undefined;
|
|
3601
|
+
const hasIncomingHolder = Array.isArray(holderRelationsPatch) && holderRelationsPatch.length > 0;
|
|
3583
3602
|
const isIncomingCustomItem = productToAdd.metadata?.origin?.isCustomItem === true || productToAdd._origin?.isCustomItem === true;
|
|
3584
|
-
const shouldForceNewLine = disableMerge || !!booking || hasIncomingGoodPass || isIncomingPersistedEntitlementPass || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
|
|
3603
|
+
const shouldForceNewLine = disableMerge || !!booking || hasIncomingGoodPass || isIncomingPersistedEntitlementPass || hasIncomingBookingUid || hasIncomingHolder || isIncomingCustomItem || isWeighingProduct;
|
|
3585
3604
|
const matchedIndex = shouldForceNewLine ? -1 : tempOrder.products.findIndex(item => {
|
|
3586
3605
|
if (this.hasGoodPassDiscount(item)) return false;
|
|
3606
|
+
if ((0, _holderRelations.getProductHolderRelations)(tempOrder, item).length > 0 || (0, _utils.hasAssignedHolderId)(item.metadata?.holder_id)) return false;
|
|
3587
3607
|
const isRuntimeEntitlementPass = this.isRuntimeEntitlementAppend(item, tempOrder);
|
|
3588
3608
|
if (isIncomingEntitlementAppend !== isRuntimeEntitlementPass) {
|
|
3589
3609
|
return false;
|
|
@@ -3674,6 +3694,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3674
3694
|
if (linked) {
|
|
3675
3695
|
tempOrder.bookings = [...(tempOrder.bookings || []), linked.booking];
|
|
3676
3696
|
}
|
|
3697
|
+
(0, _holderRelations.replaceProductHolderRelations)(tempOrder, committedProduct, holderRelationsPatch);
|
|
3677
3698
|
return committedProduct;
|
|
3678
3699
|
};
|
|
3679
3700
|
if (!matchedProduct) {
|
|
@@ -3779,6 +3800,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3779
3800
|
}));
|
|
3780
3801
|
const mutationSnapshot = salesNoteDrafts.length > 0 ? {
|
|
3781
3802
|
products: (0, _lodashEs.cloneDeep)(tempOrder.products || []),
|
|
3803
|
+
holder_relations: (0, _lodashEs.cloneDeep)(tempOrder.holder_relations),
|
|
3782
3804
|
bookings: (0, _lodashEs.cloneDeep)(tempOrder.bookings || []),
|
|
3783
3805
|
notes: (0, _lodashEs.cloneDeep)(tempOrder.notes || []),
|
|
3784
3806
|
extend: (0, _lodashEs.cloneDeep)(tempOrder._extend || {})
|
|
@@ -3803,6 +3825,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
3803
3825
|
const rollbackProductAndNotesMutation = () => {
|
|
3804
3826
|
if (!mutationSnapshot) return;
|
|
3805
3827
|
tempOrder.products = mutationSnapshot.products;
|
|
3828
|
+
if (mutationSnapshot.holder_relations === undefined) delete tempOrder.holder_relations;else tempOrder.holder_relations = mutationSnapshot.holder_relations;
|
|
3806
3829
|
tempOrder.bookings = mutationSnapshot.bookings;
|
|
3807
3830
|
tempOrder.notes = mutationSnapshot.notes;
|
|
3808
3831
|
tempOrder._extend = mutationSnapshot.extend;
|
|
@@ -4255,6 +4278,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4255
4278
|
if (uid) reapplyWeighedDiscountProductUids?.push(String(uid));
|
|
4256
4279
|
}
|
|
4257
4280
|
tempOrder.products[productIndex] = normalizedProduct;
|
|
4281
|
+
(0, _holderRelations.replaceProductHolderRelations)(tempOrder, normalizedProduct, updates._extend?.holder_relations);
|
|
4258
4282
|
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
4259
4283
|
this.captureProductRuntime(tempOrder, updates, tempOrder.products[productIndex], tempOrder.products[productIndex].metadata?.unique_identification_number);
|
|
4260
4284
|
return tempOrder.products[productIndex].metadata?.unique_identification_number;
|
|
@@ -4536,6 +4560,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4536
4560
|
tempOrder.products = nextProductIndex >= 0 ? [...productsWithoutRemaining.slice(0, nextProductIndex), remainingProduct, ...productsWithoutRemaining.slice(nextProductIndex)] : [...productsWithoutRemaining, remainingProduct];
|
|
4537
4561
|
}
|
|
4538
4562
|
}
|
|
4563
|
+
(0, _holderRelations.removeProductHolderRelations)(tempOrder, productsBeforeRemove.filter(product => !tempOrder.products.includes(product)));
|
|
4539
4564
|
this.removeSalesNotesForMissingProductLines(tempOrder);
|
|
4540
4565
|
if (mutation.commit) tempOrder = await mutation.commit();
|
|
4541
4566
|
await this.finalizeAfterProductsMutation(tempOrder);
|
|
@@ -4559,6 +4584,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4559
4584
|
const mutation = this.beginCartMutation();
|
|
4560
4585
|
let tempOrder = mutation.draft;
|
|
4561
4586
|
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
4587
|
+
(0, _holderRelations.removeProductHolderRelations)(tempOrder, tempOrder.products);
|
|
4562
4588
|
tempOrder.products = [];
|
|
4563
4589
|
tempOrder.bookings = [];
|
|
4564
4590
|
(0, _virtualSettlement.releaseTempOrderSettlementState)(tempOrder);
|
|
@@ -4589,6 +4615,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
4589
4615
|
async clearOrderForSettlementSwitch() {
|
|
4590
4616
|
const tempOrder = this.ensureTempOrder();
|
|
4591
4617
|
this.ensureSalesNotesLoadedForMutation(tempOrder);
|
|
4618
|
+
(0, _holderRelations.removeProductHolderRelations)(tempOrder, tempOrder.products);
|
|
4592
4619
|
tempOrder.products = [];
|
|
4593
4620
|
tempOrder.bookings = [];
|
|
4594
4621
|
this.removeSalesNotesForMissingProductLines(tempOrder);
|
|
@@ -5331,6 +5358,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
5331
5358
|
originalSalesSnapshot: {
|
|
5332
5359
|
summary: (0, _lodashEs.cloneDeep)(this.store.summary),
|
|
5333
5360
|
products: (0, _lodashEs.cloneDeep)(nextTempOrder.products || []),
|
|
5361
|
+
holder_relations: (0, _lodashEs.cloneDeep)(nextTempOrder.holder_relations),
|
|
5334
5362
|
bookings: (0, _lodashEs.cloneDeep)(nextTempOrder.bookings || []),
|
|
5335
5363
|
payments: (0, _lodashEs.cloneDeep)(nextTempOrder.payments || []),
|
|
5336
5364
|
surcharges: (0, _lodashEs.cloneDeep)(nextTempOrder.surcharges || []),
|
|
@@ -5483,6 +5511,9 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
5483
5511
|
nextTempOrder.metadata = raw.metadata && typeof raw.metadata === 'object' ? {
|
|
5484
5512
|
...raw.metadata
|
|
5485
5513
|
} : {};
|
|
5514
|
+
const holderRelations = (0, _holderRelations.restoreLegacyHolderRelations)(raw);
|
|
5515
|
+
if (holderRelations === undefined) delete nextTempOrder.holder_relations;else nextTempOrder.holder_relations = (0, _lodashEs.cloneDeep)(holderRelations);
|
|
5516
|
+
(0, _holderRelations.ensureHolderRelationUuids)(nextTempOrder);
|
|
5486
5517
|
nextTempOrder.holder = raw.holder && typeof raw.holder === 'object' ? {
|
|
5487
5518
|
...raw.holder
|
|
5488
5519
|
} : null;
|
|
@@ -5560,6 +5591,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
5560
5591
|
}
|
|
5561
5592
|
tempOrderExtend.productsByUid = productsByUid;
|
|
5562
5593
|
this.hydrateLinkedBookingIdentity(nextTempOrder);
|
|
5594
|
+
nextTempOrder.products.forEach(product => this.sanitizeOrderProductForTempOrder(product));
|
|
5563
5595
|
if (options?.ensureIdentity !== false) {
|
|
5564
5596
|
this.ensureExternalSaleNumber(nextTempOrder);
|
|
5565
5597
|
}
|
|
@@ -5720,7 +5752,7 @@ class OrderModule extends _BaseModule.BaseModule {
|
|
|
5720
5752
|
};
|
|
5721
5753
|
if (result.metadata) delete result.metadata.price_schema_version;
|
|
5722
5754
|
const restored = (0, _bundleDiscountHydration.restoreHydratedBundleDiscounts)(result, _utils.normalizeOrderProductDiscountList);
|
|
5723
|
-
return this.sanitizeOrderProductForTempOrder(this.normalizeVirtualSettlementProductIfEnabled(restored));
|
|
5755
|
+
return this.sanitizeOrderProductForTempOrder(this.normalizeVirtualSettlementProductIfEnabled(restored), true);
|
|
5724
5756
|
}
|
|
5725
5757
|
getLastOrderInfo() {
|
|
5726
5758
|
return this.store?.lastOrderInfo;
|
|
@@ -242,6 +242,11 @@ export interface OrderProduct extends OrderProductIdentity {
|
|
|
242
242
|
product_cover?: string;
|
|
243
243
|
metadata: Record<string, any>;
|
|
244
244
|
note?: string;
|
|
245
|
+
/** 仅作按行更新输入;正式数据保存于订单顶层。 */
|
|
246
|
+
_extend?: {
|
|
247
|
+
holder_relations?: OrderHolderRelation[];
|
|
248
|
+
[key: string]: any;
|
|
249
|
+
};
|
|
245
250
|
}
|
|
246
251
|
export interface OrderSummary {
|
|
247
252
|
product_quantity: number;
|
|
@@ -339,6 +344,17 @@ export interface SalesNotesMutationSnapshot {
|
|
|
339
344
|
}
|
|
340
345
|
export type SalesNoteProtocolRelation = SalesNoteRelation;
|
|
341
346
|
export type SalesNoteProtocol = SalesNote;
|
|
347
|
+
/** 后端关系及 metadata 均为开放对象,未知字段必须往返保留。 */
|
|
348
|
+
export interface OrderHolderRelation {
|
|
349
|
+
/** 关系自身的 UUID;新选择/旧草稿可缺省,入单与提交时由 OS 补齐。 */
|
|
350
|
+
uuid?: string;
|
|
351
|
+
relation_model: string;
|
|
352
|
+
relation_uuid: string;
|
|
353
|
+
holder_type: 'form' | 'customer';
|
|
354
|
+
holder_id: number;
|
|
355
|
+
metadata?: Record<string, any>;
|
|
356
|
+
[key: string]: any;
|
|
357
|
+
}
|
|
342
358
|
export interface OrderTempOrder {
|
|
343
359
|
order_id: number | null;
|
|
344
360
|
external_sale_number: string;
|
|
@@ -378,6 +394,7 @@ export interface OrderTempOrder {
|
|
|
378
394
|
created_at: string | undefined;
|
|
379
395
|
request_unique_idempotency_token?: string;
|
|
380
396
|
products: OrderProduct[];
|
|
397
|
+
holder_relations?: OrderHolderRelation[];
|
|
381
398
|
notes: SalesNote[];
|
|
382
399
|
bookings: any[];
|
|
383
400
|
payments: any[];
|
|
@@ -397,7 +414,7 @@ export interface OrderTempOrder {
|
|
|
397
414
|
[key: string]: any;
|
|
398
415
|
};
|
|
399
416
|
}
|
|
400
|
-
export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identification_number' | 'num'> {
|
|
417
|
+
export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identification_number' | 'num' | '_extend'> {
|
|
401
418
|
product_quantity: number;
|
|
402
419
|
payment_price: string;
|
|
403
420
|
product_sku: OrderProductSku;
|
|
@@ -598,6 +615,7 @@ export interface SubmitSalesOrderParams {
|
|
|
598
615
|
schedule_date: string;
|
|
599
616
|
created_at?: string | undefined;
|
|
600
617
|
products: OrderSubmitProduct[];
|
|
618
|
+
holder_relations?: OrderHolderRelation[];
|
|
601
619
|
bookings: OrderSubmitBooking[];
|
|
602
620
|
payments: any[];
|
|
603
621
|
vouchers: any[];
|
|
@@ -63,6 +63,7 @@ let OrderHooks = exports.OrderHooks = /*#__PURE__*/function (OrderHooks) {
|
|
|
63
63
|
* Sales Notes 乐观写入前的可恢复快照。
|
|
64
64
|
* 该对象应视为 opaque token,只用于原样传回 restoreSalesNotesMutationSnapshot。
|
|
65
65
|
*/
|
|
66
|
+
/** 后端关系及 metadata 均为开放对象,未知字段必须往返保留。 */
|
|
66
67
|
/**
|
|
67
68
|
* 添加商品行时的顺序控制。
|
|
68
69
|
* 默认追加到 products 尾部;预约数量同步可插入到既有预约组的最新行之后,
|
|
@@ -31,7 +31,7 @@ export declare const DISCOUNT_SPLIT_ORIGIN_UID_KEY = "discountSplitOriginUid";
|
|
|
31
31
|
* 没有 UID 的裸商品不会被补写 UID。这是为了兼容 Rules/mock 的历史协议形状;
|
|
32
32
|
* 正常 Order 写路径会在 normalize 阶段提前创建 UID。
|
|
33
33
|
*/
|
|
34
|
-
export declare function ensureUniqueProductLineUids(tempOrder: OrderTempOrder): void;
|
|
34
|
+
export declare function ensureUniqueProductLineUids(tempOrder: OrderTempOrder, discounts?: Array<Record<string, any>>): void;
|
|
35
35
|
/**
|
|
36
36
|
* 把券移除后已经恢复原价的同源折扣拆分行重新合并。
|
|
37
37
|
*
|
|
@@ -9,6 +9,7 @@ exports.ensureUniqueProductLineUids = ensureUniqueProductLineUids;
|
|
|
9
9
|
var _lodashEs = require("lodash-es");
|
|
10
10
|
var _utils = require("../../../solution/ScanOrder/utils");
|
|
11
11
|
var _orderCollectionIdentity = require("./orderCollectionIdentity");
|
|
12
|
+
var _holderRelations = require("../holderRelations");
|
|
12
13
|
/**
|
|
13
14
|
* 商品券拆行的身份与回并工具。
|
|
14
15
|
*
|
|
@@ -72,16 +73,20 @@ function ensureProductsByUid(tempOrder) {
|
|
|
72
73
|
* 没有 UID 的裸商品不会被补写 UID。这是为了兼容 Rules/mock 的历史协议形状;
|
|
73
74
|
* 正常 Order 写路径会在 normalize 阶段提前创建 UID。
|
|
74
75
|
*/
|
|
75
|
-
function ensureUniqueProductLineUids(tempOrder) {
|
|
76
|
+
function ensureUniqueProductLineUids(tempOrder, discounts = []) {
|
|
76
77
|
// usedUids 只描述本次 Rules 返回的商品集合,不能直接依赖 productsByUid:
|
|
77
78
|
// productsByUid 可能还保留已删除行的历史 runtime,历史 UID 不应导致当前行被改号。
|
|
78
79
|
const usedUids = new Set();
|
|
79
80
|
const productsByUid = ensureProductsByUid(tempOrder);
|
|
81
|
+
const splitGroups = new Map();
|
|
80
82
|
tempOrder.products = (tempOrder.products || []).map(product => {
|
|
81
83
|
const sourceUid = getProductLineUid(product);
|
|
82
84
|
// 单测 mock 或兼容旧 Rules 时可能返回没有 UID 的裸商品。
|
|
83
85
|
// 这里不主动补 UID,避免一个“校验重复”的工具意外改变旧协议对象形状。
|
|
84
86
|
if (!sourceUid) return product;
|
|
87
|
+
const group = splitGroups.get(sourceUid) || [];
|
|
88
|
+
group.push(product);
|
|
89
|
+
splitGroups.set(sourceUid, group);
|
|
85
90
|
|
|
86
91
|
// 实际场景:可乐 ×5 首次进入 Rules 时只有一行。
|
|
87
92
|
// 使用三张券后 Rules 可能返回「可乐 ×2 + 三条可乐 ×1」,但四条都复制原 UID。
|
|
@@ -122,6 +127,50 @@ function ensureUniqueProductLineUids(tempOrder) {
|
|
|
122
127
|
usedUids.add(splitUid);
|
|
123
128
|
return product;
|
|
124
129
|
});
|
|
130
|
+
|
|
131
|
+
// 仅按本次券上的明确 Holder 分配迁移。数组顺序不能代表券对应的人。
|
|
132
|
+
// 未能明确分配时保留原 UID,不把整组关系复制给每一个拆分行。
|
|
133
|
+
for (const [sourceUid, products] of splitGroups) {
|
|
134
|
+
if (products.length < 2) continue;
|
|
135
|
+
const relations = (0, _holderRelations.getProductHolderRelations)(tempOrder, {
|
|
136
|
+
metadata: {
|
|
137
|
+
unique_identification_number: sourceUid
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
if (!relations.length || relations.some(relation => relation.holder_type !== 'form')) continue;
|
|
141
|
+
const assignments = new Map();
|
|
142
|
+
let remaining = [...relations];
|
|
143
|
+
let ambiguous = false;
|
|
144
|
+
for (const product of products) {
|
|
145
|
+
const holderIds = new Set();
|
|
146
|
+
for (const item of product.discount_list || []) {
|
|
147
|
+
const discount = discounts.find(candidate => String(candidate.id) === String(item.discount?.resource_id));
|
|
148
|
+
if (discount?.holder?.holder_type !== 'form') continue;
|
|
149
|
+
const value = discount.holder.holder_id;
|
|
150
|
+
(Array.isArray(value) ? value : [value]).forEach(id => {
|
|
151
|
+
const recordId = id && typeof id === 'object' ? id.form_record_id : id;
|
|
152
|
+
if (recordId !== undefined && recordId !== null && recordId !== '') holderIds.add(String(recordId));
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (!holderIds.size) continue;
|
|
156
|
+
const assigned = remaining.filter(relation => holderIds.has(String(relation.holder_id)));
|
|
157
|
+
if (assigned.length !== Number(product.num)) {
|
|
158
|
+
ambiguous = true;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
assignments.set(product, assigned);
|
|
162
|
+
remaining = remaining.filter(relation => !assigned.includes(relation));
|
|
163
|
+
}
|
|
164
|
+
const unassigned = products.filter(product => !assignments.has(product));
|
|
165
|
+
if (ambiguous || unassigned.length > 1) continue;
|
|
166
|
+
if (unassigned.length === 1) {
|
|
167
|
+
if (remaining.length !== Number(unassigned[0].num)) continue;
|
|
168
|
+
assignments.set(unassigned[0], remaining);
|
|
169
|
+
} else if (remaining.length) continue;
|
|
170
|
+
for (const [product, assigned] of assignments) {
|
|
171
|
+
for (const relation of assigned) relation.relation_uuid = String(getProductLineUid(product));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
125
174
|
}
|
|
126
175
|
|
|
127
176
|
/**
|
|
@@ -154,7 +203,7 @@ function consolidateDiscountFreeProductLines(tempOrder) {
|
|
|
154
203
|
// - 手动改价/备注:用户显式表达了不同价格或不同制作要求;
|
|
155
204
|
// - 称重商品:每次称重的净重和金额属于独立交易事实;
|
|
156
205
|
// - 预约/holder/历史订单行:分别关联预约、持有人或后端 order_detail。
|
|
157
|
-
const hasMergeBoundary = hasDiscount || Boolean(product.metadata?._giftInfo || product._giftInfo) || Boolean(product.metadata?._promotion) || isManualProductDiscountLine(product) || hasProductLineNote(product) || Number(product.product_sku?.open_sold_weight || 0) === 1 || product.metadata?.is_edit_for_runtime === true || bookingId !== undefined && bookingId !== null && bookingId !== 0 && bookingId !== '0' || bookingUid !== undefined && bookingUid !== null && String(bookingUid) !== '' || holderId !== undefined && holderId !== null && String(holderId) !== '' || orderDetailId !== undefined && orderDetailId !== null && orderDetailId !== '';
|
|
206
|
+
const hasMergeBoundary = hasDiscount || Boolean(product.metadata?._giftInfo || product._giftInfo) || Boolean(product.metadata?._promotion) || isManualProductDiscountLine(product) || hasProductLineNote(product) || Number(product.product_sku?.open_sold_weight || 0) === 1 || product.metadata?.is_edit_for_runtime === true || bookingId !== undefined && bookingId !== null && bookingId !== 0 && bookingId !== '0' || bookingUid !== undefined && bookingUid !== null && String(bookingUid) !== '' || (0, _holderRelations.getProductHolderRelations)(tempOrder, product).length > 0 || holderId !== undefined && holderId !== null && String(holderId) !== '' || orderDetailId !== undefined && orderDetailId !== null && orderDetailId !== '';
|
|
158
207
|
if (hasMergeBoundary) {
|
|
159
208
|
consolidatedProducts.push(product);
|
|
160
209
|
continue;
|