@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
|
@@ -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 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
|
|
@@ -44,7 +44,7 @@ import { UnifiedBookingSalesHooks } from "./types";
|
|
|
44
44
|
import { AvailabilityRemoteOccupancyCache } from "./remoteOccupancyCache";
|
|
45
45
|
import { BookingTicket } from "../BookingTicket";
|
|
46
46
|
import { addLocalCalendarDays, captureRuntimeOffsetMinutes, formatLocalDate, formatLocalDateTime, formatLocalTime, localDateTimeToScalar, localDateToScalar, localDateToScalarStart, parseLocalDate, parseLocalDateTime } from "../../modules/ResourcePlanner/localClock";
|
|
47
|
-
import { isCustomerUserPlatform
|
|
47
|
+
import { isCustomerUserPlatform } from "../../utils/platform";
|
|
48
48
|
export * from "./types";
|
|
49
49
|
export { AvailabilityError } from "../../modules/ResourcePlanner";
|
|
50
50
|
var OPEN_DATA_SECTION_CODES = ['sale', 'reservation', 'fulfillment', 'menu', 'workflow', 'basic', 'checkout', 'availability', 'documents'];
|
|
@@ -1830,17 +1830,17 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
1830
1830
|
}
|
|
1831
1831
|
|
|
1832
1832
|
/**
|
|
1833
|
-
* H5/Kiosk
|
|
1834
|
-
*
|
|
1833
|
+
* PC/H5/Kiosk 结账默认直接等待云端 checkout;POS/WebPOS 仍保持本地待同步。
|
|
1834
|
+
* 显式传 checkoutSyncTaskEnabled: true 时仍可回退到本地同步模式。
|
|
1835
1835
|
*/
|
|
1836
1836
|
}, {
|
|
1837
1837
|
key: "shouldUseCheckoutSyncTask",
|
|
1838
1838
|
value: function shouldUseCheckoutSyncTask() {
|
|
1839
|
-
var _this$otherParams13, _this$otherParams14;
|
|
1839
|
+
var _this$otherParams13, _this$otherParams$pla, _this$otherParams14;
|
|
1840
1840
|
var configured = (_this$otherParams13 = this.otherParams) === null || _this$otherParams13 === void 0 ? void 0 : _this$otherParams13.checkoutSyncTaskEnabled;
|
|
1841
1841
|
if (configured === true) return true;
|
|
1842
|
-
var platform =
|
|
1843
|
-
return platform
|
|
1842
|
+
var platform = String((_this$otherParams$pla = (_this$otherParams14 = this.otherParams) === null || _this$otherParams14 === void 0 ? void 0 : _this$otherParams14.platform) !== null && _this$otherParams$pla !== void 0 ? _this$otherParams$pla : '').trim().toLowerCase();
|
|
1843
|
+
return !isCustomerUserPlatform(platform) && platform !== 'kiosk';
|
|
1844
1844
|
}
|
|
1845
1845
|
|
|
1846
1846
|
/** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
|
|
@@ -4282,7 +4282,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4282
4282
|
key: "getProductTimeRanges",
|
|
4283
4283
|
value: (function () {
|
|
4284
4284
|
var _getProductTimeRanges = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee37(contextId) {
|
|
4285
|
-
var _this$otherParams$
|
|
4285
|
+
var _this$otherParams$pla2,
|
|
4286
4286
|
_this$otherParams20,
|
|
4287
4287
|
_this9 = this;
|
|
4288
4288
|
var request,
|
|
@@ -4304,7 +4304,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4304
4304
|
context = _yield$this$ensureAva.context;
|
|
4305
4305
|
projectionEntry = _yield$this$ensureAva.projectionEntry;
|
|
4306
4306
|
contextVersion = context.activeVersion;
|
|
4307
|
-
isPosAvailabilityRequest = String((_this$otherParams$
|
|
4307
|
+
isPosAvailabilityRequest = String((_this$otherParams$pla2 = (_this$otherParams20 = this.otherParams) === null || _this$otherParams20 === void 0 ? void 0 : _this$otherParams20.platform) !== null && _this$otherParams$pla2 !== void 0 ? _this$otherParams$pla2 : '').trim().toLowerCase() === 'pos';
|
|
4308
4308
|
allowOutsideOperatingHoursForRequestedStartTimes = isPosAvailabilityRequest && Object.values(request.durationStartTimesByProductId || {}).some(function (startTimes) {
|
|
4309
4309
|
return Array.isArray(startTimes) && startTimes.length > 0;
|
|
4310
4310
|
});
|
|
@@ -4456,7 +4456,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4456
4456
|
key: "commitAvailabilitySelection",
|
|
4457
4457
|
value: (function () {
|
|
4458
4458
|
var _commitAvailabilitySelection = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee39(contextId, params) {
|
|
4459
|
-
var normalizedContextId, _params$bookingCount, _ref46, _params$orderProduct$, _params$orderProduct, _params$orderProduct2, _params$orderProduct3, _params$orderProduct$2, _params$orderProduct4, _params$orderProduct5, _editingLine$product_, _baseProjection$meta$, _refreshedProjection$, _baseProjection$meta$2, _this$otherParams$
|
|
4459
|
+
var normalizedContextId, _params$bookingCount, _ref46, _params$orderProduct$, _params$orderProduct, _params$orderProduct2, _params$orderProduct3, _params$orderProduct$2, _params$orderProduct4, _params$orderProduct5, _editingLine$product_, _baseProjection$meta$, _refreshedProjection$, _baseProjection$meta$2, _this$otherParams$pla3, _this$otherParams21, _ref47, _params$orderProduct$3, _params$orderProduct6, _existingBooking$meta, _ref48, _ref49, _params$orderProduct$4, _params$orderProduct7, _params$orderProduct8, _existingBooking$meta2, _existingBooking$hold, bookingCount, orderProductQuantity, partySize, _yield$this$ensureAva3, context, projectionEntry, refreshed, boundEditingUids, orderProductId, editingLine, _editingLine$product_2, baseProjection, commitWriteGuard, prepareParams, fallbackResources, commitSnapshot, refreshedProjection, _baseProjection$meta$3, latestContext, candidateDurationMinutes, candidateStartTime, allowPosAvailabilityOverride, refreshedRanges, refreshedCandidateBase, product, validation, forced, capacityConflict, revalidationEntry, revalidatedContext, refreshedCandidate, existingBooking, existingBookingUid, booking, transformed, productLineUid, bookingUid, productLineUids, bookingUids, _transformed$product_, _transformed$product_2, _transformed$product_3, _ref50, _transformed$product_4, _this$getTempOrder4, _this$getTempOrder5, _this$getTempOrder6, beforeProductLineUids, beforeBookingUids, products, addedLines, addedBookings, nextContext, result;
|
|
4460
4460
|
return _regeneratorRuntime().wrap(function _callee39$(_context39) {
|
|
4461
4461
|
while (1) switch (_context39.prev = _context39.next) {
|
|
4462
4462
|
case 0:
|
|
@@ -4686,7 +4686,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
|
|
|
4686
4686
|
this.assertAvailabilityCommitWriteCAS(commitWriteGuard);
|
|
4687
4687
|
candidateDurationMinutes = getCandidateDurationMinutes(params.candidate);
|
|
4688
4688
|
candidateStartTime = getCandidateStartTime(params.candidate);
|
|
4689
|
-
allowPosAvailabilityOverride = String((_this$otherParams$
|
|
4689
|
+
allowPosAvailabilityOverride = String((_this$otherParams$pla3 = (_this$otherParams21 = this.otherParams) === null || _this$otherParams21 === void 0 ? void 0 : _this$otherParams21.platform) !== null && _this$otherParams$pla3 !== void 0 ? _this$otherParams$pla3 : '').trim().toLowerCase() === 'pos';
|
|
4690
4690
|
refreshedRanges = getProjectionProductTimeRanges(refreshedProjection, _objectSpread({
|
|
4691
4691
|
productIds: [params.candidate.productId],
|
|
4692
4692
|
dateRange: {
|
|
@@ -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; }
|
|
@@ -171,9 +171,9 @@ function buildBookingConfigQueryKey(params = {}) {
|
|
|
171
171
|
return JSON.stringify(sorted);
|
|
172
172
|
}
|
|
173
173
|
function resolveBookingConfigRequest(platform, params = {}) {
|
|
174
|
-
const
|
|
175
|
-
const endpoint =
|
|
176
|
-
const query =
|
|
174
|
+
const isCustomerPlatform = (0, _platform.isCustomerUserPlatform)(platform);
|
|
175
|
+
const endpoint = isCustomerPlatform ? H5_BOOKING_CONFIG_ENDPOINT : BOOKING_CONFIG_ENDPOINT;
|
|
176
|
+
const query = isCustomerPlatform ? {
|
|
177
177
|
item_type: params.item_type || DEFAULT_BOOKING_CONFIG_PARAMS.item_type
|
|
178
178
|
} : {
|
|
179
179
|
...DEFAULT_BOOKING_CONFIG_PARAMS,
|
|
@@ -153,7 +153,10 @@ class CustomerModule extends _BaseModule.BaseModule {
|
|
|
153
153
|
...(search && {
|
|
154
154
|
search
|
|
155
155
|
}),
|
|
156
|
-
..._otherParams
|
|
156
|
+
..._otherParams,
|
|
157
|
+
...(url === '/customer/select-list' ? {
|
|
158
|
+
with_franchisor_data: 1
|
|
159
|
+
} : {})
|
|
157
160
|
};
|
|
158
161
|
const res = await this.request.get(url, queryParams, {
|
|
159
162
|
cache: {
|
|
@@ -412,6 +412,8 @@ export interface WalletAssetsBehaviorOptions {
|
|
|
412
412
|
export interface RefreshWalletAssetsOptions {
|
|
413
413
|
/** 商品/金额变化默认保留并重验选择;客户变化由实现层强制清空。 */
|
|
414
414
|
preserveSelection?: boolean;
|
|
415
|
+
/** 客户变化时,仅保留与本次扫码匹配的搜索结果;其他搜索缓存仍会清空。 */
|
|
416
|
+
retainSearchResultCodes?: string[];
|
|
415
417
|
}
|
|
416
418
|
export interface SelectWalletAssetOptions {
|
|
417
419
|
selected: boolean;
|
|
@@ -419,6 +421,8 @@ export interface SelectWalletAssetOptions {
|
|
|
419
421
|
}
|
|
420
422
|
export interface ScanWalletAssetResult {
|
|
421
423
|
type: SearchIdentificationCodeResult['type'];
|
|
424
|
+
/** walletCode 时保留完整 Wallet Detail,供客户解析与客户选择器使用。 */
|
|
425
|
+
data?: WalletDetailSearchData;
|
|
422
426
|
asset?: any;
|
|
423
427
|
selected: boolean;
|
|
424
428
|
state: WalletAssetsState;
|
|
@@ -864,6 +868,8 @@ export interface SearchIdentificationCodeParams extends WalletDeductionRecommend
|
|
|
864
868
|
* 搜索识别码响应数据
|
|
865
869
|
*/
|
|
866
870
|
export interface SearchIdentificationCodeResponse {
|
|
871
|
+
/** 业务是否成功 */
|
|
872
|
+
status?: boolean;
|
|
867
873
|
/** 响应状态码 */
|
|
868
874
|
code?: number;
|
|
869
875
|
/** 响应消息 */
|
|
@@ -871,12 +877,26 @@ export interface SearchIdentificationCodeResponse {
|
|
|
871
877
|
/** 响应数据 */
|
|
872
878
|
data?: SearchIdentificationCodeItem[];
|
|
873
879
|
}
|
|
880
|
+
/** Wallet code 精确搜索返回的 Wallet Detail。 */
|
|
881
|
+
export interface WalletDetailSearchData {
|
|
882
|
+
id?: string | number;
|
|
883
|
+
customer_id?: string | number;
|
|
884
|
+
customer?: Record<string, any> | null;
|
|
885
|
+
is_cross_shop_wallet?: boolean | 0 | 1;
|
|
886
|
+
[key: string]: any;
|
|
887
|
+
}
|
|
888
|
+
export interface WalletDetailSearchResponse {
|
|
889
|
+
status?: boolean;
|
|
890
|
+
code?: number;
|
|
891
|
+
message?: string;
|
|
892
|
+
data?: WalletDetailSearchData | null;
|
|
893
|
+
}
|
|
874
894
|
/**
|
|
875
895
|
* 搜索识别码结果类型
|
|
876
896
|
*/
|
|
877
897
|
export type SearchIdentificationCodeResult = {
|
|
878
898
|
type: 'walletCode';
|
|
879
|
-
data:
|
|
899
|
+
data: WalletDetailSearchData;
|
|
880
900
|
} | {
|
|
881
901
|
type: 'normalCode';
|
|
882
902
|
data: SearchIdentificationCodeItem[];
|
|
@@ -96,7 +96,7 @@ export declare class WalletPassPaymentImpl implements WalletPassPayment {
|
|
|
96
96
|
* 搜索识别码信息
|
|
97
97
|
* 通过识别码搜索相关的钱包通行证信息
|
|
98
98
|
* 基于 WalletDeductionRecommendParams 参数结构
|
|
99
|
-
*
|
|
99
|
+
* 特殊逻辑:WL 或指定 200 格式的 Wallet Code 调用 /wallet/detail/search 接口。
|
|
100
100
|
*/
|
|
101
101
|
searchIdentificationCodeAsync(params: SearchIdentificationCodeParams, config?: {
|
|
102
102
|
noCache?: boolean;
|
|
@@ -705,7 +705,7 @@ class WalletPassPaymentImpl {
|
|
|
705
705
|
* 搜索识别码信息
|
|
706
706
|
* 通过识别码搜索相关的钱包通行证信息
|
|
707
707
|
* 基于 WalletDeductionRecommendParams 参数结构
|
|
708
|
-
*
|
|
708
|
+
* 特殊逻辑:WL 或指定 200 格式的 Wallet Code 调用 /wallet/detail/search 接口。
|
|
709
709
|
*/
|
|
710
710
|
async searchIdentificationCodeAsync(params, config = {}) {
|
|
711
711
|
try {
|
|
@@ -725,6 +725,7 @@ class WalletPassPaymentImpl {
|
|
|
725
725
|
const walletDetailParams = {
|
|
726
726
|
code: code,
|
|
727
727
|
with_customer: 1,
|
|
728
|
+
with_franchisor_data: 1,
|
|
728
729
|
with: ['wallet']
|
|
729
730
|
};
|
|
730
731
|
this.paymentModule.logInfo('[WalletPass] 搜索钱包识别码', {
|
|
@@ -733,15 +734,18 @@ class WalletPassPaymentImpl {
|
|
|
733
734
|
with: walletDetailParams.with
|
|
734
735
|
});
|
|
735
736
|
const response = await this.paymentModule.request.post('/wallet/detail/search', walletDetailParams);
|
|
736
|
-
const
|
|
737
|
+
const walletDetail = response?.data;
|
|
738
|
+
if (response?.status !== true || response?.code !== 200 || !walletDetail || typeof walletDetail !== 'object' || Array.isArray(walletDetail)) {
|
|
739
|
+
throw new Error(response?.message || 'Wallet detail search failed');
|
|
740
|
+
}
|
|
737
741
|
this.paymentModule.logInfo('[WalletPass] 钱包识别码搜索完成', {
|
|
738
742
|
code: code,
|
|
739
|
-
results_count:
|
|
743
|
+
results_count: 1,
|
|
740
744
|
type: 'walletCode'
|
|
741
745
|
});
|
|
742
746
|
return {
|
|
743
747
|
type: 'walletCode',
|
|
744
|
-
data:
|
|
748
|
+
data: walletDetail
|
|
745
749
|
};
|
|
746
750
|
}
|
|
747
751
|
|
|
@@ -830,9 +834,16 @@ class WalletPassPaymentImpl {
|
|
|
830
834
|
const previousCustomerId = this.walletAssetsState.customerId;
|
|
831
835
|
const customerChanged = String(previousCustomerId ?? '') !== String(nextCustomerId ?? '');
|
|
832
836
|
const preserveSelection = options.preserveSelection !== false && !customerChanged;
|
|
837
|
+
const retainedSearchCodeKeys = new Set((options.retainSearchResultCodes || []).map(normalizeWalletAssetCode).filter(Boolean));
|
|
838
|
+
const retainedSearchResults = customerChanged && retainedSearchCodeKeys.size > 0 ? this.searchResults.filter(item => isWalletPaymentAsset(item) && getWalletAssetCodeKeys(item).some(code => retainedSearchCodeKeys.has(code))) : [];
|
|
833
839
|
if (customerChanged) {
|
|
834
840
|
this.clearSearchResults();
|
|
841
|
+
if (retainedSearchResults.length > 0) {
|
|
842
|
+
this.searchResults = mergeWalletAssets(retainedSearchResults);
|
|
843
|
+
this.queuePendingAutoSelectForAssets(retainedSearchResults);
|
|
844
|
+
}
|
|
835
845
|
}
|
|
846
|
+
const preserveSearchContext = preserveSelection || retainedSearchResults.length > 0;
|
|
836
847
|
const committedKeys = new Set(this.walletAssetsState.committedIds.map(id => String(id)));
|
|
837
848
|
const committedItems = this.walletAssetsState.items.filter(item => committedKeys.has(getWalletAssetKey(item)));
|
|
838
849
|
const selectedIds = preserveSelection ? [...this.walletAssetsState.selectedIds] : [];
|
|
@@ -901,8 +912,8 @@ class WalletPassPaymentImpl {
|
|
|
901
912
|
error: null
|
|
902
913
|
});
|
|
903
914
|
try {
|
|
904
|
-
const searchedWalletAssetCodes =
|
|
905
|
-
const useAggregateRecalculate =
|
|
915
|
+
const searchedWalletAssetCodes = preserveSearchContext ? this.getSearchedWalletAssetCodes() : [];
|
|
916
|
+
const useAggregateRecalculate = preserveSearchContext && (selectedIds.length > 0 || searchedWalletAssetCodes.length > 0);
|
|
906
917
|
const aggregateResult = useAggregateRecalculate ? await this.aggregateRecalculateWalletAssetsAsync(businessData, selectedIds) : null;
|
|
907
918
|
const result = aggregateResult || (await this.initializeWalletDataFromBusinessAsync(businessData));
|
|
908
919
|
if (requestSequence !== this.walletAssetsRequestSequence) {
|
|
@@ -920,7 +931,7 @@ class WalletPassPaymentImpl {
|
|
|
920
931
|
this.searchResults = this.searchResults.filter(item => !missingSelectedKeys.has(getWalletAssetKey(item)));
|
|
921
932
|
}
|
|
922
933
|
}
|
|
923
|
-
const searchedWalletAssets =
|
|
934
|
+
const searchedWalletAssets = preserveSearchContext ? this.syncSearchedWalletAssets([...(result.transformList || []), ...(result.noApplicableVoucher || [])]) : [];
|
|
924
935
|
if (requestSequence !== this.walletAssetsRequestSequence) {
|
|
925
936
|
return this.getWalletAssetsState();
|
|
926
937
|
}
|
|
@@ -1122,14 +1133,23 @@ class WalletPassPaymentImpl {
|
|
|
1122
1133
|
code: normalizedCode,
|
|
1123
1134
|
prepare_payments: this.formatWalletPassList2PreparePayments(this.walletAssetsState.selectedItems)
|
|
1124
1135
|
});
|
|
1136
|
+
if (result.type === 'walletCode') {
|
|
1137
|
+
return {
|
|
1138
|
+
type: 'walletCode',
|
|
1139
|
+
data: result.data,
|
|
1140
|
+
asset: result.data,
|
|
1141
|
+
selected: false,
|
|
1142
|
+
state: this.getWalletAssetsState()
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1125
1145
|
const paymentAssets = this.formatSearchedWalletPaymentAssets(result.data.filter(isWalletPaymentAsset));
|
|
1126
1146
|
if (paymentAssets.length > 0) {
|
|
1127
1147
|
this.searchResults = mergeWalletAssets(this.searchResults, paymentAssets);
|
|
1128
1148
|
}
|
|
1129
1149
|
const asset = paymentAssets.find(item => String(item?.code || '') === normalizedCode) || paymentAssets[0];
|
|
1130
|
-
if (!asset
|
|
1150
|
+
if (!asset) {
|
|
1131
1151
|
return {
|
|
1132
|
-
type:
|
|
1152
|
+
type: 'normalCode',
|
|
1133
1153
|
asset,
|
|
1134
1154
|
selected: false,
|
|
1135
1155
|
state: this.getWalletAssetsState()
|
|
@@ -397,6 +397,7 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
397
397
|
refreshWalletAssets(params?: {
|
|
398
398
|
order_wait_pay_amount?: number;
|
|
399
399
|
preserveSelection?: boolean;
|
|
400
|
+
retainSearchResultCodes?: string[];
|
|
400
401
|
}): Promise<WalletAssetsState>;
|
|
401
402
|
/** 选择或取消单张钱包资产,并立即同步 pending wallet payments。 */
|
|
402
403
|
selectWalletAsset(params: {
|
|
@@ -3013,7 +3013,8 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3013
3013
|
await this.publishWalletAssetsState(clearedState);
|
|
3014
3014
|
}
|
|
3015
3015
|
const refreshTask = wallet.refreshWalletAssetsFromBusinessAsync(businessData, {
|
|
3016
|
-
preserveSelection: params?.preserveSelection !== false && !customerChanged
|
|
3016
|
+
preserveSelection: params?.preserveSelection !== false && !customerChanged,
|
|
3017
|
+
retainSearchResultCodes: params?.retainSearchResultCodes
|
|
3017
3018
|
});
|
|
3018
3019
|
await this.publishWalletAssetsState(wallet.getWalletAssetsState());
|
|
3019
3020
|
let state = await refreshTask;
|
|
@@ -3165,10 +3166,24 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
3165
3166
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
3166
3167
|
const beforePayments = (0, _lodashEs.cloneDeep)(this.store.order.getOrderPayments());
|
|
3167
3168
|
const pendingWalletAmount = this.getPendingWalletPaymentAmount(beforePayments);
|
|
3169
|
+
const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
|
|
3168
3170
|
if (pendingWalletAmount.lte(0)) {
|
|
3169
|
-
|
|
3171
|
+
this.logWarning('confirmWalletPayment: 未发现待确认 Wallet 支付,跳过 Wallet 确认并按普通订单提交', {
|
|
3172
|
+
amountGap: amountSnapshot?.amountGap
|
|
3173
|
+
});
|
|
3174
|
+
const submitResult = await this.submitSalesOrder({
|
|
3175
|
+
smallTicketDataFlag: 1
|
|
3176
|
+
});
|
|
3177
|
+
if (isRejectedSalesSubmitResult(submitResult)) {
|
|
3178
|
+
throw new Error(getSalesSubmitErrorMessage(submitResult, '订单提交失败'));
|
|
3179
|
+
}
|
|
3180
|
+
const latestAmountSnapshot = this.store.order.getOrderAmountSnapshot?.();
|
|
3181
|
+
return {
|
|
3182
|
+
submitResult,
|
|
3183
|
+
payments: this.store.order.getOrderPayments(),
|
|
3184
|
+
isOrderFullyPaid: new _decimal.default(latestAmountSnapshot?.amountGap || 0).lte(0)
|
|
3185
|
+
};
|
|
3170
3186
|
}
|
|
3171
|
-
const amountSnapshot = this.store.order.getOrderAmountSnapshot?.();
|
|
3172
3187
|
const effectiveAmountDue = _decimal.default.max(new _decimal.default(amountSnapshot?.amountGap || 0).minus(pendingWalletAmount), 0);
|
|
3173
3188
|
if (effectiveAmountDue.gt(0.01)) {
|
|
3174
3189
|
throw new Error('Wallet 支付尚未覆盖全部待支付金额');
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -33,6 +33,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
33
33
|
protected loadOpenDataInFlight: Promise<OpenDataConfig> | null;
|
|
34
34
|
protected loadOpenDataInFlightTarget: string | null;
|
|
35
35
|
protected openDataTarget: string | null;
|
|
36
|
+
private readonly customerResolveRequests;
|
|
36
37
|
/**
|
|
37
38
|
* 在 BaseSales 默认模块清单(products/order/salesSummary/schedule)基础上追加 customer + bookingContext。
|
|
38
39
|
* bookingContext 是 SalesSdk 加车下沉所需的「预约 UI 上下文」(bookingConfig / resourcesOrigin / date)。
|
|
@@ -78,10 +79,8 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
|
|
|
78
79
|
resolveCustomerById(customerId: string | number): Promise<ICustomer | null>;
|
|
79
80
|
/** 兼容既有优惠码扫码逻辑。 */
|
|
80
81
|
private resolveCustomerByDiscountCustomerId;
|
|
81
|
-
private findCustomerById;
|
|
82
82
|
private normalizeCustomer;
|
|
83
83
|
private getRawCustomerId;
|
|
84
|
-
private hasUsableCustomerDetails;
|
|
85
84
|
/**
|
|
86
85
|
* 更新当前预约的 appointment_status。
|
|
87
86
|
*
|
|
@@ -164,6 +164,7 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
164
164
|
loadOpenDataInFlight = null;
|
|
165
165
|
loadOpenDataInFlightTarget = null;
|
|
166
166
|
openDataTarget = null;
|
|
167
|
+
customerResolveRequests = new Map();
|
|
167
168
|
|
|
168
169
|
/**
|
|
169
170
|
* 在 BaseSales 默认模块清单(products/order/salesSummary/schedule)基础上追加 customer + bookingContext。
|
|
@@ -442,7 +443,15 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
442
443
|
|
|
443
444
|
// 缺 Holder 等场景 isAvailable=false,但仍需把 Pass 归属客户带入订单,供 Holder 弹窗使用。
|
|
444
445
|
if (!hasOrderCustomer && extractedCustomerId && !isUserPlatform) {
|
|
445
|
-
|
|
446
|
+
try {
|
|
447
|
+
await this.hydrateOrderCustomerFromScanDiscounts(scannedList);
|
|
448
|
+
} catch (error) {
|
|
449
|
+
// 客户映射失败不能阻断原有 Pass 的可用性、展示或优惠处理。
|
|
450
|
+
console.warn('[BookingTicket] scan discount customer resolve failed', {
|
|
451
|
+
customerId: extractedCustomerId,
|
|
452
|
+
error
|
|
453
|
+
});
|
|
454
|
+
}
|
|
446
455
|
}
|
|
447
456
|
if (raw.isAvailable) {
|
|
448
457
|
await this.store.order.recalculateSummary({
|
|
@@ -493,43 +502,39 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
493
502
|
return null;
|
|
494
503
|
}
|
|
495
504
|
async resolveCustomerById(customerId) {
|
|
496
|
-
const
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
if (normalizedLocalCustomer && this.hasUsableCustomerDetails(normalizedLocalCustomer)) {
|
|
500
|
-
return normalizedLocalCustomer;
|
|
501
|
-
}
|
|
502
|
-
const result = await this.store.customer.queryCustomerList({
|
|
503
|
-
ids: [customerId],
|
|
504
|
-
skip: 1,
|
|
505
|
-
num: 1
|
|
506
|
-
});
|
|
507
|
-
const remoteCustomer = this.findCustomerById(result?.list || [], customerId) || result?.list?.[0] || null;
|
|
508
|
-
if (remoteCustomer) {
|
|
509
|
-
return this.normalizeCustomer(remoteCustomer);
|
|
510
|
-
}
|
|
511
|
-
try {
|
|
512
|
-
const detailCustomer = await this.store.customer.queryCustomerDetail(customerId);
|
|
513
|
-
return detailCustomer ? this.normalizeCustomer(detailCustomer) : null;
|
|
514
|
-
} catch (error) {
|
|
515
|
-
console.warn('[BookingTicket] resolveCustomerById detail request failed', {
|
|
516
|
-
customerId,
|
|
517
|
-
error
|
|
518
|
-
});
|
|
505
|
+
const rawCustomerId = String(customerId ?? '').trim();
|
|
506
|
+
const numericCustomerId = Number(rawCustomerId);
|
|
507
|
+
if (!rawCustomerId || !Number.isInteger(numericCustomerId) || numericCustomerId <= 1) {
|
|
519
508
|
return null;
|
|
520
509
|
}
|
|
510
|
+
const normalizedCustomerId = String(numericCustomerId);
|
|
511
|
+
const existingRequest = this.customerResolveRequests.get(normalizedCustomerId);
|
|
512
|
+
if (existingRequest) return existingRequest;
|
|
513
|
+
const request = this.request.post(`/customer/resolve/${encodeURIComponent(normalizedCustomerId)}`, {
|
|
514
|
+
with_franchisor_data: 1,
|
|
515
|
+
with: ['latestWalletDetail.wallet', 'contactsInfo', 'formRecord']
|
|
516
|
+
}).then(result => {
|
|
517
|
+
const customer = result?.data;
|
|
518
|
+
const resolvedCustomerId = Number(customer && typeof customer === 'object' && !Array.isArray(customer) ? this.getRawCustomerId(customer) : NaN);
|
|
519
|
+
if (result?.status !== true || result?.code !== 200 || !customer || typeof customer !== 'object' || Array.isArray(customer) || !Number.isInteger(resolvedCustomerId) || resolvedCustomerId <= 1) {
|
|
520
|
+
const error = new Error(result?.message || 'Customer resolve failed');
|
|
521
|
+
error.code = result?.code;
|
|
522
|
+
throw error;
|
|
523
|
+
}
|
|
524
|
+
return this.normalizeCustomer(customer);
|
|
525
|
+
}).finally(() => {
|
|
526
|
+
if (this.customerResolveRequests.get(normalizedCustomerId) === request) {
|
|
527
|
+
this.customerResolveRequests.delete(normalizedCustomerId);
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
this.customerResolveRequests.set(normalizedCustomerId, request);
|
|
531
|
+
return request;
|
|
521
532
|
}
|
|
522
533
|
|
|
523
534
|
/** 兼容既有优惠码扫码逻辑。 */
|
|
524
535
|
resolveCustomerByDiscountCustomerId(customerId) {
|
|
525
536
|
return this.resolveCustomerById(customerId);
|
|
526
537
|
}
|
|
527
|
-
findCustomerById(customers = [], customerId) {
|
|
528
|
-
return customers.find(customer => {
|
|
529
|
-
const rawId = this.getRawCustomerId(customer);
|
|
530
|
-
return rawId !== null && String(rawId) === String(customerId);
|
|
531
|
-
}) || null;
|
|
532
|
-
}
|
|
533
538
|
normalizeCustomer(customer) {
|
|
534
539
|
const raw = customer;
|
|
535
540
|
const rawId = this.getRawCustomerId(customer);
|
|
@@ -547,9 +552,6 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
547
552
|
const raw = customer;
|
|
548
553
|
return customer.id ?? raw.customer_id ?? raw.customerId ?? null;
|
|
549
554
|
}
|
|
550
|
-
hasUsableCustomerDetails(customer) {
|
|
551
|
-
return !!(customer.name || customer.phone || customer.email || customer.display_name || customer.customer_name);
|
|
552
|
-
}
|
|
553
555
|
|
|
554
556
|
/**
|
|
555
557
|
* 更新当前预约的 appointment_status。
|
|
@@ -1669,6 +1671,7 @@ class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
|
1669
1671
|
const result = await (0, _applyGlobalScan.applyGlobalScan)({
|
|
1670
1672
|
setOrderCustomer: customer => this.setOrderCustomer(customer),
|
|
1671
1673
|
getOrderCustomerSnapshot: () => this.getOrderCustomerSnapshot(),
|
|
1674
|
+
resolveCustomerById: customerId => this.resolveCustomerById(customerId),
|
|
1672
1675
|
getBusinessCode: () => this.otherParams?.businessCode,
|
|
1673
1676
|
buildAddProductCtx: extra => this.buildAddProductCtx(extra),
|
|
1674
1677
|
decideAddProduct: (item, options) => this.decideAddProduct(item, options),
|
|
@@ -5,6 +5,7 @@ import { GlobalScanFormattedResult } from './formatGlobalScan';
|
|
|
5
5
|
export interface GlobalScanApplyHost {
|
|
6
6
|
setOrderCustomer(customer: ICustomer | null): void;
|
|
7
7
|
getOrderCustomerSnapshot(): ICustomer | null;
|
|
8
|
+
resolveCustomerById?(customerId: string | number): Promise<ICustomer | null>;
|
|
8
9
|
getBusinessCode(): string | undefined;
|
|
9
10
|
buildAddProductCtx(extra?: Record<string, any>): Record<string, any>;
|
|
10
11
|
decideAddProduct(item: any, options?: Record<string, any>): AddProductDecision;
|
|
@@ -26,6 +27,7 @@ export interface GlobalScanApplyHost {
|
|
|
26
27
|
addProductToOrder(product: any, booking?: any): Promise<any>;
|
|
27
28
|
refreshWalletAssets?(params?: {
|
|
28
29
|
preserveSelection?: boolean;
|
|
30
|
+
retainSearchResultCodes?: string[];
|
|
29
31
|
}): Promise<any>;
|
|
30
32
|
scanWalletAsset?(code: string): Promise<{
|
|
31
33
|
type: 'walletCode' | 'normalCode';
|