@pisell/pisellos 0.10.21 → 0.10.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/modules/BookingContext/index.d.ts +3 -0
- package/dist/modules/BookingContext/index.js +42 -13
- package/dist/modules/BookingContext/types.d.ts +4 -4
- package/dist/modules/BookingContext/types.js +3 -3
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
- package/dist/modules/Order/index.d.ts +5 -0
- package/dist/modules/Order/index.js +148 -84
- package/dist/modules/ProductList/clientDataVariants.d.ts +50 -0
- package/dist/modules/ProductList/clientDataVariants.js +216 -0
- package/dist/modules/ProductList/index.d.ts +14 -13
- package/dist/modules/ProductList/index.js +105 -77
- package/dist/modules/Quotation/index.d.ts +16 -0
- package/dist/modules/Quotation/index.js +240 -27
- package/dist/modules/ResourcePlanner/planner.d.ts +2 -2
- package/dist/modules/ResourcePlanner/planner.js +88 -21
- package/dist/modules/ResourcePlanner/types.d.ts +12 -0
- package/dist/modules/Rules/index.d.ts +5 -0
- package/dist/modules/Rules/index.js +27 -12
- package/dist/solution/BaseSales/index.d.ts +16 -1
- package/dist/solution/BaseSales/index.js +667 -349
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/dist/solution/UnifiedBookingSales/index.js +290 -81
- package/dist/solution/UnifiedBookingSales/types.d.ts +4 -0
- package/dist/solution/VenueBooking/index.d.ts +2 -0
- package/dist/solution/VenueBooking/index.js +542 -494
- package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
- package/dist/solution/VenueBooking/utils/dateSummary.js +3 -1
- package/dist/solution/VenueBooking/utils/slotMerge.d.ts +2 -0
- package/dist/solution/VenueBooking/utils/slotMerge.js +3 -1
- package/dist/utils/platform.d.ts +8 -0
- package/dist/utils/platform.js +15 -0
- package/lib/model/strategy/adapter/promotion/index.js +46 -1
- package/lib/modules/BookingContext/index.d.ts +3 -0
- package/lib/modules/BookingContext/index.js +35 -8
- package/lib/modules/BookingContext/types.d.ts +4 -4
- package/lib/modules/BookingContext/types.js +3 -3
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
- package/lib/modules/Order/index.d.ts +5 -0
- package/lib/modules/Order/index.js +65 -8
- package/lib/modules/ProductList/clientDataVariants.d.ts +50 -0
- package/lib/modules/ProductList/clientDataVariants.js +204 -0
- package/lib/modules/ProductList/index.d.ts +14 -13
- package/lib/modules/ProductList/index.js +77 -58
- package/lib/modules/Quotation/index.d.ts +16 -0
- package/lib/modules/Quotation/index.js +112 -9
- package/lib/modules/ResourcePlanner/planner.d.ts +2 -2
- package/lib/modules/ResourcePlanner/planner.js +80 -20
- package/lib/modules/ResourcePlanner/types.d.ts +12 -0
- package/lib/modules/Rules/index.d.ts +5 -0
- package/lib/modules/Rules/index.js +20 -11
- package/lib/solution/BaseSales/index.d.ts +16 -1
- package/lib/solution/BaseSales/index.js +293 -66
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/UnifiedBookingSales/index.d.ts +1 -1
- package/lib/solution/UnifiedBookingSales/index.js +225 -20
- package/lib/solution/UnifiedBookingSales/types.d.ts +4 -0
- package/lib/solution/VenueBooking/index.d.ts +2 -0
- package/lib/solution/VenueBooking/index.js +28 -8
- package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
- package/lib/solution/VenueBooking/utils/dateSummary.js +3 -1
- package/lib/solution/VenueBooking/utils/slotMerge.d.ts +2 -0
- package/lib/solution/VenueBooking/utils/slotMerge.js +3 -1
- package/lib/utils/platform.d.ts +8 -0
- package/lib/utils/platform.js +22 -0
- 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
|
-
|
|
666
|
-
|
|
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
|
|
753
|
-
const strategyContext = this.getPriceQueryStrategyContext(channel);
|
|
889
|
+
const handledByOsServer = (0, _clientDataVariants.isProductQueryHandledByOsServer)(this.core, this.request);
|
|
754
890
|
try {
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
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
|
-
|
|
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
|
|
789
|
-
const
|
|
790
|
-
const
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
3271
|
-
const
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
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
|
|
3350
|
-
const
|
|
3351
|
-
|
|
3352
|
-
const
|
|
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 =
|
|
3360
|
-
const
|
|
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
|
-
|
|
3575
|
+
indices: [],
|
|
3363
3576
|
schedule,
|
|
3577
|
+
customerId,
|
|
3364
3578
|
channel
|
|
3365
3579
|
};
|
|
3366
|
-
group.
|
|
3580
|
+
group.indices.push(index);
|
|
3367
3581
|
groups.set(groupKey, group);
|
|
3368
3582
|
});
|
|
3369
|
-
await Promise.all(Array.from(groups.
|
|
3370
|
-
const
|
|
3371
|
-
|
|
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
|
-
|
|
3591
|
+
group.indices.forEach((originalIndex, groupIndex) => {
|
|
3592
|
+
authoritativeProducts[originalIndex] = resolvedProducts[groupIndex] || null;
|
|
3593
|
+
});
|
|
3377
3594
|
}));
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
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
|
|
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,
|
|
@@ -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 | 1 | 2 |
|
|
329
|
+
weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -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
|
-
/**
|
|
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>;
|