@pisell/pisellos 0.10.40 → 0.10.42

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.
Files changed (73) hide show
  1. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +58 -19
  2. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +24 -12
  3. package/dist/modules/Customer/index.js +4 -2
  4. package/dist/modules/Customer/types.d.ts +2 -0
  5. package/dist/modules/Discount/entitlementPass.d.ts +34 -0
  6. package/dist/modules/Discount/entitlementPass.js +147 -0
  7. package/dist/modules/Discount/index.d.ts +2 -0
  8. package/dist/modules/Discount/index.js +39 -13
  9. package/dist/modules/Discount/types.d.ts +26 -5
  10. package/dist/modules/Order/index.d.ts +6 -1
  11. package/dist/modules/Order/index.js +283 -118
  12. package/dist/modules/Order/utils/orderCollectionIdentity.js +16 -12
  13. package/dist/modules/Order/utils.js +17 -1
  14. package/dist/modules/Payment/types.d.ts +21 -1
  15. package/dist/modules/Payment/types.js +2 -0
  16. package/dist/modules/Payment/walletpass.d.ts +1 -1
  17. package/dist/modules/Payment/walletpass.js +80 -47
  18. package/dist/modules/ResourcePlanner/planner.d.ts +2 -2
  19. package/dist/modules/ResourcePlanner/planner.js +163 -46
  20. package/dist/modules/ResourcePlanner/types.d.ts +17 -0
  21. package/dist/modules/Rules/index.js +310 -134
  22. package/dist/solution/BaseSales/index.d.ts +3 -0
  23. package/dist/solution/BaseSales/index.js +11 -2
  24. package/dist/solution/BaseSales/utils/cartPromotion.js +141 -126
  25. package/dist/solution/BookingByStep/index.d.ts +2 -2
  26. package/dist/solution/BookingTicket/index.d.ts +1 -2
  27. package/dist/solution/BookingTicket/index.js +60 -63
  28. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +2 -0
  29. package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +266 -150
  30. package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +7 -3
  31. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +4 -0
  32. package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +8 -4
  33. package/dist/solution/ShopDiscount/index.d.ts +1 -0
  34. package/dist/solution/ShopDiscount/index.js +41 -21
  35. package/dist/solution/ShopDiscount/utils.js +3 -2
  36. package/dist/solution/UnifiedBookingSales/index.js +94 -21
  37. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +35 -6
  38. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +13 -6
  39. package/lib/modules/Customer/index.js +4 -1
  40. package/lib/modules/Customer/types.d.ts +2 -0
  41. package/lib/modules/Discount/entitlementPass.d.ts +34 -0
  42. package/lib/modules/Discount/entitlementPass.js +141 -0
  43. package/lib/modules/Discount/index.d.ts +2 -0
  44. package/lib/modules/Discount/index.js +25 -9
  45. package/lib/modules/Discount/types.d.ts +26 -5
  46. package/lib/modules/Order/index.d.ts +6 -1
  47. package/lib/modules/Order/index.js +172 -28
  48. package/lib/modules/Order/utils/orderCollectionIdentity.js +14 -11
  49. package/lib/modules/Order/utils.js +19 -1
  50. package/lib/modules/Payment/types.d.ts +21 -1
  51. package/lib/modules/Payment/types.js +1 -0
  52. package/lib/modules/Payment/walletpass.d.ts +1 -1
  53. package/lib/modules/Payment/walletpass.js +29 -9
  54. package/lib/modules/ResourcePlanner/planner.d.ts +2 -2
  55. package/lib/modules/ResourcePlanner/planner.js +137 -35
  56. package/lib/modules/ResourcePlanner/types.d.ts +17 -0
  57. package/lib/modules/Rules/index.js +230 -96
  58. package/lib/solution/BaseSales/index.d.ts +3 -0
  59. package/lib/solution/BaseSales/index.js +9 -2
  60. package/lib/solution/BaseSales/utils/cartPromotion.js +12 -4
  61. package/lib/solution/BookingByStep/index.d.ts +2 -2
  62. package/lib/solution/BookingTicket/index.d.ts +1 -2
  63. package/lib/solution/BookingTicket/index.js +36 -33
  64. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +2 -0
  65. package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +127 -42
  66. package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +7 -3
  67. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +4 -0
  68. package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +7 -3
  69. package/lib/solution/ShopDiscount/index.d.ts +1 -0
  70. package/lib/solution/ShopDiscount/index.js +26 -6
  71. package/lib/solution/ShopDiscount/utils.js +3 -2
  72. package/lib/solution/UnifiedBookingSales/index.js +86 -22
  73. package/package.json +1 -1
@@ -17,6 +17,7 @@ exports.normalizeOrderCollections = normalizeOrderCollections;
17
17
  exports.repairDuplicateProductLineIdentities = repairDuplicateProductLineIdentities;
18
18
  exports.setOrderCollectionUid = setOrderCollectionUid;
19
19
  var _lodashEs = require("lodash-es");
20
+ var _entitlementPass = require("../../Discount/entitlementPass");
20
21
  const IDENTITY_CONFIG = {
21
22
  product: {
22
23
  persistentIdField: 'order_detail_id',
@@ -81,20 +82,22 @@ function setOrderCollectionUid(kind, item, uid) {
81
82
  delete record[uidField];
82
83
  return record;
83
84
  }
84
- function getGoodPassResourceId(product) {
85
- const goodPass = (product.discount_list || []).find(item => {
86
- const type = item?.type || item?.tag || item?.discount?.type || item?.discount?.tag;
87
- return type === 'good_pass';
88
- });
89
- if (!goodPass) return null;
90
- const resourceId = goodPass.discount?.resource_id ?? goodPass.resource_id ?? goodPass.discount_id ?? goodPass.id;
91
- return isBlankOrderCollectionIdentity(resourceId) ? null : String(resourceId);
85
+ function getFullCoveragePassIdentity(product) {
86
+ const pass = (product.discount_list || []).find(item => (0, _entitlementPass.isFullCoveragePass)(item));
87
+ if (!pass) return null;
88
+ const resourceId = pass.discount?.resource_id ?? pass.resource_id ?? pass.discount_id ?? pass.id;
89
+ if (isBlankOrderCollectionIdentity(resourceId)) return null;
90
+ return {
91
+ type: String(pass.type || pass.tag),
92
+ resourceId: String(resourceId)
93
+ };
92
94
  }
93
95
  function buildSplitProductUid(originalUid, product, duplicateOrdinal) {
94
96
  const encodedOriginalUid = encodeURIComponent(originalUid);
95
- const resourceId = getGoodPassResourceId(product);
96
- if (resourceId) {
97
- return `os-split:product:${encodedOriginalUid}:good-pass:${encodeURIComponent(resourceId)}:${duplicateOrdinal}`;
97
+ const passIdentity = getFullCoveragePassIdentity(product);
98
+ if (passIdentity) {
99
+ const passType = passIdentity.type === 'good_pass' ? 'good-pass' : 'entitlement-pass';
100
+ return `os-split:product:${encodedOriginalUid}:${passType}:${encodeURIComponent(passIdentity.resourceId)}:${duplicateOrdinal}`;
98
101
  }
99
102
  return `os-split:product:${encodedOriginalUid}:duplicate:${duplicateOrdinal}`;
100
103
  }
@@ -564,6 +564,24 @@ function resolveSubmitBundleMapId(bundle) {
564
564
  }
565
565
  return undefined;
566
566
  }
567
+ function ensureSubmitDiscountIdentity(discount) {
568
+ if (!discount || typeof discount !== 'object' || Array.isArray(discount)) {
569
+ return discount;
570
+ }
571
+ const discountRecord = discount;
572
+ const metadata = discountRecord.metadata && typeof discountRecord.metadata === 'object' && !Array.isArray(discountRecord.metadata) ? discountRecord.metadata : {};
573
+ const uniqueIdentificationNumber = metadata.unique_identification_number;
574
+ if (uniqueIdentificationNumber !== undefined && uniqueIdentificationNumber !== null && String(uniqueIdentificationNumber).trim() !== '') {
575
+ return discount;
576
+ }
577
+ return {
578
+ ...discountRecord,
579
+ metadata: {
580
+ ...metadata,
581
+ unique_identification_number: (0, _orderCollectionIdentity.createUuidV4)()
582
+ }
583
+ };
584
+ }
567
585
  function collectSubmitProductDiscountList(product) {
568
586
  const submitDiscountList = Array.isArray(product?.discount_list) ? [...product.discount_list] : [];
569
587
  for (const bundle of product?.product_bundle || []) {
@@ -585,7 +603,7 @@ function collectSubmitProductDiscountList(product) {
585
603
  });
586
604
  }
587
605
  }
588
- return normalizeOrderProductDiscountList(submitDiscountList);
606
+ return normalizeOrderProductDiscountList(submitDiscountList.map(ensureSubmitDiscountIdentity));
589
607
  }
590
608
 
591
609
  /**
@@ -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: SearchIdentificationCodeItem[];
899
+ data: WalletDetailSearchData;
880
900
  } | {
881
901
  type: 'normalCode';
882
902
  data: SearchIdentificationCodeItem[];
@@ -221,6 +221,7 @@ let PaymentHooks = exports.PaymentHooks = /*#__PURE__*/function (PaymentHooks) {
221
221
  /**
222
222
  * 搜索识别码响应数据
223
223
  */
224
+ /** Wallet code 精确搜索返回的 Wallet Detail。 */
224
225
  /**
225
226
  * 搜索识别码结果类型
226
227
  */
@@ -96,7 +96,7 @@ export declare class WalletPassPaymentImpl implements WalletPassPayment {
96
96
  * 搜索识别码信息
97
97
  * 通过识别码搜索相关的钱包通行证信息
98
98
  * 基于 WalletDeductionRecommendParams 参数结构
99
- * 特殊逻辑:当识别码长度为9位且前3位为"000"时,调用 /wallet/detail/search 接口
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
- * 特殊逻辑:当识别码长度为9位且前3位为"000"时,调用 /wallet/detail/search 接口
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 searchResults = response?.data || [];
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: searchResults.length,
743
+ results_count: 1,
740
744
  type: 'walletCode'
741
745
  });
742
746
  return {
743
747
  type: 'walletCode',
744
- data: searchResults
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 = preserveSelection ? this.getSearchedWalletAssetCodes() : [];
905
- const useAggregateRecalculate = preserveSelection && (selectedIds.length > 0 || searchedWalletAssetCodes.length > 0);
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 = preserveSelection ? this.syncSearchedWalletAssets([...(result.transformList || []), ...(result.noApplicableVoucher || [])]) : [];
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 || result.type === 'walletCode') {
1150
+ if (!asset) {
1131
1151
  return {
1132
- type: result.type,
1152
+ type: 'normalCode',
1133
1153
  asset,
1134
1154
  selected: false,
1135
1155
  state: this.getWalletAssetsState()
@@ -1,5 +1,5 @@
1
1
  import type { AvailabilityProjection, AvailabilityProjectionInput, AvailabilityQuery, AvailabilityQueryResult, AvailabilitySelectionValidationParams, AvailabilitySelectionValidationResult, GetProductTimeRangesRequest, GetProductTimeRangesRuntimeOptions, ProductTimeRangeGroup } from './types';
2
2
  export declare function createAvailabilityProjection(input: AvailabilityProjectionInput): AvailabilityProjection;
3
3
  export declare function getProductTimeRanges(projection: AvailabilityProjection, request?: GetProductTimeRangesRequest, runtimeOptions?: GetProductTimeRangesRuntimeOptions): ProductTimeRangeGroup[];
4
- export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery): AvailabilityQueryResult;
5
- export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams): AvailabilitySelectionValidationResult;
4
+ export declare function queryAvailabilityProjection(projection: AvailabilityProjection, request: AvailabilityQuery, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilityQueryResult;
5
+ export declare function validateAvailabilitySelection(projection: AvailabilityProjection, params: AvailabilitySelectionValidationParams, runtimeOptions?: GetProductTimeRangesRuntimeOptions): AvailabilitySelectionValidationResult;