@pisell/pisellos 2.3.1 → 2.3.3

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 (54) hide show
  1. package/dist/model/strategy/adapter/promotion/index.js +9 -0
  2. package/dist/modules/Order/index.d.ts +9 -0
  3. package/dist/modules/Order/index.js +448 -371
  4. package/dist/modules/Order/types.d.ts +2 -0
  5. package/dist/modules/Quotation/index.d.ts +16 -2
  6. package/dist/modules/Quotation/index.js +71 -38
  7. package/dist/modules/Quotation/types.d.ts +14 -0
  8. package/dist/modules/SalesSummary/index.d.ts +1 -0
  9. package/dist/modules/SalesSummary/index.js +7 -4
  10. package/dist/modules/Schedule/index.d.ts +4 -0
  11. package/dist/modules/Schedule/index.js +31 -1
  12. package/dist/modules/Schedule/types.d.ts +2 -0
  13. package/dist/server/index.js +13 -13
  14. package/dist/server/modules/order/index.d.ts +25 -7
  15. package/dist/server/modules/order/index.js +370 -309
  16. package/dist/server/modules/products/index.d.ts +4 -0
  17. package/dist/server/modules/products/index.js +76 -45
  18. package/dist/server/modules/quotation/index.d.ts +39 -0
  19. package/dist/server/modules/quotation/index.js +278 -66
  20. package/dist/server/modules/schedule/index.d.ts +2 -0
  21. package/dist/server/modules/schedule/index.js +10 -2
  22. package/dist/solution/BaseSales/index.d.ts +10 -1
  23. package/dist/solution/BaseSales/index.js +825 -528
  24. package/dist/solution/BaseSales/types.d.ts +7 -0
  25. package/dist/solution/BaseSales/utils/quotationPrice.d.ts +12 -1
  26. package/dist/solution/BaseSales/utils/quotationPrice.js +16 -3
  27. package/dist/solution/BookingByStep/index.d.ts +1 -1
  28. package/lib/modules/Order/index.d.ts +9 -0
  29. package/lib/modules/Order/index.js +48 -9
  30. package/lib/modules/Order/types.d.ts +2 -0
  31. package/lib/modules/Quotation/index.d.ts +16 -2
  32. package/lib/modules/Quotation/index.js +49 -13
  33. package/lib/modules/Quotation/types.d.ts +14 -0
  34. package/lib/modules/SalesSummary/index.d.ts +1 -0
  35. package/lib/modules/SalesSummary/index.js +4 -3
  36. package/lib/modules/Schedule/index.d.ts +4 -0
  37. package/lib/modules/Schedule/index.js +21 -0
  38. package/lib/modules/Schedule/types.d.ts +2 -0
  39. package/lib/server/index.js +1 -1
  40. package/lib/server/modules/order/index.d.ts +25 -7
  41. package/lib/server/modules/order/index.js +88 -54
  42. package/lib/server/modules/products/index.d.ts +4 -0
  43. package/lib/server/modules/products/index.js +43 -19
  44. package/lib/server/modules/quotation/index.d.ts +39 -0
  45. package/lib/server/modules/quotation/index.js +179 -1
  46. package/lib/server/modules/schedule/index.d.ts +2 -0
  47. package/lib/server/modules/schedule/index.js +8 -1
  48. package/lib/solution/BaseSales/index.d.ts +10 -1
  49. package/lib/solution/BaseSales/index.js +218 -19
  50. package/lib/solution/BaseSales/types.d.ts +7 -0
  51. package/lib/solution/BaseSales/utils/quotationPrice.d.ts +12 -1
  52. package/lib/solution/BaseSales/utils/quotationPrice.js +15 -3
  53. package/lib/solution/BookingByStep/index.d.ts +1 -1
  54. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { OrderModule, ProductList, QuotationModule, SalesSummaryModule, ScanOrderLoggerModule as BaseSalesLoggerModule, ScheduleModule } from '../../modules';
2
2
  import type { ScanOrderLogInput as BaseSalesLogInput, ScanOrderLoggerProviderConfig as BaseSalesLoggerProviderConfig, ScanOrderLoggerProviderType as BaseSalesLoggerProviderType } from '../../modules/ScanOrderLogger/types';
3
3
  import type { QuantityCheckResult, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
4
+ import type { QuotationCustomerScopeInfo } from '../../modules/Quotation/types';
4
5
  /**
5
6
  * BaseSales 流程 hook 后缀。
6
7
  * 完整事件名应由当前模块名动态拼接,避免多个实例共享固定事件 key。
@@ -278,6 +279,12 @@ export interface BaseSalesProductBookingPriceResult {
278
279
  segments: BaseSalesProductBookingPriceSegment[];
279
280
  product_bundle?: BaseSalesBundleProductBookingPriceResult[];
280
281
  }
282
+ export type BaseSalesQuotationCustomerScopeInfo = QuotationCustomerScopeInfo;
283
+ export interface BaseSalesPriceRecalculationContextChange {
284
+ previousCustomerId?: number | string | null;
285
+ nextCustomerId?: number | string | null;
286
+ [key: string]: any;
287
+ }
281
288
  export type BaseSalesAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
282
289
  export interface BaseSalesTableFormRecord {
283
290
  policy?: string | null;
@@ -1,7 +1,18 @@
1
1
  import type { QuotationModule } from '../../../modules/Quotation';
2
2
  import type { BaseSalesCalculateProductBookingPriceParams, BaseSalesProductBookingPriceResult } from '../types';
3
3
  interface BuildBaseSalesQuotationPriceParams extends BaseSalesCalculateProductBookingPriceParams {
4
- quotation?: Pick<QuotationModule, 'getPriceForProduct' | 'getQuotationShelfId'> | null;
4
+ quotation?: (Pick<QuotationModule, 'getPriceForProduct' | 'getQuotationShelfId'> & {
5
+ getQuotationMatchForProduct?: (params: {
6
+ productId: number;
7
+ variantId?: number;
8
+ datetime: string;
9
+ channel?: string;
10
+ customer_id?: number | string;
11
+ }) => {
12
+ price: string | null;
13
+ quotationShelfId: number;
14
+ } | null;
15
+ }) | null;
5
16
  }
6
17
  export declare function calculateBaseSalesProductBookingPrice(params: BuildBaseSalesQuotationPriceParams): BaseSalesProductBookingPriceResult;
7
18
  export {};
@@ -118,20 +118,30 @@ function formatTimePoint(datetime) {
118
118
  return datetime.format('YYYY-MM-DD HH:mm:ss');
119
119
  }
120
120
  function buildPriceSegment(params) {
121
+ var _match$quotationShelf;
121
122
  var timePoint = formatTimePoint(params.segment.start);
122
- var quotedPrice = params.quotation && params.productId !== null ? params.quotation.getPriceForProduct({
123
+ var match = params.quotation && params.productId !== null && params.quotation.getQuotationMatchForProduct ? params.quotation.getQuotationMatchForProduct({
123
124
  productId: params.productId,
124
125
  variantId: params.variantId,
125
126
  datetime: timePoint,
127
+ channel: params.channel,
128
+ customer_id: params.customerId
129
+ }) : null;
130
+ var quotedPrice = match ? match.price : params.quotation && params.productId !== null ? params.quotation.getPriceForProduct({
131
+ productId: params.productId,
132
+ variantId: params.variantId,
133
+ datetime: timePoint,
134
+ channel: params.channel,
126
135
  customer_id: params.customerId
127
136
  }) : null;
128
137
  var unitPrice = toPriceString(quotedPrice !== null && quotedPrice !== void 0 ? quotedPrice : params.fallbackPrice);
129
- var quotationShelfId = quotedPrice !== null && params.quotation && params.productId !== null ? params.quotation.getQuotationShelfId({
138
+ var quotationShelfId = quotedPrice !== null ? (_match$quotationShelf = match === null || match === void 0 ? void 0 : match.quotationShelfId) !== null && _match$quotationShelf !== void 0 ? _match$quotationShelf : params.quotation && params.productId !== null ? params.quotation.getQuotationShelfId({
130
139
  productId: params.productId,
131
140
  variantId: params.variantId,
132
141
  datetime: timePoint,
142
+ channel: params.channel,
133
143
  customer_id: params.customerId
134
- }) : 0;
144
+ }) : 0 : 0;
135
145
  return {
136
146
  start_datetime: timePoint,
137
147
  end_datetime: params.segment.end ? formatTimePoint(params.segment.end) : undefined,
@@ -151,6 +161,7 @@ function calculatePriceForProduct(params) {
151
161
  productId: params.productId,
152
162
  variantId: params.variantId,
153
163
  customerId: params.customerId,
164
+ channel: params.channel,
154
165
  fallbackPrice: params.fallbackPrice,
155
166
  segment: segment
156
167
  });
@@ -183,6 +194,7 @@ function calculateBundlePrices(params, segments) {
183
194
  productId: productId,
184
195
  variantId: variantId,
185
196
  customerId: params.customer_id,
197
+ channel: params.channel,
186
198
  quantity: quantity,
187
199
  fallbackPrice: getBundleFallbackPrice(bundle),
188
200
  segments: segments
@@ -216,6 +228,7 @@ export function calculateBaseSalesProductBookingPrice(params) {
216
228
  productId: productId,
217
229
  variantId: variantId,
218
230
  customerId: params.customer_id,
231
+ channel: params.channel,
219
232
  quantity: productQuantity,
220
233
  fallbackPrice: fallbackPrice,
221
234
  segments: timeSegments
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 1 | 2 | 6 | 3 | 4 | 5;
314
+ weekNum: 0 | 2 | 1 | 6 | 3 | 4 | 5;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -358,7 +358,9 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
358
358
  private hasGoodPassDiscount;
359
359
  private getBundleRuntimeIdentity;
360
360
  private preservePersistedBundlePriceFields;
361
+ private applyOrderProductUpdateToTempOrder;
361
362
  updateOrderProduct(params: UpdateOrderProductParams): Promise<OrderProduct[]>;
363
+ updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<OrderProduct[]>;
362
364
  updateOrderProductQuantity(params: UpdateOrderProductQuantityParams): Promise<OrderProduct[]>;
363
365
  updateOrderBooking(params: UpdateOrderBookingParams): any[];
364
366
  /**
@@ -479,6 +481,13 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
479
481
  hydrateTempOrderFromRecord(record: Record<string, any>, options?: {
480
482
  recalcOnHydrate?: boolean;
481
483
  }): Promise<OrderTempOrder>;
484
+ /**
485
+ * 兼容后端详情将 holder 放在 metadata.holder 的历史形态,统一补到运行时展示路径。
486
+ *
487
+ * @example
488
+ * this.normalizeHydratedBookingHolder({ metadata: { holder: { form_record: [1] } } });
489
+ */
490
+ private normalizeHydratedBookingHolder;
482
491
  private normalizeTempOrderForRuntime;
483
492
  private hydrateLinkedBookingIdentity;
484
493
  private pickHydratedDisplayText;
@@ -2683,7 +2683,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2683
2683
  };
2684
2684
  });
2685
2685
  }
2686
- async updateOrderProduct(params) {
2686
+ applyOrderProductUpdateToTempOrder(tempOrder, params) {
2687
2687
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
2688
2688
  const {
2689
2689
  product_id,
@@ -2695,7 +2695,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2695
2695
  product_bundle,
2696
2696
  booking
2697
2697
  } = params;
2698
- const tempOrder = this.ensureTempOrder();
2699
2698
  const identityLookup = {
2700
2699
  product_id,
2701
2700
  product_variant_id
@@ -2839,6 +2838,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2839
2838
  tempOrder.products[productIndex],
2840
2839
  (_q = tempOrder.products[productIndex].metadata) == null ? void 0 : _q.unique_identification_number
2841
2840
  );
2841
+ }
2842
+ async updateOrderProduct(params) {
2843
+ const tempOrder = this.ensureTempOrder();
2844
+ this.applyOrderProductUpdateToTempOrder(tempOrder, params);
2842
2845
  await this.applyPromotion();
2843
2846
  this.applyDiscount();
2844
2847
  this.sanitizeTempOrderProducts(tempOrder);
@@ -2846,6 +2849,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
2846
2849
  this.persistTempOrder();
2847
2850
  return tempOrder.products;
2848
2851
  }
2852
+ async updateOrderProducts(paramsList) {
2853
+ const tempOrder = this.ensureTempOrder();
2854
+ if (!paramsList.length) {
2855
+ return tempOrder.products;
2856
+ }
2857
+ paramsList.forEach((params) => {
2858
+ this.applyOrderProductUpdateToTempOrder(tempOrder, params);
2859
+ });
2860
+ await this.finalizeAfterProductsMutation(tempOrder);
2861
+ return tempOrder.products;
2862
+ }
2849
2863
  async updateOrderProductQuantity(params) {
2850
2864
  var _a;
2851
2865
  const {
@@ -3634,6 +3648,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3634
3648
  this.persistTempOrder();
3635
3649
  return nextTempOrder;
3636
3650
  }
3651
+ /**
3652
+ * 兼容后端详情将 holder 放在 metadata.holder 的历史形态,统一补到运行时展示路径。
3653
+ *
3654
+ * @example
3655
+ * this.normalizeHydratedBookingHolder({ metadata: { holder: { form_record: [1] } } });
3656
+ */
3657
+ normalizeHydratedBookingHolder(booking) {
3658
+ const next = { ...booking || {} };
3659
+ const metadata = next.metadata && typeof next.metadata === "object" && !Array.isArray(next.metadata) ? { ...next.metadata } : {};
3660
+ const metadataHolder = metadata.holder && typeof metadata.holder === "object" && !Array.isArray(metadata.holder) ? metadata.holder : null;
3661
+ if (!next.holder && metadataHolder) {
3662
+ next.holder = { ...metadataHolder };
3663
+ }
3664
+ const holder = next.holder && typeof next.holder === "object" && !Array.isArray(next.holder) ? next.holder : null;
3665
+ const holderRecords = Array.isArray(holder == null ? void 0 : holder.form_record) ? holder.form_record.filter((id) => id !== void 0 && id !== null && id !== "") : [];
3666
+ const hasMetadataHolderId = metadata.holder_id !== void 0 && metadata.holder_id !== null && metadata.holder_id !== "" && (!Array.isArray(metadata.holder_id) || metadata.holder_id.length > 0);
3667
+ if (!hasMetadataHolderId && holderRecords.length > 0) {
3668
+ metadata.holder_id = holderRecords;
3669
+ }
3670
+ if (Object.keys(metadata).length > 0) {
3671
+ next.metadata = metadata;
3672
+ }
3673
+ return next;
3674
+ }
3637
3675
  normalizeTempOrderForRuntime(raw, options) {
3638
3676
  var _a, _b;
3639
3677
  const nextTempOrder = {
@@ -3660,11 +3698,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3660
3698
  nextTempOrder.holder = raw.holder && typeof raw.holder === "object" ? { ...raw.holder } : null;
3661
3699
  const rawProducts = Array.isArray(raw.products) ? raw.products : [];
3662
3700
  nextTempOrder.products = rawProducts.length > 0 ? rawProducts.map((p) => this.normalizeHydratedOrderProduct(p)) : [];
3663
- nextTempOrder.bookings = Array.isArray(raw.bookings) ? raw.bookings.map((b) => ({
3664
- ...b || {},
3665
- is_all: (0, import_utils.normalizeBookingIsAll)(b || {}),
3666
- sub_type: (0, import_utils.normalizeBookingSubType)(b || {})
3667
- })) : [];
3701
+ nextTempOrder.bookings = Array.isArray(raw.bookings) ? raw.bookings.map((b) => {
3702
+ const booking = this.normalizeHydratedBookingHolder(b || {});
3703
+ return {
3704
+ ...booking,
3705
+ is_all: (0, import_utils.normalizeBookingIsAll)(booking),
3706
+ sub_type: (0, import_utils.normalizeBookingSubType)(booking)
3707
+ };
3708
+ }) : [];
3668
3709
  nextTempOrder.payments = Array.isArray(raw.payments) ? raw.payments.map((p) => ({ ...p || {} })) : [];
3669
3710
  nextTempOrder.surcharges = Array.isArray(raw.surcharges) ? raw.surcharges.map((s) => ({ ...s || {} })) : [];
3670
3711
  nextTempOrder.relation_forms = Array.isArray(raw.relation_forms) ? raw.relation_forms.map((f) => ({ ...f || {} })) : [];
@@ -3851,8 +3892,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3851
3892
  async getOrderInfo(order_id) {
3852
3893
  const res = await this.request.get(`/order/sales/${order_id}`, {
3853
3894
  with: ["products", "bookings"]
3854
- }, {
3855
- osServer: true
3856
3895
  });
3857
3896
  return res;
3858
3897
  }
@@ -666,6 +666,8 @@ export interface OrderModuleAPI {
666
666
  updateTempOrderContactsInfo: (contactsInfo: Record<string, any> | null) => Record<string, any> | null;
667
667
  addProductToOrder: (product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput) => Promise<OrderProduct[]>;
668
668
  updateOrderProduct: (params: UpdateOrderProductParams) => Promise<OrderProduct[]>;
669
+ /** 批量更新购物车行,末尾仅触发一次促销重算与 summary 刷新 */
670
+ updateOrderProducts: (paramsList: UpdateOrderProductParams[]) => Promise<OrderProduct[]>;
669
671
  updateOrderProductQuantity: (params: UpdateOrderProductQuantityParams) => Promise<OrderProduct[]>;
670
672
  updateOrderBooking: (params: UpdateOrderBookingParams) => any[];
671
673
  removeProductFromOrder: (identity: OrderProductIdentity) => Promise<OrderProduct[]>;
@@ -1,8 +1,8 @@
1
1
  import { Module, PisellCore, ModuleOptions } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
3
  import type { ScheduleItem } from '../Schedule/types';
4
- import type { QuotationItem } from './types';
5
- export type { QuotationItem, QuotationProductData, QuotationSchedule, QuotationState, QuotationCustomer } from './types';
4
+ import type { QuotationItem, QuotationCustomerScopeInfo } from './types';
5
+ export type { QuotationItem, QuotationProductData, QuotationSchedule, QuotationState, QuotationCustomer, QuotationCustomerScope, QuotationCustomerScopeInfo, } from './types';
6
6
  export declare class QuotationModule extends BaseModule implements Module {
7
7
  protected defaultName: string;
8
8
  protected defaultVersion: string;
@@ -16,6 +16,7 @@ export declare class QuotationModule extends BaseModule implements Module {
16
16
  customer_id?: number | string;
17
17
  }): Promise<void>;
18
18
  getQuotationList(): QuotationItem[];
19
+ getQuotationCustomerScopeInfo(): QuotationCustomerScopeInfo;
19
20
  /**
20
21
  * Look up the quotation price for a specific product (+ optional variant) at a given datetime.
21
22
  * Returns the price as a string (e.g. "300.00"), or null if no quotation applies.
@@ -28,12 +29,24 @@ export declare class QuotationModule extends BaseModule implements Module {
28
29
  productId: number;
29
30
  variantId?: number;
30
31
  datetime: string;
32
+ channel?: string;
31
33
  customer_id?: number | string;
32
34
  }): string | null;
35
+ getQuotationMatchForProduct(params: {
36
+ productId: number;
37
+ variantId?: number;
38
+ datetime: string;
39
+ channel?: string;
40
+ customer_id?: number | string;
41
+ }): {
42
+ price: string | null;
43
+ quotationShelfId: number;
44
+ } | null;
33
45
  getQuotationShelfId(params: {
34
46
  productId: number;
35
47
  variantId?: number;
36
48
  datetime: string;
49
+ channel?: string;
37
50
  customer_id?: number | string;
38
51
  }): number;
39
52
  /**
@@ -49,6 +62,7 @@ export declare class QuotationModule extends BaseModule implements Module {
49
62
  setScheduleResolver(resolver: (id: number) => ScheduleItem | undefined): void;
50
63
  private isQuotationVisibleForCustomer;
51
64
  private hasValidCustomerId;
65
+ private normalizeCustomerId;
52
66
  private isQuotationActiveAt;
53
67
  private findProductData;
54
68
  }
@@ -58,6 +58,40 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
58
58
  getQuotationList() {
59
59
  return this.store.list;
60
60
  }
61
+ getQuotationCustomerScopeInfo() {
62
+ const customerById = /* @__PURE__ */ new Map();
63
+ const quotationScopes = this.store.list.filter((quotation) => Array.isArray(quotation.customer) && quotation.customer.length > 0).map((quotation) => {
64
+ const customerIds = [];
65
+ const customers = [];
66
+ const localSeen = /* @__PURE__ */ new Set();
67
+ const quotationCustomers = quotation.customer || [];
68
+ quotationCustomers.forEach((customer) => {
69
+ const customerId = this.normalizeCustomerId(customer == null ? void 0 : customer.id);
70
+ if (!customerId || localSeen.has(customerId))
71
+ return;
72
+ localSeen.add(customerId);
73
+ customerIds.push(customerId);
74
+ customers.push(customer);
75
+ if (!customerById.has(customerId))
76
+ customerById.set(customerId, customer);
77
+ });
78
+ return {
79
+ quotationId: quotation.id,
80
+ quotationName: quotation.name,
81
+ customerIds,
82
+ customers
83
+ };
84
+ });
85
+ const result = {
86
+ quotationCount: this.store.list.length,
87
+ hasCustomerScopedQuotations: quotationScopes.length > 0,
88
+ allQuotationsCustomerScoped: this.store.list.length > 0 && quotationScopes.length === this.store.list.length,
89
+ customerIds: Array.from(customerById.keys()),
90
+ customers: Array.from(customerById.values()),
91
+ quotationScopes
92
+ };
93
+ return result;
94
+ }
61
95
  /**
62
96
  * Look up the quotation price for a specific product (+ optional variant) at a given datetime.
63
97
  * Returns the price as a string (e.g. "300.00"), or null if no quotation applies.
@@ -67,6 +101,10 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
67
101
  * the requested productId wins.
68
102
  */
69
103
  getPriceForProduct(params) {
104
+ var _a;
105
+ return ((_a = this.getQuotationMatchForProduct(params)) == null ? void 0 : _a.price) ?? null;
106
+ }
107
+ getQuotationMatchForProduct(params) {
70
108
  const { productId, variantId, datetime, customer_id } = params;
71
109
  for (const quotation of this.store.list) {
72
110
  const visible = this.isQuotationVisibleForCustomer(quotation, customer_id);
@@ -80,23 +118,16 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
80
118
  continue;
81
119
  if (match.value === 0)
82
120
  continue;
83
- return String(match.value);
121
+ return {
122
+ price: String(match.value),
123
+ quotationShelfId: quotation.id
124
+ };
84
125
  }
85
126
  return null;
86
127
  }
87
128
  getQuotationShelfId(params) {
88
- const { productId, variantId, datetime, customer_id } = params;
89
- for (const quotation of this.store.list) {
90
- if (!this.isQuotationVisibleForCustomer(quotation, customer_id))
91
- continue;
92
- if (!this.isQuotationActiveAt(quotation, datetime))
93
- continue;
94
- const match = this.findProductData(quotation.product_data, productId, variantId);
95
- if (!match || match.value === 0)
96
- continue;
97
- return quotation.id;
98
- }
99
- return 0;
129
+ var _a;
130
+ return ((_a = this.getQuotationMatchForProduct(params)) == null ? void 0 : _a.quotationShelfId) ?? 0;
100
131
  }
101
132
  /**
102
133
  * Batch pre-compute quotation prices for a set of products across multiple time points.
@@ -138,6 +169,11 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
138
169
  return false;
139
170
  return Number(customerId) > 0;
140
171
  }
172
+ normalizeCustomerId(customerId) {
173
+ if (customerId === void 0 || customerId === null || customerId === "")
174
+ return null;
175
+ return String(customerId);
176
+ }
141
177
  isQuotationActiveAt(quotation, datetime) {
142
178
  var _a;
143
179
  if (!((_a = quotation.schedule) == null ? void 0 : _a.length))
@@ -45,3 +45,17 @@ export interface QuotationItem {
45
45
  export interface QuotationState {
46
46
  list: QuotationItem[];
47
47
  }
48
+ export interface QuotationCustomerScope {
49
+ quotationId: number;
50
+ quotationName: string;
51
+ customerIds: string[];
52
+ customers: QuotationCustomer[];
53
+ }
54
+ export interface QuotationCustomerScopeInfo {
55
+ quotationCount: number;
56
+ hasCustomerScopedQuotations: boolean;
57
+ allQuotationsCustomerScoped: boolean;
58
+ customerIds: string[];
59
+ customers: QuotationCustomer[];
60
+ quotationScopes: QuotationCustomerScope[];
61
+ }
@@ -29,6 +29,7 @@ export declare class SalesSummaryModule extends BaseModule implements Module, Sa
29
29
  }): Promise<{
30
30
  tax_title: string;
31
31
  tax_rate: number | undefined;
32
+ tax_country_code: string;
32
33
  product_quantity: number;
33
34
  product_original_amount: string;
34
35
  product_amount: string;
@@ -119,8 +119,8 @@ var SalesSummaryModule = class extends import_BaseModule.BaseModule {
119
119
  const summarySchedule = this.core.getModule(
120
120
  `${this.name.split("_")[0]}_schedule`
121
121
  );
122
- const needScheduleIds = (_b = (_a = this.store.surchargeList) == null ? void 0 : _a.map((item) => item.available_schedule_ids)) == null ? void 0 : _b.flat();
123
- const scheduleList = summarySchedule == null ? void 0 : summarySchedule.getScheduleListByIds(needScheduleIds);
122
+ const needScheduleIds = (((_b = (_a = this.store.surchargeList) == null ? void 0 : _a.map((item) => item.available_schedule_ids)) == null ? void 0 : _b.flat()) || []).filter((id) => id !== void 0 && id !== null && id !== "");
123
+ const scheduleList = needScheduleIds.length > 0 ? summarySchedule == null ? void 0 : summarySchedule.getScheduleListByIds(needScheduleIds) : [];
124
124
  const scheduleById = {};
125
125
  if (Array.isArray(scheduleList)) {
126
126
  for (const item of scheduleList) {
@@ -139,7 +139,8 @@ var SalesSummaryModule = class extends import_BaseModule.BaseModule {
139
139
  const summaryWithTaxMeta = {
140
140
  ...summary,
141
141
  tax_title: taxConfig.taxTitle || "",
142
- tax_rate: taxRate ?? taxConfig.taxRate
142
+ tax_rate: taxRate ?? taxConfig.taxRate,
143
+ tax_country_code: taxConfig.taxCountryCode || ""
143
144
  };
144
145
  this.store.summary = summaryWithTaxMeta;
145
146
  return summaryWithTaxMeta;
@@ -9,6 +9,7 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
9
9
  private cacheId;
10
10
  private openCache;
11
11
  private fatherModule;
12
+ private hasLoadedScheduleList;
12
13
  constructor(name?: string, version?: string);
13
14
  initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
14
15
  /**
@@ -25,6 +26,9 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
25
26
  */
26
27
  loadAllSchedule(): Promise<void>;
27
28
  setScheduleList(list: ScheduleItem[]): void;
29
+ private syncScheduleMap;
30
+ getScheduleList(): ScheduleItem[];
31
+ isScheduleListLoaded(): boolean;
28
32
  loadScheduleAvailableDate({ startDate, endDate, custom_page_id, channel, }: LoadScheduleAvailableDateParams): Promise<import("../Date/types").ITime[]>;
29
33
  getScheduleListByIds(ids: number[]): ScheduleItem[];
30
34
  setAvailabilityScheduleDateList(list: ScheduleAvailabilityDateItem[]): void;
@@ -49,6 +49,7 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
49
49
  this.defaultVersion = "1.0.0";
50
50
  this.store = {};
51
51
  this.openCache = false;
52
+ this.hasLoadedScheduleList = false;
52
53
  }
53
54
  async initialize(core, options) {
54
55
  var _a, _b;
@@ -60,10 +61,14 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
60
61
  this.store = options == null ? void 0 : options.store;
61
62
  if (options.initialState) {
62
63
  this.store.scheduleList = options.initialState.scheduleList;
64
+ this.syncScheduleMap();
63
65
  this.store.availabilityDateList = options.initialState.availabilityDateList;
66
+ this.hasLoadedScheduleList = Array.isArray(options.initialState.scheduleList);
64
67
  } else {
65
68
  this.store.scheduleList = [];
69
+ this.store.map = /* @__PURE__ */ new Map();
66
70
  this.store.availabilityDateList = [];
71
+ this.hasLoadedScheduleList = false;
67
72
  }
68
73
  if ((_a = options.otherParams) == null ? void 0 : _a.cacheId) {
69
74
  this.openCache = options.otherParams.openCache;
@@ -101,6 +106,19 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
101
106
  }
102
107
  setScheduleList(list) {
103
108
  this.store.scheduleList = list;
109
+ this.syncScheduleMap();
110
+ this.hasLoadedScheduleList = true;
111
+ }
112
+ syncScheduleMap() {
113
+ this.store.map = new Map(
114
+ (this.store.scheduleList || []).map((schedule) => [Number(schedule.id), schedule])
115
+ );
116
+ }
117
+ getScheduleList() {
118
+ return this.store.scheduleList || [];
119
+ }
120
+ isScheduleListLoaded() {
121
+ return this.hasLoadedScheduleList;
104
122
  }
105
123
  async loadScheduleAvailableDate({
106
124
  startDate,
@@ -150,6 +168,9 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
150
168
  var _a;
151
169
  const idSet = new Set(ids.map((id) => String(id)));
152
170
  console.log("getScheduleListByIds", this.store.scheduleList);
171
+ if (this.store.map instanceof Map && this.store.map.size > 0) {
172
+ return ids.map((id) => this.store.map.get(Number(id))).filter(Boolean);
173
+ }
153
174
  const list = (_a = this.store.scheduleList) == null ? void 0 : _a.filter((n) => idSet.has(String(n.id)));
154
175
  return list;
155
176
  }
@@ -25,6 +25,8 @@ export interface LoadScheduleAvailableDateParams {
25
25
  channel?: string;
26
26
  }
27
27
  export interface ScheduleModuleAPI {
28
+ getScheduleList: () => ScheduleItem[];
29
+ isScheduleListLoaded: () => boolean;
28
30
  }
29
31
  export type ScheduleItem = {
30
32
  /** 颜色 */
@@ -2486,6 +2486,7 @@ var Server = class {
2486
2486
  const shouldClearLocalOrderId = this.isLocalCheckoutOrderId(next.order_id);
2487
2487
  if (shouldClearLocalOrderId)
2488
2488
  next.order_id = null;
2489
+ delete next.vouchers;
2489
2490
  const hasCheckoutOrderNumbers = !this.isBlankCheckoutValue(next.shop_order_number) && !this.isBlankCheckoutValue(next.shop_full_order_number);
2490
2491
  if (hasCheckoutOrderNumbers) {
2491
2492
  this.logInfo(`${title}: checkout 已携带订单号,跳过查重`, {
@@ -2541,7 +2542,6 @@ var Server = class {
2541
2542
  shop_order_number: next.shop_order_number,
2542
2543
  shop_full_order_number: next.shop_full_order_number
2543
2544
  });
2544
- delete next.vouchers;
2545
2545
  return next;
2546
2546
  } catch (error) {
2547
2547
  this.logWarning(`${title}: checkout 查找本地订单失败`, {
@@ -15,7 +15,6 @@ export declare class OrderModule extends BaseModule implements Module {
15
15
  private syncTimer?;
16
16
  private isProcessingSyncBatch;
17
17
  private isIdlePhase;
18
- private resourceIdIndex;
19
18
  private logger;
20
19
  private storage;
21
20
  private orderSQLiteSaveQueue; /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
@@ -32,10 +31,10 @@ export declare class OrderModule extends BaseModule implements Module {
32
31
  private emitOrdersChanged;
33
32
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
34
33
  /**
35
- * 记录信息日志
36
- * @param title 日志标题
37
- * @param metadata 日志元数据
38
- */
34
+ * 记录信息日志
35
+ * @param title 日志标题
36
+ * @param metadata 日志元数据
37
+ */
39
38
  private logInfo;
40
39
  /**
41
40
  * 记录错误日志
@@ -89,7 +88,6 @@ export declare class OrderModule extends BaseModule implements Module {
89
88
  * @returns 刷新后的订单列表
90
89
  */
91
90
  silentRefresh(): Promise<OrderData[]>;
92
- getOrdersByResourceId(resourceId: string | number): OrderData[];
93
91
  private normalizeOrderForMemoryList;
94
92
  /**
95
93
  * 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
@@ -126,7 +124,6 @@ export declare class OrderModule extends BaseModule implements Module {
126
124
  private isBlankIdentityValue;
127
125
  private getOrderIdentityEntries;
128
126
  private getOrderIdentityKeys;
129
- private extractResourceIds;
130
127
  private getOrderDateKey;
131
128
  /**
132
129
  * 初始化 OrderDataSource 实例
@@ -175,6 +172,27 @@ export declare class OrderModule extends BaseModule implements Module {
175
172
  * 将增量订单合并到 store
176
173
  */
177
174
  private mergeOrdersToStore;
175
+ /**
176
+ * 在身份索引中查找与目标订单共享任一身份键的已存在订单下标。
177
+ * 返回所有命中键里最小的下标,等价于原 findOrderIndexByIdentity 的「取首个匹配」语义。
178
+ *
179
+ * @example
180
+ * const idx = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys)
181
+ */
182
+ private lookupOrderIndexByIdentityKeys;
183
+ /**
184
+ * 将订单的全部身份键登记到索引并指向其在列表中的下标。
185
+ * 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
186
+ *
187
+ * @example
188
+ * this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex)
189
+ */
190
+ private registerOrderIdentityKeys;
191
+ /**
192
+ * 合并热路径去重兜底:默认直接返回原列表(增量索引已保证无重复)。
193
+ * 仅当 ORDER_MERGE_SELF_CHECK 开启时,额外做一次全表压缩并在发现残留重复时告警。
194
+ */
195
+ private runOrderStoreSelfCheck;
178
196
  private normalizeOrderSyncMessage;
179
197
  private normalizeOrderSyncPayload;
180
198
  private uniqueOrderIds;