@pisell/pisellos 2.3.19 → 2.3.21

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 (35) hide show
  1. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +16 -10
  2. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +2 -1
  3. package/dist/modules/Order/index.d.ts +1 -1
  4. package/dist/modules/Order/index.js +48 -31
  5. package/dist/modules/Order/types.d.ts +1 -0
  6. package/dist/modules/Order/utils.js +10 -2
  7. package/dist/modules/Product/index.d.ts +1 -1
  8. package/dist/server/index.d.ts +4 -0
  9. package/dist/server/index.js +392 -253
  10. package/dist/server/modules/order/types.d.ts +2 -0
  11. package/dist/server/modules/products/index.d.ts +5 -1
  12. package/dist/server/modules/products/index.js +383 -315
  13. package/dist/server/modules/products/types.d.ts +4 -0
  14. package/dist/solution/BaseSales/index.js +144 -127
  15. package/dist/solution/BaseSales/types.d.ts +2 -0
  16. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +3 -1
  17. package/dist/solution/BookingByStep/index.d.ts +1 -1
  18. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +5 -0
  19. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +1 -0
  20. package/lib/modules/Order/index.d.ts +1 -1
  21. package/lib/modules/Order/index.js +34 -12
  22. package/lib/modules/Order/types.d.ts +1 -0
  23. package/lib/modules/Order/utils.js +10 -1
  24. package/lib/modules/Product/index.d.ts +1 -1
  25. package/lib/server/index.d.ts +4 -0
  26. package/lib/server/index.js +83 -2
  27. package/lib/server/modules/order/types.d.ts +2 -0
  28. package/lib/server/modules/products/index.d.ts +5 -1
  29. package/lib/server/modules/products/index.js +20 -0
  30. package/lib/server/modules/products/types.d.ts +4 -0
  31. package/lib/solution/BaseSales/index.js +40 -22
  32. package/lib/solution/BaseSales/types.d.ts +2 -0
  33. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +2 -0
  34. package/lib/solution/BookingByStep/index.d.ts +1 -1
  35. package/package.json +1 -1
@@ -85,6 +85,8 @@ export interface BaseSalesOrderProduct extends BaseSalesOrderProductIdentity {
85
85
  booking_uid?: string;
86
86
  /** 多语言商品标题快照,随 tempOrder 提交到 checkout。 */
87
87
  product_title?: BaseSalesLocalizedText;
88
+ /** 商品封面图快照,随 tempOrder 提交到 checkout。 */
89
+ product_cover?: string;
88
90
  /**
89
91
  * 行级扩展 metadata。价格相关的权威字段:
90
92
  *
@@ -166,7 +166,8 @@ export function transformBaseProductToOrderProduct(params) {
166
166
  source_product_price: sourceProductPrice,
167
167
  main_product_selling_price: mainProductSellingPrice,
168
168
  main_product_original_price: mainProductOriginalPrice,
169
- price_schema_version: 2
169
+ price_schema_version: 2,
170
+ holder_config: sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct.holder_config
170
171
  }, hasPriceOverride ? {
171
172
  price_override: String(payload.price_override),
172
173
  is_manual_discount: 1
@@ -198,6 +199,7 @@ export function transformBaseProductToOrderProduct(params) {
198
199
  metadata: metadata,
199
200
  note: payload.note != null ? String(payload.note) : '',
200
201
  product_title: productTitle,
202
+ product_cover: sourceProduct === null || sourceProduct === void 0 ? void 0 : sourceProduct.cover,
201
203
  _origin: _objectSpread(_objectSpread({}, sourceProduct || {}), {}, {
202
204
  callbackData: payload
203
205
  })
@@ -358,7 +358,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
358
358
  };
359
359
  setOtherData(key: string, value: any): void;
360
360
  getOtherData(key: string): any;
361
- getProductTypeById(id: number): Promise<"normal" | "duration" | "session">;
361
+ getProductTypeById(id: number): Promise<"duration" | "session" | "normal">;
362
362
  /**
363
363
  * 提供给 UI 的方法,减轻 UI 层的计算压力,UI 层只需要传递 cartItemId 和 resourceCode 即返回对应的 renderList
364
364
  *
@@ -136,6 +136,9 @@ function resolveProductTitle(product, booking, sourceProduct) {
136
136
  const metadata = product.metadata || {};
137
137
  return (sourceProduct == null ? void 0 : sourceProduct.title) ?? (sourceProduct == null ? void 0 : sourceProduct.name) ?? metadata.product_title ?? metadata.product_name ?? ((_a = booking == null ? void 0 : booking.product) == null ? void 0 : _a.title) ?? ((_b = booking == null ? void 0 : booking.detail) == null ? void 0 : _b.product_title) ?? "";
138
138
  }
139
+ function resolveProductCover(product, booking, sourceProduct) {
140
+ return (sourceProduct == null ? void 0 : sourceProduct.cover) ?? product.product_cover ?? "";
141
+ }
139
142
  function resolveMainProductPrice(product, fallback) {
140
143
  const metadata = product.metadata || {};
141
144
  const value = metadata.main_product_original_price ?? metadata.source_product_price;
@@ -195,6 +198,7 @@ function buildCacheItemFromOrderLine(input) {
195
198
  const capacity = resolveCapacityFromBooking(booking);
196
199
  const holderId = ((_a = booking.metadata) == null ? void 0 : _a.holder_id) ?? booking.holder_id;
197
200
  const productTitle = resolveProductTitle(product, booking, sourceProduct);
201
+ const productCover = resolveProductCover(product, booking, sourceProduct);
198
202
  const productOptionString = (0, import_orderLineDisplay.buildProductOptionStringFromOrderLine)(product);
199
203
  const other = {
200
204
  product_variant_id: product.product_variant_id ?? 0,
@@ -214,6 +218,7 @@ function buildCacheItemFromOrderLine(input) {
214
218
  sub_type: booking.sub_type,
215
219
  quantity: product.num ?? 1,
216
220
  product_name: productTitle,
221
+ product_cover: productCover,
217
222
  note: product.note ?? ((_b = booking == null ? void 0 : booking.detail) == null ? void 0 : _b.note) ?? "",
218
223
  price: mainProductPrice,
219
224
  total: selling,
@@ -136,6 +136,7 @@ function buildNormalProductCacheItemFromOrderLine(input) {
136
136
  product_id: resolvedId,
137
137
  _id: uid,
138
138
  title: (sourceProduct == null ? void 0 : sourceProduct.title) ?? product.product_title ?? "",
139
+ cover: (sourceProduct == null ? void 0 : sourceProduct.cover) ?? product.product_cover ?? "",
139
140
  price: (sourceProduct == null ? void 0 : sourceProduct.price) ?? sourcePrice,
140
141
  selling_price: product.selling_price,
141
142
  original_price: product.original_price,
@@ -463,7 +463,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
463
463
  generateIdempotencyToken(): string;
464
464
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
465
465
  createOrder(params: CommitOrderParams['query']): {
466
- type: "virtual" | "appointment_booking";
466
+ type: "appointment_booking" | "virtual";
467
467
  platform: string;
468
468
  sales_channel: string;
469
469
  order_sales_channel: string;
@@ -547,7 +547,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
547
547
  };
548
548
  }
549
549
  applyDiscount(options) {
550
- var _a, _b, _c, _d;
550
+ var _a, _b, _c;
551
551
  const tempOrder = this.store.tempOrder;
552
552
  if (!tempOrder)
553
553
  return;
@@ -560,13 +560,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
560
560
  const rulesModule = this.store.rules;
561
561
  if (!rulesModule)
562
562
  return;
563
- const holders = ((_b = tempOrder.holder) == null ? void 0 : _b.form_record) || [];
564
563
  const result = rulesModule.calcDiscount({
565
564
  productList: tempOrder.products,
566
565
  discountList,
567
- holders,
566
+ holders: [],
568
567
  isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
569
- orderTotalAmount: Number(((_c = this.store.summary) == null ? void 0 : _c.total_amount) || 0)
568
+ orderTotalAmount: Number(((_b = this.store.summary) == null ? void 0 : _b.total_amount) || 0)
570
569
  }, {
571
570
  reapplyBookingDiscountProductUids: options == null ? void 0 : options.reapplyBookingDiscountProductUids
572
571
  });
@@ -597,7 +596,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
597
596
  result.productList || tempOrder.products,
598
597
  result.discountList
599
598
  );
600
- (_d = this.store.discount) == null ? void 0 : _d.setDiscountList(result.discountList);
599
+ (_c = this.store.discount) == null ? void 0 : _c.setDiscountList(result.discountList);
601
600
  }
602
601
  this.hasActiveCustomerBoundDiscount = (tempOrder.products || []).some(
603
602
  (product) => this.productHasCustomerBoundDiscount(product)
@@ -1489,6 +1488,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1489
1488
  }
1490
1489
  restoreOriginalSnapshotIfProductsUnchanged(tempOrder, snapshot) {
1491
1490
  const currentFingerprint = this.buildOrderProductsFingerprint(tempOrder.products);
1491
+ const manualDepositOverride = this.getManualDepositOverride(tempOrder);
1492
1492
  if (currentFingerprint !== snapshot.productFingerprint) {
1493
1493
  const currentStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(tempOrder.products);
1494
1494
  const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(
@@ -1497,11 +1497,24 @@ var OrderModule = class extends import_BaseModule.BaseModule {
1497
1497
  if (currentStructuralFingerprint !== snapshotStructuralFingerprint)
1498
1498
  return null;
1499
1499
  }
1500
- const summary = {
1500
+ let summary = {
1501
1501
  ...(0, import_utils.createEmptySummary)(),
1502
1502
  ...(0, import_lodash_es.cloneDeep)(snapshot.summary || {})
1503
1503
  };
1504
- if (!this.isSnapshotPayableAmountUnchanged(tempOrder, snapshot, summary))
1504
+ const shouldUseManualDepositOverride = Boolean(
1505
+ manualDepositOverride && manualDepositOverride.productStructuralFingerprint === this.buildOrderProductsStructuralFingerprint(tempOrder.products)
1506
+ );
1507
+ if (shouldUseManualDepositOverride) {
1508
+ summary = this.applyDepositAmountToSummary(
1509
+ tempOrder,
1510
+ summary,
1511
+ manualDepositOverride.amount
1512
+ );
1513
+ } else if (manualDepositOverride) {
1514
+ this.clearManualDepositOverride(tempOrder);
1515
+ }
1516
+ const isPayableAmountUnchanged = this.isSnapshotPayableAmountUnchanged(tempOrder, snapshot, summary);
1517
+ if (!isPayableAmountUnchanged)
1505
1518
  return null;
1506
1519
  if (Array.isArray(snapshot.products)) {
1507
1520
  tempOrder.products = (0, import_lodash_es.cloneDeep)(snapshot.products);
@@ -3159,10 +3172,16 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3159
3172
  if (!paramsList.length) {
3160
3173
  return tempOrder.products;
3161
3174
  }
3162
- paramsList.forEach((params) => {
3163
- this.applyOrderProductUpdateToTempOrder(tempOrder, params);
3175
+ const reapplyBookingDiscountProductUids = paramsList.reduce((acc, params) => {
3176
+ const updatedProductUid = this.applyOrderProductUpdateToTempOrder(tempOrder, params);
3177
+ if (params.allow_booking_discount_reapply && updatedProductUid) {
3178
+ acc.push(String(updatedProductUid));
3179
+ }
3180
+ return acc;
3181
+ }, []);
3182
+ await this.finalizeAfterProductsMutation(tempOrder, {
3183
+ reapplyBookingDiscountProductUids: reapplyBookingDiscountProductUids.length ? reapplyBookingDiscountProductUids : void 0
3164
3184
  });
3165
- await this.finalizeAfterProductsMutation(tempOrder);
3166
3185
  this.logInfo("updateOrderProduct success", {
3167
3186
  paramsList
3168
3187
  });
@@ -3271,10 +3290,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
3271
3290
  * @example
3272
3291
  * await this.finalizeAfterProductsMutation(tempOrder);
3273
3292
  */
3274
- async finalizeAfterProductsMutation(tempOrder) {
3293
+ async finalizeAfterProductsMutation(tempOrder, options) {
3275
3294
  this.syncTempOrderHolderFromBookings(tempOrder);
3276
3295
  await this.applyPromotion();
3277
- this.applyDiscount();
3296
+ this.applyDiscount({
3297
+ reapplyBookingDiscountProductUids: options == null ? void 0 : options.reapplyBookingDiscountProductUids
3298
+ });
3278
3299
  this.sanitizeTempOrderProducts(tempOrder);
3279
3300
  await this.recalculateSummary({ createIfMissing: true });
3280
3301
  this.persistTempOrder();
@@ -4213,6 +4234,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
4213
4234
  if (!existingIdentity) {
4214
4235
  row.metadata.unique_identification_number = (0, import_utils.createUuidV4)();
4215
4236
  }
4237
+ row.metadata.is_edit_for_runtime = true;
4216
4238
  const normalized = (0, import_utils3.normalizeOrderProduct)(row);
4217
4239
  normalized.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
4218
4240
  normalized.discount_list
@@ -198,6 +198,7 @@ export interface OrderProduct extends OrderProductIdentity {
198
198
  product_bundle: any[];
199
199
  booking_uid?: string;
200
200
  product_title?: OrderLocalizedText;
201
+ product_cover?: string;
201
202
  metadata: Record<string, any>;
202
203
  note?: string;
203
204
  }
@@ -803,6 +803,9 @@ function normalizeSubmitProduct(product) {
803
803
  if (rawMetadata.is_rule !== void 0) {
804
804
  cleanMetadata.is_rule = rawMetadata.is_rule;
805
805
  }
806
+ if (rawMetadata.holder_config !== void 0) {
807
+ cleanMetadata.holder_config = rawMetadata.holder_config;
808
+ }
806
809
  const productSku = {
807
810
  ...submitProduct.product_sku && typeof submitProduct.product_sku === "object" ? submitProduct.product_sku : {},
808
811
  option: formatSubmitOptionItems((_a = submitProduct.product_sku) == null ? void 0 : _a.option)
@@ -1159,11 +1162,16 @@ function isHolderConfigRequired(holderConfig) {
1159
1162
  return Number(holderConfig.required) === 1;
1160
1163
  }
1161
1164
  function productRequiresFormSubject(tempOrder, product) {
1165
+ var _a, _b;
1166
+ const _orderProduct = (_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.find((item) => {
1167
+ return item.metadata.unique_identification_number === product._id || item.product_id === product.id;
1168
+ });
1162
1169
  const runtimeOrigin = getRuntimeProductOrigin(tempOrder, product);
1163
- return isHolderConfigRequired(product == null ? void 0 : product.holder_config) || isHolderConfigRequired(runtimeOrigin == null ? void 0 : runtimeOrigin.holder_config);
1170
+ return isHolderConfigRequired((_b = _orderProduct == null ? void 0 : _orderProduct.metadata) == null ? void 0 : _b.holder_config) || isHolderConfigRequired(runtimeOrigin == null ? void 0 : runtimeOrigin.holder_config) || isHolderConfigRequired(product == null ? void 0 : product.holder_config);
1164
1171
  }
1165
1172
  function resolveIsFormSubject(tempOrder, product) {
1166
1173
  var _a;
1174
+ debugger;
1167
1175
  if (((_a = tempOrder == null ? void 0 : tempOrder.holder) == null ? void 0 : _a.type) === "form")
1168
1176
  return true;
1169
1177
  if (product)
@@ -1192,6 +1200,7 @@ function mergeOrderProductDisplayFields(previous, next) {
1192
1200
  "product_name",
1193
1201
  "product_cover",
1194
1202
  "cover",
1203
+ "product_cover",
1195
1204
  "variant_title",
1196
1205
  "product_sku",
1197
1206
  "payment_price"
@@ -49,5 +49,5 @@ export declare class Product extends BaseModule implements Module {
49
49
  getCategories(): ProductCategory[];
50
50
  setOtherParams(key: string, value: any): void;
51
51
  getOtherParams(): any;
52
- getProductType(): "normal" | "duration" | "session";
52
+ getProductType(): "duration" | "session" | "normal";
53
53
  }
@@ -445,6 +445,10 @@ declare class Server {
445
445
  private sumPaidOrderPayments;
446
446
  private toAmountNumber;
447
447
  private buildSmallTicketProductMap;
448
+ private collectSalesDetailProductIds;
449
+ private buildSalesDetailProductSnapshotMap;
450
+ private withProductCatalogSnapshots;
451
+ private withSalesDetailProductSnapshots;
448
452
  private withPendingSyncProductTitles;
449
453
  private buildProductTitleSnapshot;
450
454
  private getProductTitleSnapshotCurrentLocale;
@@ -769,12 +769,13 @@ var Server = class {
769
769
  if (!this.shouldForceRemoteSalesDetail(data)) {
770
770
  const localOrder = await this.order.getLocalOrderByLookup(lookup);
771
771
  if (localOrder) {
772
+ const enrichedOrder = await this.withSalesDetailProductSnapshots(localOrder);
772
773
  this.logInfo("handleOrderSalesDetail: 命中本地订单", { lookup });
773
774
  return {
774
775
  code: 200,
775
776
  status: true,
776
777
  message: "",
777
- data: localOrder
778
+ data: enrichedOrder
778
779
  };
779
780
  }
780
781
  }
@@ -821,11 +822,12 @@ var Server = class {
821
822
  };
822
823
  }
823
824
  this.logInfo("handleOrderSalesDetail: 远端订单已同步到本地", { lookup });
825
+ const enrichedOrder = await this.withSalesDetailProductSnapshots(savedOrder);
824
826
  return {
825
827
  code: 200,
826
828
  status: true,
827
829
  message: "",
828
- data: savedOrder
830
+ data: enrichedOrder
829
831
  };
830
832
  } catch (error) {
831
833
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -3231,6 +3233,85 @@ var Server = class {
3231
3233
  return map;
3232
3234
  }, {});
3233
3235
  }
3236
+ collectSalesDetailProductIds(order) {
3237
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : [];
3238
+ const productIds = /* @__PURE__ */ new Set();
3239
+ products.forEach((product) => {
3240
+ const rawProductId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
3241
+ if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
3242
+ return;
3243
+ const productId = Number(rawProductId);
3244
+ if (Number.isFinite(productId))
3245
+ productIds.add(productId);
3246
+ });
3247
+ return Array.from(productIds);
3248
+ }
3249
+ async buildSalesDetailProductSnapshotMap(order) {
3250
+ var _a;
3251
+ const productIds = this.collectSalesDetailProductIds(order);
3252
+ const getSnapshots = (_a = this.products) == null ? void 0 : _a.getProductSnapshotsByIds;
3253
+ if (!productIds.length || typeof getSnapshots !== "function")
3254
+ return {};
3255
+ try {
3256
+ return await getSnapshots.call(this.products, productIds);
3257
+ } catch (error) {
3258
+ this.logWarning("buildSalesDetailProductSnapshotMap: 查询本地商品快照失败", {
3259
+ product_ids: productIds,
3260
+ error: error instanceof Error ? error.message : String(error)
3261
+ });
3262
+ return {};
3263
+ }
3264
+ }
3265
+ withProductCatalogSnapshots(product, snapshotMap) {
3266
+ if (!product || typeof product !== "object")
3267
+ return product;
3268
+ const rawProductId = (product == null ? void 0 : product.product_id) ?? (product == null ? void 0 : product.id);
3269
+ if (rawProductId === void 0 || rawProductId === null || rawProductId === "")
3270
+ return product;
3271
+ const productId = Number(rawProductId);
3272
+ if (!Number.isFinite(productId))
3273
+ return product;
3274
+ const snapshot = snapshotMap[String(productId)];
3275
+ if (!snapshot)
3276
+ return product;
3277
+ const shouldFillCover = (product.product_cover === void 0 || product.product_cover === null || product.product_cover === "") && snapshot.cover !== void 0 && snapshot.cover !== null && snapshot.cover !== "";
3278
+ const metadata = product.metadata && typeof product.metadata === "object" ? product.metadata : {};
3279
+ const shouldFillHolderConfig = (metadata.holder_config === void 0 || metadata.holder_config === null) && snapshot.holder_config !== void 0 && snapshot.holder_config !== null;
3280
+ if (!shouldFillCover && !shouldFillHolderConfig)
3281
+ return product;
3282
+ return {
3283
+ ...product,
3284
+ ...shouldFillCover ? { product_cover: snapshot.cover } : {},
3285
+ ...shouldFillHolderConfig ? {
3286
+ metadata: {
3287
+ ...metadata,
3288
+ holder_config: snapshot.holder_config
3289
+ }
3290
+ } : {}
3291
+ };
3292
+ }
3293
+ async withSalesDetailProductSnapshots(order) {
3294
+ const products = Array.isArray(order == null ? void 0 : order.products) ? order.products : null;
3295
+ if (!(products == null ? void 0 : products.length))
3296
+ return order;
3297
+ const snapshotMap = await this.buildSalesDetailProductSnapshotMap(order);
3298
+ if (!Object.keys(snapshotMap).length)
3299
+ return order;
3300
+ let hasChanged = false;
3301
+ const enrichedProducts = products.map((product) => {
3302
+ const nextProduct = this.withProductCatalogSnapshots(product, snapshotMap);
3303
+ if (nextProduct !== product)
3304
+ hasChanged = true;
3305
+ return nextProduct;
3306
+ });
3307
+ if (!hasChanged)
3308
+ return order;
3309
+ const enrichedOrder = {
3310
+ ...order,
3311
+ products: enrichedProducts
3312
+ };
3313
+ return enrichedOrder;
3314
+ }
3234
3315
  withPendingSyncProductTitles(order, productMap) {
3235
3316
  const products = Array.isArray(order.products) ? order.products : null;
3236
3317
  if (!(products == null ? void 0 : products.length))
@@ -104,6 +104,8 @@ export interface OrderProductLineItem {
104
104
  num: number;
105
105
  /** 商品标题快照;本地待同步订单会补齐为多语言对象。 */
106
106
  product_title?: OrderProductTitleSnapshot | string | null;
107
+ /** 商品封面图 */
108
+ product_cover?: string | null;
107
109
  /** 多规格 ID。来源:Detail.product_variant_id */
108
110
  product_variant_id?: number;
109
111
  /**
@@ -2,7 +2,7 @@ import { Module, PisellCore } from '../../../types';
2
2
  import { BaseModule } from '../../../modules/BaseModule';
3
3
  import { ProductData } from '../../../modules/Product/types';
4
4
  import type { RouteDefinition } from '../../types';
5
- import { ProductIdScope, ProductFormatter, ProductFormatterContext } from './types';
5
+ import { ProductIdScope, type ProductSnapshot, ProductFormatter, ProductFormatterContext } from './types';
6
6
  /**
7
7
  * Products 模块 - 用于获取和管理完整的商品详细数据
8
8
  * 相比 ProductList 模块,Products 会获取所有详细信息并缓存
@@ -185,6 +185,10 @@ export declare class ProductsModule extends BaseModule implements Module {
185
185
  * 获取商品列表(深拷贝,供外部安全使用)
186
186
  */
187
187
  getProducts(): Promise<ProductData[]>;
188
+ /**
189
+ * 批量获取商品轻量快照,供订单详情等响应补齐展示协议字段。
190
+ */
191
+ getProductSnapshotsByIds(ids: number[]): Promise<Record<string, ProductSnapshot>>;
188
192
  /**
189
193
  * 内部获取商品列表的直接引用(无拷贝)
190
194
  * 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
@@ -860,6 +860,26 @@ var ProductsModule = class extends import_BaseModule.BaseModule {
860
860
  (0, import_product.perfMark)("ProductsModule.getProducts(structuredClone)", performance.now() - t0, { count: result.length });
861
861
  return result;
862
862
  }
863
+ /**
864
+ * 批量获取商品轻量快照,供订单详情等响应补齐展示协议字段。
865
+ */
866
+ async getProductSnapshotsByIds(ids) {
867
+ const snapshots = {};
868
+ const seen = /* @__PURE__ */ new Set();
869
+ for (const id of ids) {
870
+ if (!Number.isFinite(id) || seen.has(id))
871
+ continue;
872
+ seen.add(id);
873
+ const product = this.store.map.get(id);
874
+ if (!product)
875
+ continue;
876
+ snapshots[String(id)] = {
877
+ cover: product.cover,
878
+ holder_config: product.holder_config
879
+ };
880
+ }
881
+ return snapshots;
882
+ }
863
883
  /**
864
884
  * 内部获取商品列表的直接引用(无拷贝)
865
885
  * 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
@@ -28,6 +28,10 @@ export interface ProductIdScope {
28
28
  /** 指定商品集合 ID */
29
29
  collectionIds?: number[];
30
30
  }
31
+ export interface ProductSnapshot {
32
+ cover?: ProductData['cover'];
33
+ holder_config?: ProductData['holder_config'];
34
+ }
31
35
  /**
32
36
  * 加载报价单商品价格参数
33
37
  */
@@ -102,7 +102,25 @@ function getBaseSalesMetadataUid(item, metadataKey) {
102
102
  return null;
103
103
  return String(uid);
104
104
  }
105
- function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
105
+ function isBaseSalesBlankValue(value) {
106
+ return value === void 0 || value === null || value === "";
107
+ }
108
+ function mergeBaseSalesProductSnapshotFields(currentItem, loadedItem) {
109
+ var _a, _b, _c;
110
+ const mergedItem = (0, import_lodash_es.cloneDeep)(loadedItem);
111
+ if (isBaseSalesBlankValue(mergedItem.product_cover) && !isBaseSalesBlankValue(currentItem == null ? void 0 : currentItem.product_cover)) {
112
+ mergedItem.product_cover = currentItem.product_cover;
113
+ }
114
+ const currentHolderConfig = (_a = currentItem == null ? void 0 : currentItem.metadata) == null ? void 0 : _a.holder_config;
115
+ if ((((_b = mergedItem.metadata) == null ? void 0 : _b.holder_config) === void 0 || ((_c = mergedItem.metadata) == null ? void 0 : _c.holder_config) === null) && currentHolderConfig !== void 0 && currentHolderConfig !== null) {
116
+ mergedItem.metadata = {
117
+ ...mergedItem.metadata || {},
118
+ holder_config: currentHolderConfig
119
+ };
120
+ }
121
+ return mergedItem;
122
+ }
123
+ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey, arrayKey) {
106
124
  const result = [];
107
125
  const indexByUid = /* @__PURE__ */ new Map();
108
126
  const appendOrReplaceByUid = (item) => {
@@ -114,7 +132,7 @@ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
114
132
  }
115
133
  const existingIndex = indexByUid.get(uid);
116
134
  if (existingIndex !== void 0) {
117
- result[existingIndex] = clonedItem;
135
+ result[existingIndex] = arrayKey === "products" ? mergeBaseSalesProductSnapshotFields(result[existingIndex], clonedItem) : clonedItem;
118
136
  return;
119
137
  }
120
138
  indexByUid.set(uid, result.length);
@@ -134,7 +152,7 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord) {
134
152
  if (Array.isArray(currentValue) && Array.isArray(loadedValue)) {
135
153
  const metadataKey = getBaseSalesUniqueArrayMetadataKey(key);
136
154
  if (metadataKey) {
137
- return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey);
155
+ return mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey, key);
138
156
  }
139
157
  return [
140
158
  ...(0, import_lodash_es.cloneDeep)(currentValue),
@@ -260,7 +278,10 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
260
278
  if (!this.store.order)
261
279
  return;
262
280
  this.serverOrderChangeHydrateInFlight = (async () => {
263
- const sales = await this.store.order.hydrateTempOrderFromRecord(changedOrder, {
281
+ var _a, _b;
282
+ const currentTempOrder = (_b = (_a = this.store.order).getTempOrder) == null ? void 0 : _b.call(_a);
283
+ const record = mergeSalesDetailRecordWithTempOrder(currentTempOrder, changedOrder);
284
+ const sales = await this.store.order.hydrateTempOrderFromRecord(record, {
264
285
  recalcOnHydrate: false
265
286
  });
266
287
  this.currentSalesDetail = sales;
@@ -1094,7 +1115,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1094
1115
  });
1095
1116
  }
1096
1117
  async loadDiscountConfig(params) {
1097
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
1118
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
1098
1119
  if (!this.store.order)
1099
1120
  throw new Error("order 模块未初始化");
1100
1121
  const tempOrder = this.store.order.ensureTempOrder();
@@ -1165,13 +1186,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1165
1186
  };
1166
1187
  }
1167
1188
  if (rulesModule) {
1168
- const holders = ((_l = tempOrder.holder) == null ? void 0 : _l.form_record) || [];
1169
- const orderTotalAmount = Number(((_m = orderStore.summary) == null ? void 0 : _m.total_amount) || 0);
1189
+ const orderTotalAmount = Number(((_l = orderStore.summary) == null ? void 0 : _l.total_amount) || 0);
1170
1190
  console.log("[BaseSales.applyDiscountConfig.calcDiscount]");
1171
1191
  const result = rulesModule.calcDiscount({
1172
1192
  productList: tempOrder.products,
1173
1193
  discountList: nextDiscountList,
1174
- holders,
1194
+ holders: [],
1175
1195
  isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
1176
1196
  orderTotalAmount
1177
1197
  }) || { productList: tempOrder.products, discountList: nextDiscountList };
@@ -1182,8 +1202,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1182
1202
  );
1183
1203
  }
1184
1204
  for (const product of tempOrder.products || []) {
1185
- const productUid = (_n = product.metadata) == null ? void 0 : _n.unique_identification_number;
1186
- const runtimeOrigin = productUid ? (_q = (_p = (_o = tempOrder._extend) == null ? void 0 : _o.productsByUid) == null ? void 0 : _p[productUid]) == null ? void 0 : _q.origin : void 0;
1205
+ const productUid = (_m = product.metadata) == null ? void 0 : _m.unique_identification_number;
1206
+ const runtimeOrigin = productUid ? (_p = (_o = (_n = tempOrder._extend) == null ? void 0 : _n.productsByUid) == null ? void 0 : _o[productUid]) == null ? void 0 : _p.origin : void 0;
1187
1207
  if ((runtimeOrigin == null ? void 0 : runtimeOrigin.isManualDiscount) || isBaseSalesManualProductDiscountProduct(product))
1188
1208
  continue;
1189
1209
  const totalPerUnitDiscount = (product.discount_list || []).reduce(
@@ -1191,7 +1211,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1191
1211
  0
1192
1212
  );
1193
1213
  const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
1194
- const sourcePrice = ((_r = product.metadata) == null ? void 0 : _r.source_product_price) ?? (((_s = product.metadata) == null ? void 0 : _s.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1214
+ const sourcePrice = ((_q = product.metadata) == null ? void 0 : _q.source_product_price) ?? (((_r = product.metadata) == null ? void 0 : _r.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1195
1215
  const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
1196
1216
  const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
1197
1217
  if (product.metadata) {
@@ -1227,7 +1247,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1227
1247
  };
1228
1248
  }
1229
1249
  async bestDiscount(cb) {
1230
- var _a, _b, _c, _d;
1250
+ var _a, _b, _c;
1231
1251
  if (!this.store.order)
1232
1252
  throw new Error("order 模块未初始化");
1233
1253
  const tempOrder = this.store.order.ensureTempOrder();
@@ -1246,13 +1266,12 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1246
1266
  };
1247
1267
  await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
1248
1268
  if (rulesModule) {
1249
- const holders = ((_c = tempOrder.holder) == null ? void 0 : _c.form_record) || [];
1250
- const orderTotalAmount = Number(((_d = orderStore.summary) == null ? void 0 : _d.total_amount) || 0);
1269
+ const orderTotalAmount = Number(((_c = orderStore.summary) == null ? void 0 : _c.total_amount) || 0);
1251
1270
  console.log("[BaseSales.bestDiscount.calcDiscount]");
1252
1271
  result = rulesModule.calcDiscount({
1253
1272
  productList: tempOrder.products,
1254
1273
  discountList: nextDiscountList,
1255
- holders,
1274
+ holders: [],
1256
1275
  isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
1257
1276
  orderTotalAmount
1258
1277
  }) || result;
@@ -1306,7 +1325,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1306
1325
  }
1307
1326
  // TODO 需要优化,这段逻辑太长了,里面应该有些历史遗留问题
1308
1327
  async setDiscountSelected(params) {
1309
- var _a, _b, _c, _d, _e, _f, _g, _h;
1328
+ var _a, _b, _c, _d, _e, _f, _g;
1310
1329
  try {
1311
1330
  if (!this.store.order)
1312
1331
  throw new Error("order 模块未初始化");
@@ -1323,17 +1342,16 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1323
1342
  const orderStore = this.store.order.store || {};
1324
1343
  const discountModule = orderStore.discount;
1325
1344
  const rulesModule = orderStore.rules;
1326
- const holders = ((_a = tempOrder.holder) == null ? void 0 : _a.form_record) || [];
1327
1345
  let nextDiscountList = updated;
1328
1346
  await (discountModule == null ? void 0 : discountModule.setDiscountList(updated));
1329
1347
  if (rulesModule) {
1330
- const orderTotalAmount = Number(((_b = orderStore.summary) == null ? void 0 : _b.total_amount) || 0);
1348
+ const orderTotalAmount = Number(((_a = orderStore.summary) == null ? void 0 : _a.total_amount) || 0);
1331
1349
  console.log("[BaseSales.setDiscountSelected.calcDiscount]");
1332
1350
  const result = rulesModule.calcDiscount(
1333
1351
  {
1334
1352
  productList: tempOrder.products,
1335
1353
  discountList: updated,
1336
- holders,
1354
+ holders: [],
1337
1355
  isFormSubject: (product) => (0, import_utils.resolveIsFormSubject)(tempOrder, product),
1338
1356
  orderTotalAmount
1339
1357
  },
@@ -1373,8 +1391,8 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1373
1391
  return rid != null && selectedResourceIds.has(rid);
1374
1392
  });
1375
1393
  for (const product of tempOrder.products) {
1376
- const productUid = (_c = product.metadata) == null ? void 0 : _c.unique_identification_number;
1377
- const runtimeOrigin = productUid ? (_f = (_e = (_d = tempOrder._extend) == null ? void 0 : _d.productsByUid) == null ? void 0 : _e[productUid]) == null ? void 0 : _f.origin : void 0;
1394
+ const productUid = (_b = product.metadata) == null ? void 0 : _b.unique_identification_number;
1395
+ const runtimeOrigin = productUid ? (_e = (_d = (_c = tempOrder._extend) == null ? void 0 : _c.productsByUid) == null ? void 0 : _d[productUid]) == null ? void 0 : _e.origin : void 0;
1378
1396
  if ((runtimeOrigin == null ? void 0 : runtimeOrigin.isManualDiscount) || isBaseSalesManualProductDiscountProduct(product))
1379
1397
  continue;
1380
1398
  product.discount_list = filterSelectedDiscountDetails(product.discount_list);
@@ -1398,7 +1416,7 @@ var BaseSalesImpl = class extends import_BaseModule.BaseModule {
1398
1416
  0
1399
1417
  );
1400
1418
  const optionSum = (0, import_utils.sumOptionUnitPrice)((0, import_utils.getProductSkuOptions)(product));
1401
- const sourcePrice = ((_g = product.metadata) == null ? void 0 : _g.source_product_price) ?? (((_h = product.metadata) == null ? void 0 : _h.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1419
+ const sourcePrice = ((_f = product.metadata) == null ? void 0 : _f.source_product_price) ?? (((_g = product.metadata) == null ? void 0 : _g.main_product_original_price) != null ? new import_decimal.default(Number(product.metadata.main_product_original_price) || 0).minus(optionSum).toFixed(2) : product.original_price ?? "0");
1402
1420
  const newSourceSellingPrice = new import_decimal.default(Number(sourcePrice) || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
1403
1421
  const newMainSellingPrice = new import_decimal.default(Number(newSourceSellingPrice) || 0).plus(optionSum).toDecimalPlaces(2).toFixed(2);
1404
1422
  if (product.metadata) {
@@ -85,6 +85,8 @@ export interface BaseSalesOrderProduct extends BaseSalesOrderProductIdentity {
85
85
  booking_uid?: string;
86
86
  /** 多语言商品标题快照,随 tempOrder 提交到 checkout。 */
87
87
  product_title?: BaseSalesLocalizedText;
88
+ /** 商品封面图快照,随 tempOrder 提交到 checkout。 */
89
+ product_cover?: string;
88
90
  /**
89
91
  * 行级扩展 metadata。价格相关的权威字段:
90
92
  *
@@ -198,6 +198,7 @@ function transformBaseProductToOrderProduct(params) {
198
198
  main_product_selling_price: mainProductSellingPrice,
199
199
  main_product_original_price: mainProductOriginalPrice,
200
200
  price_schema_version: 2,
201
+ holder_config: sourceProduct == null ? void 0 : sourceProduct.holder_config,
201
202
  ...hasPriceOverride ? {
202
203
  price_override: String(payload.price_override),
203
204
  is_manual_discount: 1
@@ -236,6 +237,7 @@ function transformBaseProductToOrderProduct(params) {
236
237
  metadata,
237
238
  note: payload.note != null ? String(payload.note) : "",
238
239
  product_title: productTitle,
240
+ product_cover: sourceProduct == null ? void 0 : sourceProduct.cover,
239
241
  _origin: {
240
242
  ...sourceProduct || {},
241
243
  callbackData: payload