@pisell/pisellos 0.10.39 → 0.10.41
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/index.js +4 -4
- package/dist/modules/Customer/index.js +4 -2
- package/dist/modules/Customer/types.d.ts +2 -0
- package/dist/modules/Payment/types.d.ts +21 -1
- package/dist/modules/Payment/types.js +2 -0
- package/dist/modules/Payment/walletpass.d.ts +1 -1
- package/dist/modules/Payment/walletpass.js +80 -47
- package/dist/solution/BaseSales/index.d.ts +1 -0
- package/dist/solution/BaseSales/index.js +64 -43
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +1 -2
- package/dist/solution/BookingTicket/index.js +60 -63
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +2 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +266 -150
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +5 -3
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +4 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +8 -4
- package/dist/solution/UnifiedBookingSales/index.d.ts +2 -2
- package/dist/solution/UnifiedBookingSales/index.js +10 -10
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/index.js +3 -3
- package/lib/modules/Customer/index.js +4 -1
- package/lib/modules/Customer/types.d.ts +2 -0
- package/lib/modules/Payment/types.d.ts +21 -1
- package/lib/modules/Payment/types.js +1 -0
- package/lib/modules/Payment/walletpass.d.ts +1 -1
- package/lib/modules/Payment/walletpass.js +29 -9
- package/lib/solution/BaseSales/index.d.ts +1 -0
- package/lib/solution/BaseSales/index.js +18 -3
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +1 -2
- package/lib/solution/BookingTicket/index.js +36 -33
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +2 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +127 -42
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +5 -3
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +4 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +7 -3
- package/lib/solution/UnifiedBookingSales/index.d.ts +2 -2
- package/lib/solution/UnifiedBookingSales/index.js +4 -4
- package/package.json +1 -1
|
@@ -5,10 +5,21 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.applyGlobalScan = applyGlobalScan;
|
|
7
7
|
var _addProductDecision = require("../addProductDecision");
|
|
8
|
-
var _cartView = require("../cartView");
|
|
9
8
|
var _scanProductValues = require("./scanProductValues");
|
|
10
9
|
/** applyGlobalScan 所需的 BookingTicket 运行时能力 */
|
|
11
10
|
|
|
11
|
+
function getRealCustomerId(customer) {
|
|
12
|
+
const customerId = Number(customer?.id ?? customer?.customer_id);
|
|
13
|
+
return Number.isInteger(customerId) && customerId > 1 ? customerId : undefined;
|
|
14
|
+
}
|
|
15
|
+
function getWalletAssetCustomerId(asset) {
|
|
16
|
+
const customerId = Number(asset?.customer_id ?? asset?.holder?.customer_id);
|
|
17
|
+
return Number.isInteger(customerId) && customerId > 1 ? customerId : undefined;
|
|
18
|
+
}
|
|
19
|
+
function getErrorMessage(error) {
|
|
20
|
+
return error instanceof Error ? error.message : String(error || '');
|
|
21
|
+
}
|
|
22
|
+
|
|
12
23
|
/**
|
|
13
24
|
* 处理单条扫码商品的加车决策(含弹窗链)。
|
|
14
25
|
*/
|
|
@@ -93,17 +104,55 @@ async function applyGlobalScan(host, formatted, bridge) {
|
|
|
93
104
|
const {
|
|
94
105
|
searchType,
|
|
95
106
|
data,
|
|
96
|
-
scanCode
|
|
107
|
+
scanCode,
|
|
108
|
+
customerId: formattedCustomerId,
|
|
109
|
+
isCrossShopWallet
|
|
97
110
|
} = formatted;
|
|
98
111
|
if (searchType === 'wallet') {
|
|
99
|
-
|
|
112
|
+
const currentCustomer = host.getOrderCustomerSnapshot();
|
|
113
|
+
if (getRealCustomerId(currentCustomer) !== undefined) {
|
|
114
|
+
return {
|
|
115
|
+
status: 'success',
|
|
116
|
+
kind: 'customer'
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
let customer = data;
|
|
120
|
+
if (isCrossShopWallet) {
|
|
121
|
+
const sourceCustomerId = getRealCustomerId({
|
|
122
|
+
id: formattedCustomerId
|
|
123
|
+
});
|
|
124
|
+
if (sourceCustomerId === undefined || !host.resolveCustomerById) {
|
|
125
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
126
|
+
return {
|
|
127
|
+
status: 'failed',
|
|
128
|
+
reason: 'invalid_data'
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
customer = await host.resolveCustomerById(sourceCustomerId);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
bridge?.onNotify?.('fail', getErrorMessage(error) || 'pisell2.text.scan-global-failed');
|
|
135
|
+
return {
|
|
136
|
+
status: 'failed',
|
|
137
|
+
reason: 'invalid_data'
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const customerId = getRealCustomerId(customer) ?? (!isCrossShopWallet ? getRealCustomerId({
|
|
142
|
+
id: formattedCustomerId
|
|
143
|
+
}) : undefined);
|
|
144
|
+
if (!customer || customerId === undefined) {
|
|
100
145
|
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
101
146
|
return {
|
|
102
147
|
status: 'failed',
|
|
103
148
|
reason: 'invalid_data'
|
|
104
149
|
};
|
|
105
150
|
}
|
|
106
|
-
|
|
151
|
+
const orderCustomer = customer.id === undefined || customer.id === null ? {
|
|
152
|
+
...customer,
|
|
153
|
+
id: customerId
|
|
154
|
+
} : customer;
|
|
155
|
+
host.setOrderCustomer(orderCustomer);
|
|
107
156
|
bridge?.onNotify?.('success', 'pisell2.text.add-client-success');
|
|
108
157
|
return {
|
|
109
158
|
status: 'success',
|
|
@@ -112,7 +161,58 @@ async function applyGlobalScan(host, formatted, bridge) {
|
|
|
112
161
|
}
|
|
113
162
|
if (searchType === 'walletPass') {
|
|
114
163
|
const snapshot = host.getOrderCustomerSnapshot();
|
|
115
|
-
const
|
|
164
|
+
const currentCustomerIsWalkIn = getRealCustomerId(snapshot) === undefined;
|
|
165
|
+
let activeCustomer = snapshot;
|
|
166
|
+
const bindWalletPassCustomer = async asset => {
|
|
167
|
+
if (!currentCustomerIsWalkIn) {
|
|
168
|
+
return {
|
|
169
|
+
resolveFailed: false
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const assetCustomerId = getWalletAssetCustomerId(asset) ?? getRealCustomerId({
|
|
173
|
+
id: formattedCustomerId
|
|
174
|
+
});
|
|
175
|
+
let customer = null;
|
|
176
|
+
if (assetCustomerId !== undefined) {
|
|
177
|
+
if (!host.resolveCustomerById) {
|
|
178
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
179
|
+
return {
|
|
180
|
+
resolveFailed: true
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
customer = await host.resolveCustomerById(assetCustomerId);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.warn('[GlobalScan] Wallet asset customer lookup failed', error);
|
|
187
|
+
bridge?.onNotify?.('fail', getErrorMessage(error) || 'pisell2.text.scan-global-failed');
|
|
188
|
+
return {
|
|
189
|
+
resolveFailed: true
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const customerId = getRealCustomerId(customer);
|
|
194
|
+
if (!customer || customerId === undefined) {
|
|
195
|
+
if (assetCustomerId !== undefined) {
|
|
196
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
resolveFailed: assetCustomerId !== undefined
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
const orderCustomer = customer.id === undefined || customer.id === null ? {
|
|
203
|
+
...customer,
|
|
204
|
+
id: customerId
|
|
205
|
+
} : customer;
|
|
206
|
+
host.setOrderCustomer(orderCustomer);
|
|
207
|
+
activeCustomer = orderCustomer;
|
|
208
|
+
await host.refreshWalletAssets?.({
|
|
209
|
+
preserveSelection: false,
|
|
210
|
+
retainSearchResultCodes: [scanCode]
|
|
211
|
+
});
|
|
212
|
+
return {
|
|
213
|
+
resolveFailed: false
|
|
214
|
+
};
|
|
215
|
+
};
|
|
116
216
|
const trySelectWalletAsset = async () => {
|
|
117
217
|
if (!host.scanWalletAsset) return null;
|
|
118
218
|
const walletResult = await host.scanWalletAsset(scanCode).catch(error => {
|
|
@@ -123,61 +223,46 @@ async function applyGlobalScan(host, formatted, bridge) {
|
|
|
123
223
|
if (walletResult.type !== 'normalCode' || !walletResult.asset) {
|
|
124
224
|
return null;
|
|
125
225
|
}
|
|
226
|
+
const bindResult = await bindWalletPassCustomer(walletResult.asset);
|
|
126
227
|
if (walletResult.selected) {
|
|
127
|
-
|
|
228
|
+
if (!bindResult.resolveFailed) {
|
|
229
|
+
bridge?.onNotify?.('success');
|
|
230
|
+
}
|
|
128
231
|
return {
|
|
129
232
|
status: 'success',
|
|
130
233
|
kind: 'promotion'
|
|
131
234
|
};
|
|
132
235
|
}
|
|
133
236
|
// 已识别为 Wallet 支付资产但当前不可用:保留禁用展示,不回退优惠码。
|
|
134
|
-
|
|
237
|
+
if (!bindResult.resolveFailed) {
|
|
238
|
+
bridge?.onNotify?.('fail', 'pisell2.text.goodpass.code-invalid-cart');
|
|
239
|
+
}
|
|
135
240
|
return {
|
|
136
241
|
status: 'failed',
|
|
137
242
|
reason: 'invalid_data'
|
|
138
243
|
};
|
|
139
244
|
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
status: 'failed',
|
|
147
|
-
reason: 'no_bridge'
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
const result = await bridge.applyPromotionCode(scanCode);
|
|
151
|
-
if (result?.isAccepted ?? result?.isAvailable) {
|
|
152
|
-
return {
|
|
153
|
-
status: 'success',
|
|
154
|
-
kind: 'promotion'
|
|
155
|
-
};
|
|
156
|
-
}
|
|
245
|
+
const walletSelection = await trySelectWalletAsset();
|
|
246
|
+
if (walletSelection) return walletSelection;
|
|
247
|
+
|
|
248
|
+
// 非支付类 Wallet Pass 仍可能由 batch-search 返回所属客户。
|
|
249
|
+
await bindWalletPassCustomer();
|
|
250
|
+
if (!bridge?.applyPromotionCode) {
|
|
157
251
|
return {
|
|
158
252
|
status: 'failed',
|
|
159
|
-
reason: '
|
|
253
|
+
reason: 'no_bridge'
|
|
160
254
|
};
|
|
161
255
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (bridge?.applyPromotionCode) {
|
|
169
|
-
const promotionResult = await bridge.applyPromotionCode(scanCode, Number(data?.id ?? data?.customer_id) || undefined);
|
|
170
|
-
if (promotionResult?.isAccepted ?? promotionResult?.isAvailable) {
|
|
171
|
-
return {
|
|
172
|
-
status: 'success',
|
|
173
|
-
kind: 'promotion'
|
|
174
|
-
};
|
|
175
|
-
}
|
|
256
|
+
const promotionResult = await bridge.applyPromotionCode(scanCode, getRealCustomerId(activeCustomer));
|
|
257
|
+
if (promotionResult?.isAccepted ?? promotionResult?.isAvailable) {
|
|
258
|
+
return {
|
|
259
|
+
status: 'success',
|
|
260
|
+
kind: 'promotion'
|
|
261
|
+
};
|
|
176
262
|
}
|
|
177
|
-
bridge?.onNotify?.('success', 'pisell2.text.add-client-success');
|
|
178
263
|
return {
|
|
179
|
-
status: '
|
|
180
|
-
|
|
264
|
+
status: 'failed',
|
|
265
|
+
reason: 'invalid_data'
|
|
181
266
|
};
|
|
182
267
|
}
|
|
183
268
|
if (searchType === 'product' || searchType === 'local_product') {
|
|
@@ -14,6 +14,7 @@ const searchWalletPass = async (request, code) => {
|
|
|
14
14
|
// 翻译识别码名称 0:不翻译 1:翻译
|
|
15
15
|
relation_product: 1,
|
|
16
16
|
// 组装关联商品: 0不处理 1处理
|
|
17
|
+
with_franchisor_data: 1,
|
|
17
18
|
with: ['customer'],
|
|
18
19
|
tags: ['point_card',
|
|
19
20
|
// 积分卡
|
|
@@ -51,17 +52,18 @@ exports.searchWalletPass = searchWalletPass;
|
|
|
51
52
|
const searchWallet = async (request, code) => {
|
|
52
53
|
const params = {
|
|
53
54
|
code,
|
|
54
|
-
with_customer: 1
|
|
55
|
+
with_customer: 1,
|
|
56
|
+
with_franchisor_data: 1
|
|
55
57
|
};
|
|
56
58
|
try {
|
|
57
59
|
const res = await request?.post('/wallet/detail/search', params);
|
|
58
|
-
if (res?.code
|
|
60
|
+
if (res?.status === true && res?.code === 200 && !!res?.data) {
|
|
59
61
|
return {
|
|
60
62
|
searchType: 'wallet',
|
|
61
63
|
response: res
|
|
62
64
|
};
|
|
63
65
|
}
|
|
64
|
-
throw new Error('没有找到对应的识别码');
|
|
66
|
+
throw new Error(res?.message || '没有找到对应的识别码');
|
|
65
67
|
} catch (error) {
|
|
66
68
|
throw error;
|
|
67
69
|
}
|
|
@@ -6,6 +6,10 @@ export interface GlobalScanFormattedResult {
|
|
|
6
6
|
searchType: GlobalScanSearchType;
|
|
7
7
|
data: any;
|
|
8
8
|
scanCode: string;
|
|
9
|
+
/** Wallet / Wallet Pass 来源客户 ID;跨店时必须先解析为当前店客户。 */
|
|
10
|
+
customerId?: string | number;
|
|
11
|
+
/** 仅 Wallet 返回;true 时禁止直接使用响应内的来源客户。 */
|
|
12
|
+
isCrossShopWallet?: boolean;
|
|
9
13
|
}
|
|
10
14
|
interface RawScanSearchResult {
|
|
11
15
|
searchType?: GlobalScanSearchType;
|
|
@@ -36,14 +36,18 @@ function formatGlobalScanResult(raw, scanCode) {
|
|
|
36
36
|
return {
|
|
37
37
|
searchType,
|
|
38
38
|
data: resultData?.customer,
|
|
39
|
-
scanCode
|
|
39
|
+
scanCode,
|
|
40
|
+
customerId: resultData?.customer_id,
|
|
41
|
+
isCrossShopWallet: resultData?.is_cross_shop_wallet === true || Number(resultData?.is_cross_shop_wallet) === 1
|
|
40
42
|
};
|
|
41
43
|
}
|
|
42
44
|
if (searchType === 'walletPass') {
|
|
45
|
+
const firstResult = resultData?.[0];
|
|
43
46
|
return {
|
|
44
47
|
searchType,
|
|
45
|
-
data:
|
|
46
|
-
scanCode
|
|
48
|
+
data: firstResult?.customer,
|
|
49
|
+
scanCode,
|
|
50
|
+
customerId: firstResult?.customer_id ?? firstResult?.holder?.customer_id ?? firstResult?.customer?.id ?? firstResult?.customer?.customer_id
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
if (searchType === 'product' || searchType === 'local_product') {
|
|
@@ -123,8 +123,8 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
|
|
|
123
123
|
*/
|
|
124
124
|
clearSessionStorageOrderSnapshot(): void;
|
|
125
125
|
/**
|
|
126
|
-
* H5/Kiosk
|
|
127
|
-
*
|
|
126
|
+
* PC/H5/Kiosk 结账默认直接等待云端 checkout;POS/WebPOS 仍保持本地待同步。
|
|
127
|
+
* 显式传 checkoutSyncTaskEnabled: true 时仍可回退到本地同步模式。
|
|
128
128
|
*/
|
|
129
129
|
protected shouldUseCheckoutSyncTask(): boolean;
|
|
130
130
|
/** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
|
|
@@ -1522,14 +1522,14 @@ class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
|
1522
1522
|
}
|
|
1523
1523
|
|
|
1524
1524
|
/**
|
|
1525
|
-
* H5/Kiosk
|
|
1526
|
-
*
|
|
1525
|
+
* PC/H5/Kiosk 结账默认直接等待云端 checkout;POS/WebPOS 仍保持本地待同步。
|
|
1526
|
+
* 显式传 checkoutSyncTaskEnabled: true 时仍可回退到本地同步模式。
|
|
1527
1527
|
*/
|
|
1528
1528
|
shouldUseCheckoutSyncTask() {
|
|
1529
1529
|
const configured = this.otherParams?.checkoutSyncTaskEnabled;
|
|
1530
1530
|
if (configured === true) return true;
|
|
1531
|
-
const platform = (
|
|
1532
|
-
return platform
|
|
1531
|
+
const platform = String(this.otherParams?.platform ?? '').trim().toLowerCase();
|
|
1532
|
+
return !(0, _platform.isCustomerUserPlatform)(platform) && platform !== 'kiosk';
|
|
1533
1533
|
}
|
|
1534
1534
|
|
|
1535
1535
|
/** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
|