@pisell/pisellos 2.2.302 → 2.2.303
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/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/itemRule/adapter.d.ts +4 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
- package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/dist/model/strategy/adapter/itemRule/type.js +19 -1
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
- package/dist/modules/Discount/index.d.ts +2 -0
- package/dist/modules/Discount/index.js +41 -5
- package/dist/modules/Discount/types.d.ts +21 -0
- package/dist/modules/OpenData/index.d.ts +15 -2
- package/dist/modules/OpenData/index.js +307 -19
- package/dist/modules/OpenData/types.d.ts +55 -0
- package/dist/modules/OpenData/types.js +7 -1
- package/dist/modules/OpenData/utils.d.ts +21 -1
- package/dist/modules/OpenData/utils.js +138 -0
- package/dist/modules/Order/index.d.ts +50 -7
- package/dist/modules/Order/index.js +1690 -815
- package/dist/modules/Order/salesNotes.d.ts +31 -0
- package/dist/modules/Order/salesNotes.js +492 -0
- package/dist/modules/Order/types.d.ts +117 -10
- package/dist/modules/Order/types.js +6 -1
- package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
- package/dist/modules/Order/utils/virtualSettlement.js +284 -0
- package/dist/modules/Order/utils.d.ts +5 -1
- package/dist/modules/Order/utils.js +138 -33
- package/dist/modules/Payment/walletpass.js +20 -21
- package/dist/modules/Product/types.d.ts +23 -0
- package/dist/modules/ProductList/index.d.ts +2 -1
- package/dist/modules/ProductList/index.js +100 -20
- package/dist/modules/ProductList/types.d.ts +10 -0
- package/dist/modules/Rules/index.d.ts +5 -0
- package/dist/modules/Rules/index.js +30 -14
- 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 +21 -1
- package/dist/plugins/request.d.ts +2 -1
- package/dist/plugins/request.js +4 -2
- package/dist/server/index.d.ts +21 -0
- package/dist/server/index.js +1774 -1285
- package/dist/server/modules/order/types.d.ts +50 -0
- package/dist/server/modules/order/types.js +2 -0
- package/dist/server/utils/small-ticket.d.ts +4 -1
- package/dist/server/utils/small-ticket.js +461 -96
- package/dist/solution/BaseSales/index.d.ts +24 -3
- package/dist/solution/BaseSales/index.js +1484 -873
- package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +22 -5
- package/dist/solution/BookingTicket/index.js +558 -443
- package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
- package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
- package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
- package/dist/solution/RegisterAndLogin/config.js +95 -40
- package/dist/solution/RegisterAndLogin/index.js +4 -1
- package/dist/solution/Sales/index.d.ts +16 -1
- package/dist/solution/Sales/index.js +338 -63
- package/dist/solution/Sales/types.d.ts +10 -0
- package/dist/solution/ScanOrder/index.d.ts +1 -0
- package/dist/solution/ScanOrder/index.js +31 -27
- package/dist/solution/ScanOrder/utils.d.ts +1 -0
- package/dist/solution/ScanOrder/utils.js +2 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +20 -6
- package/dist/solution/UnifiedBookingSales/index.js +874 -527
- package/dist/solution/UnifiedBookingSales/types.d.ts +21 -2
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +8 -4
- package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
- package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
- package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/lib/model/strategy/adapter/itemRule/type.js +19 -1
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
- package/lib/modules/Discount/index.d.ts +2 -0
- package/lib/modules/Discount/index.js +34 -2
- package/lib/modules/Discount/types.d.ts +21 -0
- package/lib/modules/OpenData/index.d.ts +15 -2
- package/lib/modules/OpenData/index.js +230 -3
- package/lib/modules/OpenData/types.d.ts +55 -0
- package/lib/modules/OpenData/types.js +9 -1
- package/lib/modules/OpenData/utils.d.ts +21 -1
- package/lib/modules/OpenData/utils.js +126 -0
- package/lib/modules/Order/index.d.ts +50 -7
- package/lib/modules/Order/index.js +704 -64
- package/lib/modules/Order/salesNotes.d.ts +31 -0
- package/lib/modules/Order/salesNotes.js +382 -0
- package/lib/modules/Order/types.d.ts +117 -10
- package/lib/modules/Order/types.js +5 -1
- package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
- package/lib/modules/Order/utils/virtualSettlement.js +262 -0
- package/lib/modules/Order/utils.d.ts +5 -1
- package/lib/modules/Order/utils.js +127 -21
- package/lib/modules/Payment/walletpass.js +14 -11
- package/lib/modules/Product/types.d.ts +23 -0
- package/lib/modules/ProductList/index.d.ts +2 -1
- package/lib/modules/ProductList/index.js +47 -2
- package/lib/modules/ProductList/types.d.ts +10 -0
- package/lib/modules/Rules/index.d.ts +5 -0
- package/lib/modules/Rules/index.js +22 -12
- package/lib/modules/SalesSummary/index.d.ts +1 -0
- package/lib/modules/SalesSummary/index.js +4 -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 +17 -1
- package/lib/plugins/request.d.ts +2 -1
- package/lib/plugins/request.js +3 -2
- package/lib/server/index.d.ts +21 -0
- package/lib/server/index.js +492 -108
- package/lib/server/modules/order/types.d.ts +50 -0
- package/lib/server/modules/order/types.js +1 -0
- package/lib/server/utils/small-ticket.d.ts +4 -1
- package/lib/server/utils/small-ticket.js +427 -72
- package/lib/solution/BaseSales/index.d.ts +24 -3
- package/lib/solution/BaseSales/index.js +433 -30
- package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +22 -5
- package/lib/solution/BookingTicket/index.js +60 -15
- package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
- package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
- package/lib/solution/RegisterAndLogin/config.js +49 -8
- package/lib/solution/RegisterAndLogin/index.js +4 -1
- package/lib/solution/Sales/index.d.ts +16 -1
- package/lib/solution/Sales/index.js +168 -1
- package/lib/solution/Sales/types.d.ts +10 -0
- package/lib/solution/ScanOrder/index.d.ts +1 -0
- package/lib/solution/ScanOrder/index.js +5 -1
- package/lib/solution/ScanOrder/utils.d.ts +1 -0
- package/lib/solution/ScanOrder/utils.js +1 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +20 -6
- package/lib/solution/UnifiedBookingSales/index.js +169 -16
- package/lib/solution/UnifiedBookingSales/types.d.ts +21 -2
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +5 -1
- package/package.json +1 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { SalesNote, SalesNoteProtocol, SalesNoteTextInput } from './types';
|
|
2
|
+
export interface SalesNotePolicy {
|
|
3
|
+
note_type: string;
|
|
4
|
+
importance: string;
|
|
5
|
+
uniquePerPrimaryTarget: boolean;
|
|
6
|
+
primary_relation_type: 'about';
|
|
7
|
+
secondary_order_relation_type: 'related_to';
|
|
8
|
+
}
|
|
9
|
+
export declare function getSalesNotePolicy(note_type: string): SalesNotePolicy | null;
|
|
10
|
+
export declare function buildSalesNoteText(input: SalesNoteTextInput): Record<string, string>;
|
|
11
|
+
export interface SalesNoteValidationOptions {
|
|
12
|
+
allowUnresolvedOrderTarget?: boolean;
|
|
13
|
+
expectedOrderTargetUuid?: string;
|
|
14
|
+
productTargetUuids?: ReadonlySet<string>;
|
|
15
|
+
}
|
|
16
|
+
export type EncodeSalesNotesOptions = SalesNoteValidationOptions;
|
|
17
|
+
export declare function encodeSalesNotes(notes: SalesNote[], options?: EncodeSalesNotesOptions): SalesNoteProtocol[];
|
|
18
|
+
export interface DecodedSalesNotesSnapshot {
|
|
19
|
+
notes: SalesNote[];
|
|
20
|
+
complete: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface DecodeSalesNotesOptions {
|
|
23
|
+
allowUnresolvedOrderTarget?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function decodeSalesNotesSnapshot(value: unknown, options?: DecodeSalesNotesOptions): DecodedSalesNotesSnapshot;
|
|
26
|
+
export declare function decodeSalesNotes(value: unknown, options?: DecodeSalesNotesOptions): SalesNote[];
|
|
27
|
+
export declare function finalizeSalesNotesForCheckout(params: {
|
|
28
|
+
notes: unknown;
|
|
29
|
+
shopOrderNumber: unknown;
|
|
30
|
+
productTargetUuids: string[];
|
|
31
|
+
}): SalesNoteProtocol[];
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.buildSalesNoteText = buildSalesNoteText;
|
|
7
|
+
exports.decodeSalesNotes = decodeSalesNotes;
|
|
8
|
+
exports.decodeSalesNotesSnapshot = decodeSalesNotesSnapshot;
|
|
9
|
+
exports.encodeSalesNotes = encodeSalesNotes;
|
|
10
|
+
exports.finalizeSalesNotesForCheckout = finalizeSalesNotesForCheckout;
|
|
11
|
+
exports.getSalesNotePolicy = getSalesNotePolicy;
|
|
12
|
+
const MAX_UUID_LENGTH = 255;
|
|
13
|
+
const LOCALIZED_NOTE_LOCALES = ['en', 'zh-CN', 'zh-HK', 'ja', 'pt'];
|
|
14
|
+
const UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
15
|
+
/**
|
|
16
|
+
* 备注业务规则统一注册在 OS;调用方只传 note_type、目标行和原始文本。
|
|
17
|
+
* 后续新增备注类型时在这里增加 policy,不把 importance / Relation 规则下放给 UI。
|
|
18
|
+
*/
|
|
19
|
+
const SALES_NOTE_POLICIES = {
|
|
20
|
+
allergy: {
|
|
21
|
+
note_type: 'allergy',
|
|
22
|
+
importance: 'high',
|
|
23
|
+
uniquePerPrimaryTarget: true,
|
|
24
|
+
primary_relation_type: 'about',
|
|
25
|
+
secondary_order_relation_type: 'related_to'
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
function getSalesNotePolicy(note_type) {
|
|
29
|
+
return SALES_NOTE_POLICIES[note_type] || null;
|
|
30
|
+
}
|
|
31
|
+
function normalizeUuid(value, field, options) {
|
|
32
|
+
const uuid = String(value ?? '').trim();
|
|
33
|
+
if (!uuid && !options?.allowEmpty) {
|
|
34
|
+
throw new Error(`[Order Notes] ${field} 不能为空`);
|
|
35
|
+
}
|
|
36
|
+
if (uuid.length > MAX_UUID_LENGTH) {
|
|
37
|
+
throw new Error(`[Order Notes] ${field} 不能超过 ${MAX_UUID_LENGTH} 个字符`);
|
|
38
|
+
}
|
|
39
|
+
return uuid;
|
|
40
|
+
}
|
|
41
|
+
function normalizeEntityUuid(value, field) {
|
|
42
|
+
const uuid = normalizeUuid(value, field);
|
|
43
|
+
if (!UUID_V4_PATTERN.test(uuid)) {
|
|
44
|
+
throw new Error(`[Order Notes] ${field} 必须为 UUID v4`);
|
|
45
|
+
}
|
|
46
|
+
return uuid;
|
|
47
|
+
}
|
|
48
|
+
function normalizeTextRecord(value) {
|
|
49
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return {};
|
|
50
|
+
return Object.entries(value).reduce((result, [locale, text]) => {
|
|
51
|
+
if (typeof text === 'string') result[locale] = text;
|
|
52
|
+
return result;
|
|
53
|
+
}, {});
|
|
54
|
+
}
|
|
55
|
+
function normalizeLocalizedLabel(label) {
|
|
56
|
+
if (typeof label === 'string') {
|
|
57
|
+
const text = label.trim();
|
|
58
|
+
return text ? {
|
|
59
|
+
default: text
|
|
60
|
+
} : {};
|
|
61
|
+
}
|
|
62
|
+
return Object.entries(label || {}).reduce((result, [locale, value]) => {
|
|
63
|
+
const text = String(value ?? '').trim();
|
|
64
|
+
if (text) result[locale] = text;
|
|
65
|
+
return result;
|
|
66
|
+
}, {});
|
|
67
|
+
}
|
|
68
|
+
function getLocaleCandidates(locale) {
|
|
69
|
+
const raw = String(locale || '').trim();
|
|
70
|
+
const normalized = raw.replace(/_/g, '-');
|
|
71
|
+
const base = normalized.split('-')[0];
|
|
72
|
+
return Array.from(new Set([raw, normalized, base].filter(Boolean)));
|
|
73
|
+
}
|
|
74
|
+
function normalizeLocaleLookupKey(locale) {
|
|
75
|
+
return String(locale || '').trim().replace(/_/g, '-').toLowerCase();
|
|
76
|
+
}
|
|
77
|
+
function resolveLocalizedLabel(label, locale) {
|
|
78
|
+
if (typeof label === 'string') return label.trim();
|
|
79
|
+
const normalized = normalizeLocalizedLabel(label);
|
|
80
|
+
const entries = Object.entries(normalized);
|
|
81
|
+
const lowerCaseLookup = new Map(entries.map(([key, value]) => [normalizeLocaleLookupKey(key), value]));
|
|
82
|
+
for (const candidate of getLocaleCandidates(locale)) {
|
|
83
|
+
const matched = lowerCaseLookup.get(normalizeLocaleLookupKey(candidate));
|
|
84
|
+
if (matched) return matched;
|
|
85
|
+
}
|
|
86
|
+
const localeBase = normalizeLocaleLookupKey(locale).split('-')[0];
|
|
87
|
+
const sameLanguage = entries.find(([key]) => normalizeLocaleLookupKey(key).split('-')[0] === localeBase)?.[1];
|
|
88
|
+
return sameLanguage || lowerCaseLookup.get('en') || lowerCaseLookup.get('zh-cn') || lowerCaseLookup.get('default') || entries[0]?.[1] || '';
|
|
89
|
+
}
|
|
90
|
+
function joinNoteParts(parts) {
|
|
91
|
+
return parts.map(part => String(part ?? '')).filter(part => part.trim().length > 0).join(',');
|
|
92
|
+
}
|
|
93
|
+
function buildSalesNoteText(input) {
|
|
94
|
+
if (input.kind === 'plain') {
|
|
95
|
+
const text = String(input.input ?? '');
|
|
96
|
+
if (!text.trim()) throw new Error('[Order Notes] 备注输入不能为空');
|
|
97
|
+
return {
|
|
98
|
+
'zh-CN': '',
|
|
99
|
+
original: text
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (input.kind === 'resolved') {
|
|
103
|
+
const text = normalizeTextRecord(input.text);
|
|
104
|
+
if (!Object.values(text).some(value => value.trim())) {
|
|
105
|
+
throw new Error('[Order Notes] 备注文本不能为空');
|
|
106
|
+
}
|
|
107
|
+
return text;
|
|
108
|
+
}
|
|
109
|
+
const inputText = String(input.input ?? '');
|
|
110
|
+
const seenIds = new Set();
|
|
111
|
+
const selections = (input.selections || []).filter(selection => {
|
|
112
|
+
const id = String(selection?.id ?? '').trim();
|
|
113
|
+
if (!id || seenIds.has(id)) return false;
|
|
114
|
+
seenIds.add(id);
|
|
115
|
+
return true;
|
|
116
|
+
});
|
|
117
|
+
if (!selections.length && !inputText.trim()) {
|
|
118
|
+
throw new Error('[Order Notes] 过敏选项和补充说明不能同时为空');
|
|
119
|
+
}
|
|
120
|
+
const result = {};
|
|
121
|
+
for (const locale of LOCALIZED_NOTE_LOCALES) {
|
|
122
|
+
result[locale] = joinNoteParts([...selections.map(selection => resolveLocalizedLabel(selection.label, locale)), inputText]);
|
|
123
|
+
}
|
|
124
|
+
result.original = joinNoteParts([...selections.map(selection => resolveLocalizedLabel(selection.label, input.locale)), inputText]);
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
function validateSalesNote(note, options = {}) {
|
|
128
|
+
normalizeEntityUuid(note.uuid, 'Note uuid');
|
|
129
|
+
const note_type = String(note.note_type || '').trim();
|
|
130
|
+
const policy = getSalesNotePolicy(note_type);
|
|
131
|
+
if (!policy) {
|
|
132
|
+
throw new Error(`[Order Notes] 当前未注册备注类型: ${note_type || '(empty)'}`);
|
|
133
|
+
}
|
|
134
|
+
if (note.importance !== policy.importance) {
|
|
135
|
+
throw new Error(`[Order Notes] ${note_type} importance 必须为 ${policy.importance}`);
|
|
136
|
+
}
|
|
137
|
+
const text = note.content?.text;
|
|
138
|
+
if (!text || typeof text !== 'object' || Array.isArray(text) || Object.values(text).some(value => typeof value !== 'string') || !Object.values(text).some(value => value.trim())) {
|
|
139
|
+
throw new Error('[Order Notes] content.text 不能为空');
|
|
140
|
+
}
|
|
141
|
+
if (!Array.isArray(note.note_relations) || note.note_relations.length === 0) {
|
|
142
|
+
throw new Error('[Order Notes] note_relations 不能为空');
|
|
143
|
+
}
|
|
144
|
+
const relationUuids = new Set();
|
|
145
|
+
let primaryCount = 0;
|
|
146
|
+
let orderRelationCount = 0;
|
|
147
|
+
for (const relation of note.note_relations) {
|
|
148
|
+
const relationUuid = normalizeEntityUuid(relation.uuid, 'Relation uuid');
|
|
149
|
+
if (relationUuids.has(relationUuid)) {
|
|
150
|
+
throw new Error('[Order Notes] 同一 Note 内 Relation uuid 不能重复');
|
|
151
|
+
}
|
|
152
|
+
relationUuids.add(relationUuid);
|
|
153
|
+
if (relation.is_primary !== 0 && relation.is_primary !== 1) {
|
|
154
|
+
throw new Error('[Order Notes] is_primary 只允许整数 0 或 1');
|
|
155
|
+
}
|
|
156
|
+
if (relation.relation_type !== 'about' && relation.relation_type !== 'related_to') {
|
|
157
|
+
throw new Error('[Order Notes] relation_type 不合法');
|
|
158
|
+
}
|
|
159
|
+
if (relation.target_type !== 'order' && relation.target_type !== 'order_detail') {
|
|
160
|
+
throw new Error('[Order Notes] target_type 不合法');
|
|
161
|
+
}
|
|
162
|
+
if (relation.is_primary === 1) {
|
|
163
|
+
primaryCount += 1;
|
|
164
|
+
if (relation.relation_type !== policy.primary_relation_type || relation.target_type !== 'order_detail') {
|
|
165
|
+
throw new Error('[Order Notes] 主关系必须使用 about + order_detail');
|
|
166
|
+
}
|
|
167
|
+
const targetUuid = normalizeUuid(relation.target_uuid, 'Relation target_uuid');
|
|
168
|
+
if (options.productTargetUuids && !options.productTargetUuids.has(targetUuid)) {
|
|
169
|
+
throw new Error('[Order Notes] 商品 Relation target_uuid 不属于当前订单');
|
|
170
|
+
}
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (relation.target_type === 'order' && relation.relation_type === policy.secondary_order_relation_type) {
|
|
174
|
+
orderRelationCount += 1;
|
|
175
|
+
const targetUuid = normalizeUuid(relation.target_uuid, 'Relation target_uuid', {
|
|
176
|
+
allowEmpty: options.allowUnresolvedOrderTarget === true
|
|
177
|
+
});
|
|
178
|
+
if (options.expectedOrderTargetUuid !== undefined && targetUuid !== options.expectedOrderTargetUuid) {
|
|
179
|
+
throw new Error('[Order Notes] 订单 Relation target_uuid 与 shop_order_number 不一致');
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
throw new Error('[Order Notes] 非主体关系必须使用 related_to + order');
|
|
184
|
+
}
|
|
185
|
+
if (primaryCount !== 1) {
|
|
186
|
+
throw new Error('[Order Notes] 每条 Note 必须且只能有一个主关系');
|
|
187
|
+
}
|
|
188
|
+
if (orderRelationCount !== 1) {
|
|
189
|
+
throw new Error('[Order Notes] 每条商品 Note 必须且只能有一个订单冗余关系');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function encodeSalesNotes(notes, options = {}) {
|
|
193
|
+
const entityUuids = new Set();
|
|
194
|
+
const uniquePolicyTargets = new Set();
|
|
195
|
+
return (notes || []).map(note => {
|
|
196
|
+
validateSalesNote(note, options);
|
|
197
|
+
const noteUuid = normalizeEntityUuid(note.uuid, 'Note uuid');
|
|
198
|
+
if (entityUuids.has(noteUuid)) {
|
|
199
|
+
throw new Error('[Order Notes] Note/Relation uuid 不能重复');
|
|
200
|
+
}
|
|
201
|
+
entityUuids.add(noteUuid);
|
|
202
|
+
const note_type = String(note.note_type).trim();
|
|
203
|
+
const noteRelations = note.note_relations.map(relation => {
|
|
204
|
+
const relationUuid = normalizeEntityUuid(relation.uuid, 'Relation uuid');
|
|
205
|
+
if (entityUuids.has(relationUuid)) {
|
|
206
|
+
throw new Error('[Order Notes] Note/Relation uuid 不能重复');
|
|
207
|
+
}
|
|
208
|
+
entityUuids.add(relationUuid);
|
|
209
|
+
const allowEmptyTarget = options.allowUnresolvedOrderTarget === true && relation.is_primary === 0 && relation.relation_type === 'related_to' && relation.target_type === 'order';
|
|
210
|
+
return {
|
|
211
|
+
uuid: relationUuid,
|
|
212
|
+
relation_type: relation.relation_type,
|
|
213
|
+
target_type: relation.target_type,
|
|
214
|
+
target_uuid: normalizeUuid(relation.target_uuid, 'Relation target_uuid', {
|
|
215
|
+
allowEmpty: allowEmptyTarget
|
|
216
|
+
}),
|
|
217
|
+
is_primary: relation.is_primary
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
const primaryRelation = noteRelations.find(relation => relation.is_primary === 1);
|
|
221
|
+
const policy = getSalesNotePolicy(note_type);
|
|
222
|
+
if (policy.uniquePerPrimaryTarget) {
|
|
223
|
+
const policyTargetKey = [note_type, primaryRelation.target_type, primaryRelation.target_uuid].join(':');
|
|
224
|
+
if (uniquePolicyTargets.has(policyTargetKey)) {
|
|
225
|
+
throw new Error('[Order Notes] 同一商品行不能重复提交同类型 Note');
|
|
226
|
+
}
|
|
227
|
+
uniquePolicyTargets.add(policyTargetKey);
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
uuid: noteUuid,
|
|
231
|
+
note_type,
|
|
232
|
+
content: {
|
|
233
|
+
text: {
|
|
234
|
+
...(note.content?.text || {})
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
importance: note.importance,
|
|
238
|
+
note_relations: noteRelations
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function decodeRelation(value) {
|
|
243
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
244
|
+
const raw = value;
|
|
245
|
+
const uuid = String(raw.uuid ?? '').trim();
|
|
246
|
+
const target_uuid = String(raw.target_uuid ?? '').trim();
|
|
247
|
+
const relation_type = raw.relation_type;
|
|
248
|
+
const target_type = raw.target_type;
|
|
249
|
+
const is_primary = raw.is_primary;
|
|
250
|
+
if (!uuid || relation_type !== 'about' && relation_type !== 'related_to' || target_type !== 'order' && target_type !== 'order_detail' || is_primary !== 0 && is_primary !== 1) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
uuid,
|
|
255
|
+
relation_type,
|
|
256
|
+
target_type,
|
|
257
|
+
target_uuid,
|
|
258
|
+
is_primary
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function decodeSalesNotesSnapshot(value, options = {}) {
|
|
262
|
+
if (!Array.isArray(value)) return {
|
|
263
|
+
notes: [],
|
|
264
|
+
complete: false
|
|
265
|
+
};
|
|
266
|
+
const notes = [];
|
|
267
|
+
const entityUuids = new Set();
|
|
268
|
+
const uniquePolicyTargets = new Set();
|
|
269
|
+
let complete = true;
|
|
270
|
+
for (const item of value) {
|
|
271
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
272
|
+
complete = false;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const raw = item;
|
|
276
|
+
const uuid = String(raw.uuid ?? '').trim();
|
|
277
|
+
const note_type = String(raw.note_type ?? '').trim();
|
|
278
|
+
const importance = String(raw.importance ?? '').trim();
|
|
279
|
+
const rawText = raw.content?.text;
|
|
280
|
+
const text = normalizeTextRecord(rawText);
|
|
281
|
+
if (!rawText || typeof rawText !== 'object' || Array.isArray(rawText) || Object.keys(text).length !== Object.keys(rawText).length) {
|
|
282
|
+
complete = false;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
const rawNoteRelations = Array.isArray(raw.note_relations) ? raw.note_relations : null;
|
|
286
|
+
const noteRelations = rawNoteRelations ? rawNoteRelations.map(relation => decodeRelation(relation)).filter(relation => relation !== null) : [];
|
|
287
|
+
if (!rawNoteRelations || noteRelations.length !== rawNoteRelations.length) {
|
|
288
|
+
complete = false;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const note = {
|
|
292
|
+
uuid,
|
|
293
|
+
note_type,
|
|
294
|
+
content: {
|
|
295
|
+
text
|
|
296
|
+
},
|
|
297
|
+
importance,
|
|
298
|
+
note_relations: noteRelations
|
|
299
|
+
};
|
|
300
|
+
try {
|
|
301
|
+
validateSalesNote(note, {
|
|
302
|
+
allowUnresolvedOrderTarget: options.allowUnresolvedOrderTarget
|
|
303
|
+
});
|
|
304
|
+
if (entityUuids.has(note.uuid)) {
|
|
305
|
+
complete = false;
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
entityUuids.add(note.uuid);
|
|
309
|
+
let hasDuplicateRelationUuid = false;
|
|
310
|
+
for (const relation of note.note_relations) {
|
|
311
|
+
if (entityUuids.has(relation.uuid)) {
|
|
312
|
+
hasDuplicateRelationUuid = true;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (hasDuplicateRelationUuid) {
|
|
317
|
+
complete = false;
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
note.note_relations.forEach(relation => entityUuids.add(relation.uuid));
|
|
321
|
+
const policy = getSalesNotePolicy(note.note_type);
|
|
322
|
+
const primaryRelation = note.note_relations.find(relation => relation.is_primary === 1);
|
|
323
|
+
if (policy?.uniquePerPrimaryTarget && primaryRelation) {
|
|
324
|
+
const policyTargetKey = [note.note_type, primaryRelation.target_type, primaryRelation.target_uuid].join(':');
|
|
325
|
+
if (uniquePolicyTargets.has(policyTargetKey)) {
|
|
326
|
+
complete = false;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
uniquePolicyTargets.add(policyTargetKey);
|
|
330
|
+
}
|
|
331
|
+
notes.push(note);
|
|
332
|
+
} catch {
|
|
333
|
+
complete = false;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
notes,
|
|
338
|
+
complete
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function decodeSalesNotes(value, options = {}) {
|
|
342
|
+
return decodeSalesNotesSnapshot(value, options).notes;
|
|
343
|
+
}
|
|
344
|
+
function finalizeSalesNotesForCheckout(params) {
|
|
345
|
+
if (!Array.isArray(params.notes)) {
|
|
346
|
+
throw new Error('[Order Notes] checkout notes 必须为数组');
|
|
347
|
+
}
|
|
348
|
+
if (params.notes.length === 0) return [];
|
|
349
|
+
const shopOrderNumber = normalizeUuid(params.shopOrderNumber, 'shop_order_number');
|
|
350
|
+
const productTargetUuids = new Set();
|
|
351
|
+
for (const rawTargetUuid of params.productTargetUuids || []) {
|
|
352
|
+
const targetUuid = normalizeUuid(rawTargetUuid, '商品 target_uuid');
|
|
353
|
+
if (productTargetUuids.has(targetUuid)) {
|
|
354
|
+
throw new Error('[Order Notes] 商品行业务标识不能重复');
|
|
355
|
+
}
|
|
356
|
+
productTargetUuids.add(targetUuid);
|
|
357
|
+
}
|
|
358
|
+
const decoded = decodeSalesNotesSnapshot(params.notes, {
|
|
359
|
+
allowUnresolvedOrderTarget: true
|
|
360
|
+
});
|
|
361
|
+
if (!decoded.complete || decoded.notes.length !== params.notes.length) {
|
|
362
|
+
throw new Error('[Order Notes] checkout Notes 快照不完整');
|
|
363
|
+
}
|
|
364
|
+
const finalizedNotes = decoded.notes.map(note => ({
|
|
365
|
+
...note,
|
|
366
|
+
content: {
|
|
367
|
+
text: {
|
|
368
|
+
...note.content.text
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
note_relations: note.note_relations.map(relation => ({
|
|
372
|
+
...relation,
|
|
373
|
+
...(relation.is_primary === 0 && relation.relation_type === 'related_to' && relation.target_type === 'order' ? {
|
|
374
|
+
target_uuid: shopOrderNumber
|
|
375
|
+
} : {})
|
|
376
|
+
}))
|
|
377
|
+
}));
|
|
378
|
+
return encodeSalesNotes(finalizedNotes, {
|
|
379
|
+
expectedOrderTargetUuid: shopOrderNumber,
|
|
380
|
+
productTargetUuids
|
|
381
|
+
});
|
|
382
|
+
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { CartItem } from '../Cart/types';
|
|
2
2
|
import type { DiscountModule } from '../Discount';
|
|
3
3
|
import type { RulesModule } from '../Rules';
|
|
4
|
-
import type { Discount } from '../Discount/types';
|
|
4
|
+
import type { Discount, VirtualCurrencyAsset } from '../Discount/types';
|
|
5
5
|
import type { UnavailableReason } from '../Rules/types';
|
|
6
6
|
import type { SubmitPayloadEnhancer } from './utils';
|
|
7
7
|
import type { PaymentItem } from '../Payment/types';
|
|
8
8
|
import type { ICustomer } from '../AccountList/types';
|
|
9
9
|
import type { OrderProductDiscountItem } from '../../server/modules/order/types';
|
|
10
10
|
export type { OrderProductDiscountItem } from '../../server/modules/order/types';
|
|
11
|
+
export type PickupReferenceMode = 'counter_pickup' | 'table_service';
|
|
12
|
+
export type ShopServiceType = 'dine_in' | 'takeaway';
|
|
13
|
+
export interface ShopServiceData {
|
|
14
|
+
pickup_reference_mode?: PickupReferenceMode;
|
|
15
|
+
service_type?: ShopServiceType | '';
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
11
18
|
export declare enum OrderHooks {
|
|
12
19
|
OnOrderCreate = "order:onOrderCreate",
|
|
13
20
|
OnOrderUpdate = "order:onOrderUpdate",
|
|
@@ -110,7 +117,7 @@ export interface OrderLastGiftActions {
|
|
|
110
117
|
}>;
|
|
111
118
|
toRemove: string[];
|
|
112
119
|
}
|
|
113
|
-
/** onPromotionApplied
|
|
120
|
+
/** onPromotionApplied 稳定态事件 payload(促销、折扣与 summary 均已完成)。 */
|
|
114
121
|
export interface OrderPromotionAppliedPayload {
|
|
115
122
|
unfulfilledPromotions: OrderUnfulfilledPromotion[];
|
|
116
123
|
giftActions: OrderLastGiftActions;
|
|
@@ -124,7 +131,7 @@ export interface OrderPromotionAppliedPayload {
|
|
|
124
131
|
product_variant_id: number;
|
|
125
132
|
}>;
|
|
126
133
|
}>;
|
|
127
|
-
/**
|
|
134
|
+
/** 折扣重算后的最终商品列表 */
|
|
128
135
|
products: OrderProduct[];
|
|
129
136
|
}
|
|
130
137
|
/**
|
|
@@ -188,6 +195,17 @@ export interface OrderProductSku {
|
|
|
188
195
|
export interface OrderLocalizedText {
|
|
189
196
|
[locale: string]: string | null;
|
|
190
197
|
}
|
|
198
|
+
export interface PointCardSnapshotItem {
|
|
199
|
+
id: number | string;
|
|
200
|
+
tag: 'point_card';
|
|
201
|
+
product_id?: number | string;
|
|
202
|
+
product_name: string;
|
|
203
|
+
par_value: string;
|
|
204
|
+
used_par_value: string;
|
|
205
|
+
}
|
|
206
|
+
export interface OrderMetaList {
|
|
207
|
+
point_cards_snapshot?: PointCardSnapshotItem[];
|
|
208
|
+
}
|
|
191
209
|
export interface OrderProduct extends OrderProductIdentity {
|
|
192
210
|
order_detail_id: number | null;
|
|
193
211
|
num: number;
|
|
@@ -198,6 +216,7 @@ export interface OrderProduct extends OrderProductIdentity {
|
|
|
198
216
|
gift_card?: number;
|
|
199
217
|
selling_price: string;
|
|
200
218
|
original_price: string;
|
|
219
|
+
payment_price?: string;
|
|
201
220
|
tax_fee: string;
|
|
202
221
|
is_charge_tax: number;
|
|
203
222
|
discount_list: OrderProductDiscountItem[];
|
|
@@ -238,6 +257,72 @@ export interface OrderSummary {
|
|
|
238
257
|
tax_title?: string;
|
|
239
258
|
tax_rate?: number;
|
|
240
259
|
}
|
|
260
|
+
export type SalesNoteRelationType = 'about' | 'related_to';
|
|
261
|
+
export type SalesNoteTargetType = 'order' | 'order_detail';
|
|
262
|
+
export type SalesNoteLocalizedText = string | Record<string, string>;
|
|
263
|
+
export interface SalesNoteLocalizedSelection {
|
|
264
|
+
id: string;
|
|
265
|
+
label: SalesNoteLocalizedText;
|
|
266
|
+
}
|
|
267
|
+
export type SalesNoteTextInput = {
|
|
268
|
+
kind: 'localizedSelections';
|
|
269
|
+
selections: SalesNoteLocalizedSelection[];
|
|
270
|
+
locale: string;
|
|
271
|
+
input?: string;
|
|
272
|
+
} | {
|
|
273
|
+
kind: 'plain';
|
|
274
|
+
input: string;
|
|
275
|
+
} | {
|
|
276
|
+
kind: 'resolved';
|
|
277
|
+
text: Record<string, string>;
|
|
278
|
+
};
|
|
279
|
+
export interface SalesNoteRelation {
|
|
280
|
+
uuid: string;
|
|
281
|
+
relation_type: SalesNoteRelationType;
|
|
282
|
+
target_type: SalesNoteTargetType;
|
|
283
|
+
target_uuid: string;
|
|
284
|
+
is_primary: 0 | 1;
|
|
285
|
+
}
|
|
286
|
+
export interface SalesNote {
|
|
287
|
+
uuid: string;
|
|
288
|
+
note_type: string;
|
|
289
|
+
content: {
|
|
290
|
+
text: Record<string, string>;
|
|
291
|
+
};
|
|
292
|
+
importance: string;
|
|
293
|
+
note_relations: SalesNoteRelation[];
|
|
294
|
+
}
|
|
295
|
+
export interface SalesNoteTarget {
|
|
296
|
+
target_type: 'order_detail';
|
|
297
|
+
target_uuid: string;
|
|
298
|
+
}
|
|
299
|
+
export interface SetSalesNoteInput {
|
|
300
|
+
note_type: string;
|
|
301
|
+
target: SalesNoteTarget;
|
|
302
|
+
text: SalesNoteTextInput;
|
|
303
|
+
}
|
|
304
|
+
export interface SalesNoteDraftInput {
|
|
305
|
+
note_type: string;
|
|
306
|
+
text: SalesNoteTextInput;
|
|
307
|
+
}
|
|
308
|
+
export interface SalesNotesRuntimeState {
|
|
309
|
+
loaded: boolean;
|
|
310
|
+
dirty: boolean;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Sales Notes 乐观写入前的可恢复快照。
|
|
314
|
+
* 该对象应视为 opaque token,只用于原样传回 restoreSalesNotesMutationSnapshot。
|
|
315
|
+
*/
|
|
316
|
+
export interface SalesNotesMutationSnapshot {
|
|
317
|
+
orderIdentity: {
|
|
318
|
+
orderId: number | string | null;
|
|
319
|
+
externalSaleNumber: string;
|
|
320
|
+
};
|
|
321
|
+
notes: SalesNote[];
|
|
322
|
+
state: SalesNotesRuntimeState;
|
|
323
|
+
}
|
|
324
|
+
export type SalesNoteProtocolRelation = SalesNoteRelation;
|
|
325
|
+
export type SalesNoteProtocol = SalesNote;
|
|
241
326
|
export interface OrderTempOrder {
|
|
242
327
|
order_id: number | null;
|
|
243
328
|
external_sale_number: string;
|
|
@@ -277,18 +362,22 @@ export interface OrderTempOrder {
|
|
|
277
362
|
created_at: string | undefined;
|
|
278
363
|
request_unique_idempotency_token?: string;
|
|
279
364
|
products: OrderProduct[];
|
|
365
|
+
notes: SalesNote[];
|
|
280
366
|
bookings: any[];
|
|
281
367
|
payments: any[];
|
|
368
|
+
refunds?: any[];
|
|
282
369
|
surcharges: any[];
|
|
283
370
|
discount_list?: any[];
|
|
284
371
|
relation_forms: any[];
|
|
285
372
|
contacts: any[];
|
|
286
373
|
contacts_info: Record<string, any> | null;
|
|
287
374
|
holder: Record<string, any> | null;
|
|
375
|
+
order_meta_list?: OrderMetaList;
|
|
288
376
|
metadata: Record<string, any>;
|
|
289
377
|
summary?: OrderSummary;
|
|
290
378
|
_extend?: {
|
|
291
379
|
productsByUid?: Record<string, Record<string, any>>;
|
|
380
|
+
salesNotesState?: SalesNotesRuntimeState;
|
|
292
381
|
[key: string]: any;
|
|
293
382
|
};
|
|
294
383
|
}
|
|
@@ -297,8 +386,9 @@ export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identific
|
|
|
297
386
|
payment_price: string;
|
|
298
387
|
product_sku: OrderProductSku;
|
|
299
388
|
}
|
|
300
|
-
export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'products' | '_extend' | 'customer' | 'discount_list' | 'created_at'> {
|
|
389
|
+
export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'products' | 'notes' | '_extend' | 'customer' | 'discount_list' | 'created_at' | 'payment_status'> {
|
|
301
390
|
platform: string;
|
|
391
|
+
payment_status?: string;
|
|
302
392
|
created_at?: string | undefined;
|
|
303
393
|
request_unique_idempotency_token?: string;
|
|
304
394
|
form_record_ids?: Array<{
|
|
@@ -306,6 +396,7 @@ export interface OrderSubmitPayload extends Omit<OrderTempOrder, 'platform' | 'p
|
|
|
306
396
|
form_record_id: number | string;
|
|
307
397
|
}>;
|
|
308
398
|
products: OrderSubmitProduct[];
|
|
399
|
+
notes?: SalesNoteProtocol[];
|
|
309
400
|
summary?: OrderSummary;
|
|
310
401
|
small_ticket_data_flag?: number;
|
|
311
402
|
}
|
|
@@ -316,6 +407,7 @@ export interface OrderState {
|
|
|
316
407
|
syncState?: OrderSyncState;
|
|
317
408
|
discountList: any[];
|
|
318
409
|
availableWalletIds?: number[];
|
|
410
|
+
virtualCurrencyList?: VirtualCurrencyAsset[];
|
|
319
411
|
discount: DiscountModule | null;
|
|
320
412
|
rules: RulesModule | null;
|
|
321
413
|
}
|
|
@@ -334,6 +426,8 @@ export interface AddProductToOrderOptions {
|
|
|
334
426
|
insertAfterProductUid?: string;
|
|
335
427
|
/** 跳过同商品/规格匹配,始终新增购物车行。 */
|
|
336
428
|
disableMerge?: boolean;
|
|
429
|
+
/** 商品行 UID 落定后,由 OrderModule 原子绑定到该行的 Sales Notes 草稿。 */
|
|
430
|
+
salesNotes?: SalesNoteDraftInput[];
|
|
337
431
|
}
|
|
338
432
|
/**
|
|
339
433
|
* 删除商品后的可选位置保持策略。
|
|
@@ -452,7 +546,7 @@ export interface SubmitSalesOrderParams {
|
|
|
452
546
|
sales_channel: string;
|
|
453
547
|
order_sales_channel: string;
|
|
454
548
|
status: string;
|
|
455
|
-
payment_status
|
|
549
|
+
payment_status?: string;
|
|
456
550
|
shipping_status: string;
|
|
457
551
|
customer_id: number | null;
|
|
458
552
|
customer_name: string;
|
|
@@ -484,6 +578,7 @@ export interface SubmitSalesOrderParams {
|
|
|
484
578
|
contacts: any[];
|
|
485
579
|
contacts_info: Record<string, any> | null;
|
|
486
580
|
holder: Record<string, any> | null;
|
|
581
|
+
order_meta_list?: OrderMetaList;
|
|
487
582
|
metadata: Record<string, any>;
|
|
488
583
|
summary?: OrderSummary;
|
|
489
584
|
small_ticket_data_flag?: number;
|
|
@@ -716,6 +811,8 @@ export interface OrderModuleAPI {
|
|
|
716
811
|
addNewOrder: () => Promise<OrderTempOrder>;
|
|
717
812
|
restoreOrder: () => OrderTempOrder;
|
|
718
813
|
getOrderProducts: () => OrderProduct[];
|
|
814
|
+
getVirtualCurrencyList: () => VirtualCurrencyAsset[];
|
|
815
|
+
clearOrderForSettlementSwitch: () => Promise<OrderTempOrder>;
|
|
719
816
|
getOrderSummary: () => Promise<OrderSummary>;
|
|
720
817
|
recalculateSummary: (options?: {
|
|
721
818
|
createIfMissing?: boolean;
|
|
@@ -749,9 +846,17 @@ export interface OrderModuleAPI {
|
|
|
749
846
|
updateTempOrderShopDiscount: (amount: string | number) => string;
|
|
750
847
|
updateTempOrderDepositAmount: (amount: string | number) => OrderSummary;
|
|
751
848
|
updateTempOrderCustomer: (customer: UpdateTempOrderCustomerInput) => OrderSnapshot['customer'];
|
|
849
|
+
updateTempOrderPickupReferenceMode: (mode: PickupReferenceMode) => ShopServiceData;
|
|
850
|
+
updateTempOrderServiceType: (serviceType: ShopServiceType) => ShopServiceData;
|
|
752
851
|
updateTempOrderBuzzer: (buzzer: string) => string;
|
|
753
852
|
updateTempOrderContactsInfo: (contactsInfo: Record<string, any> | null) => Record<string, any> | null;
|
|
754
853
|
addProductToOrder: (product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput, options?: AddProductToOrderOptions) => Promise<OrderProduct[]>;
|
|
854
|
+
getSalesNotes: () => SalesNote[];
|
|
855
|
+
createSalesNotesMutationSnapshot: () => SalesNotesMutationSnapshot;
|
|
856
|
+
restoreSalesNotesMutationSnapshot: (snapshot: SalesNotesMutationSnapshot) => void;
|
|
857
|
+
setSalesNote: (input: SetSalesNoteInput) => Promise<SalesNote>;
|
|
858
|
+
removeSalesNote: (uuid: string) => Promise<void>;
|
|
859
|
+
clearSalesNotes: () => Promise<void>;
|
|
755
860
|
updateOrderProduct: (params: UpdateOrderProductParams) => Promise<OrderProduct[]>;
|
|
756
861
|
/** 批量更新购物车行,末尾仅触发一次促销重算与 summary 刷新 */
|
|
757
862
|
updateOrderProducts: (paramsList: UpdateOrderProductParams[]) => Promise<OrderProduct[]>;
|
|
@@ -778,6 +883,8 @@ export interface OrderModuleAPI {
|
|
|
778
883
|
isTempOrderPersistEnabled: () => boolean;
|
|
779
884
|
/** 提交 tempOrder 变更并触发 `{moduleName}:changed` 事件 */
|
|
780
885
|
notifyTempOrderChanged: () => void;
|
|
886
|
+
/** PC/H5 为在线店铺;其它或缺失平台统一按 POS 处理。 */
|
|
887
|
+
isOnlineStorePlatform: () => boolean;
|
|
781
888
|
submitTempOrder: <T = any>(params?: {
|
|
782
889
|
cacheId?: string;
|
|
783
890
|
platform?: string;
|
|
@@ -885,7 +992,7 @@ export interface OrderModuleAPI {
|
|
|
885
992
|
*/
|
|
886
993
|
appendPromotionTags: <T extends Record<string, any>>(products: T[]) => T[];
|
|
887
994
|
/**
|
|
888
|
-
* 应用购物车促销(评估 → 差异化赠品 →
|
|
995
|
+
* 应用购物车促销(评估 → 差异化赠品 → 折扣/summary 重算 → emit onPromotionApplied)。
|
|
889
996
|
*
|
|
890
997
|
* 自动在 addProductToOrder / updateOrderProductQuantity / removeProductFromOrder /
|
|
891
998
|
* clearOrderCartLines / setOrderCustomer 等写路径末尾触发,业务一般无需手动调用。
|
|
@@ -899,10 +1006,10 @@ export interface OrderModuleAPI {
|
|
|
899
1006
|
/** 读取上次 applyPromotion 产出的赠品操作 diff(toAdd / toReduce / toRemove) */
|
|
900
1007
|
getLastGiftActions: () => OrderLastGiftActions | null;
|
|
901
1008
|
/**
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1009
|
+
* 取消订单
|
|
1010
|
+
* @param params 取消订单参数
|
|
1011
|
+
* @returns 后端返回结果
|
|
1012
|
+
*/
|
|
906
1013
|
cancelOrder: (params: CancelOrderParams) => Promise<any>;
|
|
907
1014
|
/**
|
|
908
1015
|
* 变更预约状态
|