@pisell/pisellos 0.10.21 → 0.10.23

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/index.d.ts +3 -0
  2. package/dist/modules/BookingContext/index.js +42 -13
  3. package/dist/modules/BookingContext/types.d.ts +4 -4
  4. package/dist/modules/BookingContext/types.js +3 -3
  5. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
  6. package/dist/modules/OpenData/index.d.ts +1 -0
  7. package/dist/modules/OpenData/index.js +28 -9
  8. package/dist/modules/Order/index.d.ts +5 -0
  9. package/dist/modules/Order/index.js +148 -84
  10. package/dist/modules/ProductList/clientDataVariants.d.ts +50 -0
  11. package/dist/modules/ProductList/clientDataVariants.js +216 -0
  12. package/dist/modules/ProductList/index.d.ts +14 -13
  13. package/dist/modules/ProductList/index.js +105 -77
  14. package/dist/modules/Quotation/index.d.ts +16 -0
  15. package/dist/modules/Quotation/index.js +240 -27
  16. package/dist/modules/ResourcePlanner/planner.d.ts +2 -2
  17. package/dist/modules/ResourcePlanner/planner.js +88 -21
  18. package/dist/modules/ResourcePlanner/types.d.ts +12 -0
  19. package/dist/modules/Rules/index.d.ts +5 -0
  20. package/dist/modules/Rules/index.js +27 -12
  21. package/dist/solution/BaseSales/index.d.ts +16 -1
  22. package/dist/solution/BaseSales/index.js +667 -349
  23. package/dist/solution/BookingByStep/index.d.ts +1 -1
  24. package/dist/solution/BookingTicket/index.d.ts +1 -1
  25. package/dist/solution/Sales/index.js +5 -3
  26. package/dist/solution/UnifiedBookingSales/index.d.ts +1 -1
  27. package/dist/solution/UnifiedBookingSales/index.js +290 -81
  28. package/dist/solution/UnifiedBookingSales/types.d.ts +4 -0
  29. package/dist/solution/VenueBooking/index.d.ts +2 -0
  30. package/dist/solution/VenueBooking/index.js +542 -494
  31. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  32. package/dist/solution/VenueBooking/utils/dateSummary.js +3 -1
  33. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +2 -0
  34. package/dist/solution/VenueBooking/utils/slotMerge.js +3 -1
  35. package/dist/utils/platform.d.ts +8 -0
  36. package/dist/utils/platform.js +15 -0
  37. package/lib/modules/BookingContext/index.d.ts +3 -0
  38. package/lib/modules/BookingContext/index.js +35 -8
  39. package/lib/modules/BookingContext/types.d.ts +4 -4
  40. package/lib/modules/BookingContext/types.js +3 -3
  41. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
  42. package/lib/modules/OpenData/index.d.ts +1 -0
  43. package/lib/modules/OpenData/index.js +13 -0
  44. package/lib/modules/Order/index.d.ts +5 -0
  45. package/lib/modules/Order/index.js +65 -8
  46. package/lib/modules/ProductList/clientDataVariants.d.ts +50 -0
  47. package/lib/modules/ProductList/clientDataVariants.js +204 -0
  48. package/lib/modules/ProductList/index.d.ts +14 -13
  49. package/lib/modules/ProductList/index.js +77 -58
  50. package/lib/modules/Quotation/index.d.ts +16 -0
  51. package/lib/modules/Quotation/index.js +112 -9
  52. package/lib/modules/ResourcePlanner/planner.d.ts +2 -2
  53. package/lib/modules/ResourcePlanner/planner.js +80 -20
  54. package/lib/modules/ResourcePlanner/types.d.ts +12 -0
  55. package/lib/modules/Rules/index.d.ts +5 -0
  56. package/lib/modules/Rules/index.js +20 -11
  57. package/lib/solution/BaseSales/index.d.ts +16 -1
  58. package/lib/solution/BaseSales/index.js +293 -66
  59. package/lib/solution/BookingByStep/index.d.ts +1 -1
  60. package/lib/solution/BookingTicket/index.d.ts +1 -1
  61. package/lib/solution/Sales/index.js +2 -1
  62. package/lib/solution/UnifiedBookingSales/index.d.ts +1 -1
  63. package/lib/solution/UnifiedBookingSales/index.js +225 -20
  64. package/lib/solution/UnifiedBookingSales/types.d.ts +4 -0
  65. package/lib/solution/VenueBooking/index.d.ts +2 -0
  66. package/lib/solution/VenueBooking/index.js +28 -8
  67. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  68. package/lib/solution/VenueBooking/utils/dateSummary.js +3 -1
  69. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +2 -0
  70. package/lib/solution/VenueBooking/utils/slotMerge.js +3 -1
  71. package/lib/utils/platform.d.ts +8 -0
  72. package/lib/utils/platform.js +22 -0
  73. package/package.json +1 -1
@@ -30,6 +30,8 @@ var _paymentUtils = require("../../modules/Order/payment-utils");
30
30
  var _paymentNumber = require("../../utils/payment-number");
31
31
  var _orderCollectionIdentity = require("../../modules/Order/utils/orderCollectionIdentity");
32
32
  var _dayjs = _interopRequireDefault(require("dayjs"));
33
+ var _clientDataVariants = require("../../modules/ProductList/clientDataVariants");
34
+ var _platform = require("../../utils/platform");
33
35
  var _Quotation = require("../../modules/Quotation");
34
36
  var _transformBaseProductToOrderProduct = require("./utils/transformBaseProductToOrderProduct");
35
37
  var _quotationPrice = require("./utils/quotationPrice");
@@ -662,8 +664,10 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
662
664
  async loadQuotationForPriceQuery(params) {
663
665
  if (!params.quotation) return;
664
666
  this.applyQuotationScheduleResolver(params.quotation);
665
- await params.quotation.loadQuotations({
666
- channel: params.channel || this.otherParams?.channel,
667
+ const quotation = params.quotation;
668
+ const load = typeof quotation.ensureQuotations === 'function' ? quotation.ensureQuotations.bind(quotation) : quotation.loadQuotations.bind(quotation);
669
+ await load({
670
+ channel: this.getPriceQueryChannel(params.channel),
667
671
  customer_id: params.customer_id
668
672
  });
669
673
  }
@@ -745,34 +749,175 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
745
749
  schedule_datetime: now.format('YYYY-MM-DD HH:mm:ss')
746
750
  };
747
751
  }
752
+ isCustomerUserPriceQuery() {
753
+ return (0, _platform.isCustomerUserPlatform)(this.otherParams?.platform);
754
+ }
755
+ getPriceQueryScheduleList() {
756
+ const storeScheduleList = this.store.schedule?.getScheduleList?.();
757
+ if (Array.isArray(storeScheduleList) && storeScheduleList.length > 0) {
758
+ return storeScheduleList;
759
+ }
760
+ const contextScheduleList = this.core?.context?.scheduleList;
761
+ return Array.isArray(contextScheduleList) && contextScheduleList.length > 0 ? contextScheduleList : undefined;
762
+ }
763
+ buildPriceQueryPayload(params) {
764
+ const channel = this.getPriceQueryChannel(params.channel);
765
+ const strategyContext = this.getPriceQueryStrategyContext(channel);
766
+ return {
767
+ ids: params.ids,
768
+ ...(this.isCustomerUserPriceQuery() ? {} : {
769
+ open_quotation: 1
770
+ }),
771
+ open_bundle: 1,
772
+ with: [..._clientDataVariants.PRODUCT_QUERY_DATA_VARIANT_RELATIONS],
773
+ status: 'published',
774
+ num: Math.max(params.ids.length, 1),
775
+ skip: 1,
776
+ customer_id: params.customerId,
777
+ schedule_date: params.schedule.schedule_date,
778
+ schedule_datetime: params.schedule.schedule_datetime,
779
+ application_code: channel,
780
+ ...(Object.keys(strategyContext).length ? {
781
+ strategy_context: strategyContext
782
+ } : {})
783
+ };
784
+ }
785
+ getRawProductPriceSources(ids) {
786
+ const products = this.store.products;
787
+ if (typeof products?.getRawProductPriceSources !== 'function') {
788
+ return new Map();
789
+ }
790
+ try {
791
+ const result = products.getRawProductPriceSources(ids);
792
+ return result instanceof Map ? result : new Map();
793
+ } catch (error) {
794
+ this.logWarning('getRawProductPriceSources: 读取商品原始报价源失败', {
795
+ ids,
796
+ error: error instanceof Error ? error.message : String(error)
797
+ });
798
+ return new Map();
799
+ }
800
+ }
801
+ rememberRawProductPriceSources(products) {
802
+ const productList = this.store.products;
803
+ if (typeof productList?.rememberRawProductQueryResult !== 'function') return;
804
+ try {
805
+ productList.rememberRawProductQueryResult(products);
806
+ } catch (error) {
807
+ this.logWarning('rememberRawProductPriceSources: 保存商品原始报价源失败', {
808
+ error: error instanceof Error ? error.message : String(error)
809
+ });
810
+ }
811
+ }
812
+ getSelectedProductVariantId(product) {
813
+ const variantId = Number(product?.product_variant_id ?? product?.variant_id ?? 0);
814
+ return Number.isFinite(variantId) && variantId > 0 ? variantId : 0;
815
+ }
816
+
817
+ /**
818
+ * 将目录原始商品还原为本次选择的 SKU 基线。
819
+ *
820
+ * 这里绝不能复用已评估后的目录商品,否则从命中智能价切回不命中的
821
+ * 日期时会残留旧价格。套餐仅验证所选关系存在,最终仍由 merge 方法把
822
+ * 评估后的套餐价格映射回用户的选择数据。
823
+ */
824
+ prepareRawProductForPriceQuery(rawProduct, selectedProduct) {
825
+ const product = (0, _lodashEs.cloneDeep)(rawProduct);
826
+ const rawProductId = this.getPriceQueryProductId(product);
827
+ const selectedProductId = this.getPriceQueryProductId(selectedProduct);
828
+ if (rawProductId === null || selectedProductId === null || rawProductId !== selectedProductId) {
829
+ return null;
830
+ }
831
+ const selectedVariantId = this.getSelectedProductVariantId(selectedProduct);
832
+ product.product_id = product.product_id ?? product.id;
833
+ product.product_variant_id = selectedVariantId;
834
+ product.variant_id = selectedVariantId;
835
+ if (selectedVariantId > 0) {
836
+ const variants = Array.isArray(product.variant) ? product.variant : [];
837
+ const selectedVariant = variants.find(variant => Number(variant?.id) === selectedVariantId);
838
+ if (!selectedVariant) return null;
839
+ const variantPrice = selectedVariant.price ?? selectedVariant.selling_price ?? selectedVariant.base_price;
840
+ if (variantPrice === undefined || variantPrice === null || variantPrice === '') {
841
+ return null;
842
+ }
843
+ product.price = variantPrice;
844
+ product.selling_price = selectedVariant.selling_price ?? variantPrice;
845
+ product.base_price = selectedVariant.base_price ?? variantPrice;
846
+ }
847
+ const selectedBundles = Array.isArray(selectedProduct.product_bundle) ? selectedProduct.product_bundle : [];
848
+ if (selectedBundles.length > 0) {
849
+ const rawBundleItems = this.getAuthoritativeBundleItems(product);
850
+ const allSelectedBundlesExist = selectedBundles.every(bundle => {
851
+ const authoritativeBundle = this.findAuthoritativeBundleItem(bundle, rawBundleItems);
852
+ if (!authoritativeBundle) return false;
853
+ const selectedBundleVariantId = Number(bundle?.bundle_variant_id ?? bundle?.variant_id ?? 0);
854
+ const authoritativeBundleVariantId = Number(authoritativeBundle?.bundle_variant_id ?? authoritativeBundle?.variant_id ?? 0);
855
+ if ((Number.isFinite(selectedBundleVariantId) ? selectedBundleVariantId : 0) !== (Number.isFinite(authoritativeBundleVariantId) ? authoritativeBundleVariantId : 0)) {
856
+ return false;
857
+ }
858
+
859
+ // 省略字段表示该套餐子商品关系没有被价格查询完整水合,不能把它
860
+ // 当作“没有规则”而静默使用基础价。
861
+ return Array.isArray(authoritativeBundle.data_variants);
862
+ });
863
+ if (!allSelectedBundlesExist) return null;
864
+ }
865
+ return product;
866
+ }
867
+ resolveLocalProductForPriceQuery(params) {
868
+ if (!params.rawProduct) return null;
869
+ const preparedProduct = this.prepareRawProductForPriceQuery(params.rawProduct, params.selectedProduct);
870
+ if (!preparedProduct) return null;
871
+ const scheduleList = this.getPriceQueryScheduleList();
872
+ const result = (0, _clientDataVariants.tryResolveClientDataVariants)({
873
+ core: this.core,
874
+ otherParams: this.otherParams,
875
+ products: [preparedProduct],
876
+ queryPayload: params.queryPayload,
877
+ handledByOsServer: false,
878
+ ...(scheduleList ? {
879
+ scheduleList
880
+ } : {})
881
+ });
882
+ if (result.status !== 'resolved') return null;
883
+ return result.products[0] || null;
884
+ }
748
885
  async loadProductsForPriceQuery(params) {
749
886
  const ids = Array.from(new Set(params.ids.filter(id => Number.isFinite(id))));
750
887
  const productsById = new Map();
751
888
  if (!ids.length || !this.request) return productsById;
752
- const channel = this.getPriceQueryChannel(params.channel);
753
- const strategyContext = this.getPriceQueryStrategyContext(channel);
889
+ const handledByOsServer = (0, _clientDataVariants.isProductQueryHandledByOsServer)(this.core, this.request);
754
890
  try {
755
- const response = await this.request.post('/product/query', {
756
- ids,
757
- open_quotation: 1,
758
- open_bundle: 1,
759
- status: 'published',
760
- num: 1,
761
- skip: 1,
762
- customer_id: params.customerId,
763
- schedule_date: params.schedule.schedule_date,
764
- schedule_datetime: params.schedule.schedule_datetime,
765
- application_code: channel,
766
- ...(Object.keys(strategyContext).length ? {
767
- strategy_context: strategyContext
768
- } : {})
769
- }, {
891
+ const queryPayload = this.buildPriceQueryPayload({
892
+ ...params,
893
+ ids
894
+ });
895
+ const response = await this.request.post('/product/query', queryPayload, {
770
896
  osServer: true,
771
897
  customToast: () => {}
772
898
  });
773
899
  const list = response?.data?.list || response?.list || [];
774
900
  if (!Array.isArray(list)) return productsById;
775
- list.forEach(item => {
901
+ if (this.isCustomerUserPriceQuery() && !handledByOsServer) {
902
+ this.rememberRawProductPriceSources(list);
903
+ list.forEach(item => {
904
+ const productId = Number(item?.id ?? item?.product_id);
905
+ if (Number.isFinite(productId)) productsById.set(productId, item);
906
+ });
907
+ return productsById;
908
+ }
909
+ const scheduleList = this.getPriceQueryScheduleList();
910
+ const resolvedList = (0, _clientDataVariants.resolveClientDataVariants)({
911
+ core: this.core,
912
+ otherParams: this.otherParams,
913
+ products: list,
914
+ queryPayload,
915
+ handledByOsServer,
916
+ ...(scheduleList ? {
917
+ scheduleList
918
+ } : {})
919
+ });
920
+ resolvedList.forEach(item => {
776
921
  const productId = Number(item?.id ?? item?.product_id);
777
922
  if (Number.isFinite(productId)) productsById.set(productId, item);
778
923
  });
@@ -785,18 +930,69 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
785
930
  return productsById;
786
931
  }
787
932
  }
788
- async loadProductForPriceQuery(params, customerId) {
789
- const product = params.product || {};
790
- const productId = this.getPriceQueryProductId(product);
791
- if (productId === null || !this.request) return null;
792
- const schedule = this.getPriceQuerySchedule(params);
793
- const productsById = await this.loadProductsForPriceQuery({
794
- ids: [productId],
795
- schedule,
796
- customerId,
933
+ async resolveProductsForPriceQuery(params) {
934
+ const selectedProducts = params.priceQueries.map(item => item.product || {});
935
+ const productIds = selectedProducts.map(product => this.getPriceQueryProductId(product));
936
+ const ids = Array.from(new Set(productIds.filter(id => id !== null)));
937
+ if (!ids.length) {
938
+ return selectedProducts.map(() => null);
939
+ }
940
+ const handledByOsServer = this.request ? (0, _clientDataVariants.isProductQueryHandledByOsServer)(this.core, this.request) : false;
941
+ const canUseLocalFastPath = this.isCustomerUserPriceQuery() && !handledByOsServer;
942
+ if (!canUseLocalFastPath) {
943
+ if (!this.request) return selectedProducts.map(() => null);
944
+ const productsById = await this.loadProductsForPriceQuery({
945
+ ids,
946
+ schedule: params.schedule,
947
+ customerId: params.customerId,
948
+ channel: params.channel
949
+ });
950
+ return productIds.map(productId => productId === null ? null : productsById.get(productId) || null);
951
+ }
952
+ const queryPayload = this.buildPriceQueryPayload({
953
+ ids,
954
+ schedule: params.schedule,
955
+ customerId: params.customerId,
956
+ channel: params.channel
957
+ });
958
+ const cachedRawProducts = this.getRawProductPriceSources(ids);
959
+ const authoritativeProducts = selectedProducts.map((selectedProduct, index) => {
960
+ const productId = productIds[index];
961
+ return productId === null ? null : this.resolveLocalProductForPriceQuery({
962
+ selectedProduct,
963
+ rawProduct: cachedRawProducts.get(productId),
964
+ queryPayload
965
+ });
966
+ });
967
+ const missingIds = Array.from(new Set(productIds.filter((productId, index) => productId !== null && !authoritativeProducts[index])));
968
+ if (!missingIds.length) return authoritativeProducts;
969
+ if (!this.request) return authoritativeProducts;
970
+ const remoteRawProducts = await this.loadProductsForPriceQuery({
971
+ ids: missingIds,
972
+ schedule: params.schedule,
973
+ customerId: params.customerId,
797
974
  channel: params.channel
798
975
  });
799
- return productsById.get(productId) || null;
976
+ authoritativeProducts.forEach((authoritativeProduct, index) => {
977
+ if (authoritativeProduct) return;
978
+ const productId = productIds[index];
979
+ if (productId === null) return;
980
+ const rawProduct = remoteRawProducts.get(productId);
981
+ const locallyResolved = this.resolveLocalProductForPriceQuery({
982
+ selectedProduct: selectedProducts[index],
983
+ rawProduct,
984
+ queryPayload
985
+ });
986
+ if (locallyResolved) {
987
+ authoritativeProducts[index] = locallyResolved;
988
+ return;
989
+ }
990
+
991
+ // 严格客户端能力仍不可用时,真实请求已经是最后的权威降级。
992
+ // 尽量应用所选 SKU 基线;关系不完整时保持旧的远端商品语义。
993
+ authoritativeProducts[index] = rawProduct ? this.prepareRawProductForPriceQuery(rawProduct, selectedProducts[index]) || rawProduct : null;
994
+ });
995
+ return authoritativeProducts;
800
996
  }
801
997
  getAuthoritativeBundleItems(product) {
802
998
  if (Array.isArray(product?.product_bundle)) return product.product_bundle;
@@ -3264,18 +3460,28 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3264
3460
  return (0, _transformBaseProductToOrderProduct.transformBaseProductToOrderProduct)(params);
3265
3461
  }
3266
3462
  async calculateProductBookingPrice(params) {
3267
- const quotation = this.store.quotation;
3463
+ const useCustomerUserPricing = this.isCustomerUserPriceQuery();
3464
+ const quotation = useCustomerUserPricing ? undefined : this.store.quotation;
3268
3465
  const customerId = params.customer_id ?? this.getCurrentOrderCustomerId();
3269
3466
  await this.prepareProductPriceQueryContext(customerId);
3270
- const authoritativeProduct = await this.loadProductForPriceQuery(params, customerId);
3271
- const product = this.mergeProductForPriceQuery(params.product, authoritativeProduct);
3272
- await this.loadQuotationForPriceQuery({
3273
- quotation,
3274
- customer_id: customerId,
3275
- channel: params.channel
3467
+ const channel = this.getPriceQueryChannel(params.channel);
3468
+ const [authoritativeProduct] = await this.resolveProductsForPriceQuery({
3469
+ priceQueries: [params],
3470
+ schedule: this.getPriceQuerySchedule(params),
3471
+ customerId,
3472
+ channel
3276
3473
  });
3474
+ const product = this.mergeProductForPriceQuery(params.product, authoritativeProduct);
3475
+ if (!useCustomerUserPricing) {
3476
+ await this.loadQuotationForPriceQuery({
3477
+ quotation,
3478
+ customer_id: customerId,
3479
+ channel
3480
+ });
3481
+ }
3277
3482
  return (0, _quotationPrice.calculateBaseSalesProductBookingPrice)({
3278
3483
  ...params,
3484
+ channel,
3279
3485
  product,
3280
3486
  fallback_price: authoritativeProduct ? undefined : params.fallback_price,
3281
3487
  customer_id: customerId,
@@ -3327,7 +3533,7 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3327
3533
  const scopedCustomerIds = new Set(scopeInfo.customerIds.map(id => String(id)));
3328
3534
  const previousCustomerId = this.normalizePriceContextCustomerId(params.previousCustomerId);
3329
3535
  const nextCustomerId = this.normalizePriceContextCustomerId(params.nextCustomerId);
3330
- if (this.hasSmartPricingStrategies()) {
3536
+ if (this.isCustomerUserPriceQuery() || this.hasSmartPricingStrategies()) {
3331
3537
  return previousCustomerId !== nextCustomerId;
3332
3538
  }
3333
3539
  const previousInScope = previousCustomerId ? scopedCustomerIds.has(previousCustomerId) : false;
@@ -3346,50 +3552,71 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
3346
3552
  }
3347
3553
  async calculateProductBookingPrices(paramsList) {
3348
3554
  if (!paramsList.length) return [];
3349
- const quotation = this.store.quotation;
3350
- const customerId = paramsList[0]?.customer_id ?? this.getCurrentOrderCustomerId();
3351
- await this.prepareProductPriceQueryContext(customerId);
3352
- const productMapsByGroup = new Map();
3555
+ const useCustomerUserPricing = this.isCustomerUserPriceQuery();
3556
+ const quotation = useCustomerUserPricing ? undefined : this.store.quotation;
3557
+ const currentOrderCustomerId = this.getCurrentOrderCustomerId();
3558
+ const resolvedChannels = paramsList.map(params => this.getPriceQueryChannel(params.channel));
3559
+ const authoritativeProducts = paramsList.map(() => null);
3560
+ const preparedCustomerKeys = new Set();
3561
+ await Promise.all(paramsList.map(async params => {
3562
+ const customerId = params.customer_id ?? currentOrderCustomerId;
3563
+ const customerKey = this.normalizePriceContextCustomerId(customerId) || '';
3564
+ if (preparedCustomerKeys.has(customerKey)) return;
3565
+ preparedCustomerKeys.add(customerKey);
3566
+ await this.prepareProductPriceQueryContext(customerId);
3567
+ }));
3353
3568
  const groups = new Map();
3354
- paramsList.forEach(params => {
3355
- const product = params.product || {};
3356
- const productId = this.getPriceQueryProductId(product);
3357
- if (productId === null) return;
3569
+ paramsList.forEach((params, index) => {
3358
3570
  const schedule = this.getPriceQuerySchedule(params);
3359
- const channel = params.channel || this.otherParams?.channel;
3360
- const groupKey = [schedule.schedule_date, schedule.schedule_datetime, channel || ''].join('|');
3571
+ const channel = resolvedChannels[index];
3572
+ const customerId = params.customer_id ?? currentOrderCustomerId;
3573
+ const groupKey = [schedule.schedule_date, schedule.schedule_datetime, channel || '', this.normalizePriceContextCustomerId(customerId) || ''].join('|');
3361
3574
  const group = groups.get(groupKey) || {
3362
- ids: new Set(),
3575
+ indices: [],
3363
3576
  schedule,
3577
+ customerId,
3364
3578
  channel
3365
3579
  };
3366
- group.ids.add(productId);
3580
+ group.indices.push(index);
3367
3581
  groups.set(groupKey, group);
3368
3582
  });
3369
- await Promise.all(Array.from(groups.entries()).map(async ([groupKey, group]) => {
3370
- const productsById = await this.loadProductsForPriceQuery({
3371
- ids: Array.from(group.ids),
3583
+ await Promise.all(Array.from(groups.values()).map(async group => {
3584
+ const priceQueries = group.indices.map(index => paramsList[index]);
3585
+ const resolvedProducts = await this.resolveProductsForPriceQuery({
3586
+ priceQueries,
3372
3587
  schedule: group.schedule,
3373
- customerId,
3588
+ customerId: group.customerId,
3374
3589
  channel: group.channel
3375
3590
  });
3376
- productMapsByGroup.set(groupKey, productsById);
3591
+ group.indices.forEach((originalIndex, groupIndex) => {
3592
+ authoritativeProducts[originalIndex] = resolvedProducts[groupIndex] || null;
3593
+ });
3377
3594
  }));
3378
- await this.loadQuotationForPriceQuery({
3379
- quotation,
3380
- customer_id: customerId,
3381
- channel: paramsList[0]?.channel
3382
- });
3383
- return paramsList.map(params => {
3595
+ if (!useCustomerUserPricing) {
3596
+ const quotationContexts = new Map();
3597
+ paramsList.forEach((params, index) => {
3598
+ const channel = resolvedChannels[index];
3599
+ const key = channel || '';
3600
+ if (quotationContexts.has(key)) return;
3601
+ quotationContexts.set(key, {
3602
+ channel,
3603
+ customer_id: params.customer_id ?? currentOrderCustomerId
3604
+ });
3605
+ });
3606
+ await Promise.all(Array.from(quotationContexts.values()).map(context => this.loadQuotationForPriceQuery({
3607
+ quotation,
3608
+ ...context
3609
+ })));
3610
+ }
3611
+ return paramsList.map((params, index) => {
3384
3612
  const productInput = params.product || {};
3385
- const productId = this.getPriceQueryProductId(productInput);
3386
- const schedule = this.getPriceQuerySchedule(params);
3387
- const channel = params.channel || this.otherParams?.channel;
3388
- const groupKey = [schedule.schedule_date, schedule.schedule_datetime, channel || ''].join('|');
3389
- const authoritativeProduct = productId === null ? null : productMapsByGroup.get(groupKey)?.get(productId) || null;
3613
+ const authoritativeProduct = authoritativeProducts[index];
3390
3614
  const product = this.mergeProductForPriceQuery(productInput, authoritativeProduct);
3615
+ const customerId = params.customer_id ?? currentOrderCustomerId;
3616
+ const channel = resolvedChannels[index];
3391
3617
  return (0, _quotationPrice.calculateBaseSalesProductBookingPrice)({
3392
3618
  ...params,
3619
+ channel,
3393
3620
  product,
3394
3621
  fallback_price: authoritativeProduct ? undefined : params.fallback_price,
3395
3622
  customer_id: customerId,
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
345
345
  count: number;
346
346
  left: number;
347
347
  summaryCount: number;
348
- status: "sold_out" | "lots_of_space" | "filling_up_fast";
348
+ status: "lots_of_space" | "filling_up_fast" | "sold_out";
349
349
  }[];
350
350
  /**
351
351
  * 找到多个资源的公共可用时间段
@@ -339,7 +339,7 @@ export declare class BookingTicketImpl extends BaseSalesImpl implements Module {
339
339
  * 获取当前的客户搜索条件
340
340
  * @returns 当前搜索条件
341
341
  */
342
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
342
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
343
343
  /**
344
344
  * 获取客户列表状态(包含滚动加载相关状态)
345
345
  * @returns 客户状态
@@ -94,7 +94,8 @@ class SalesImpl extends _BaseModule.BaseModule {
94
94
  initialState: {},
95
95
  otherParams: {
96
96
  fatherModule: this.name,
97
- openCache: false
97
+ openCache: false,
98
+ platform: this.otherParams?.platform
98
99
  }
99
100
  });
100
101
  await this.core.effects.emit(`${this.name}:onInited`, {});
@@ -232,7 +232,7 @@ export declare class UnifiedBookingSalesImpl extends BookingTicket {
232
232
  private releaseAvailabilityCommitLock;
233
233
  /** IO boundary: loads catalog, schedules, resources, occupancies, and registers one context. */
234
234
  prepareAvailabilityProjection(params: UnifiedBookingSalesPrepareAvailabilityProjectionParams): Promise<AvailabilityContextRef>;
235
- /** Pure configuration calculation over the current context projection. */
235
+ /** Candidate calculation over the current context projection and runtime minute. */
236
236
  getProductTimeRanges(contextId: string, request?: GetProductTimeRangesRequest): Promise<ContextualProductTimeRangeGroup[]>;
237
237
  /** Thin facade: auto-refresh on cart drift, then delegate to the pure projection query. */
238
238
  queryBookingAvailability(contextId: string, request: ContextualAvailabilityQuery): Promise<ContextualAvailabilityQueryResult>;