@pisell/pisellos 1.0.76 → 1.0.78

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.
@@ -130,6 +130,49 @@ var RulesModule = class extends import_BaseModule.BaseModule {
130
130
  const filteredDiscountList = addModeDiscount.filter((discount) => {
131
131
  return !discount.isManualSelect;
132
132
  });
133
+ const flattenProductsWithBundle = (productList2) => {
134
+ const flattened = [];
135
+ productList2.forEach((originProduct) => {
136
+ const product = this.hooks.getProduct(originProduct);
137
+ flattened.push({
138
+ type: "main",
139
+ originProduct,
140
+ product,
141
+ price: Number(product.price || 0),
142
+ id: product.id,
143
+ _id: product._id,
144
+ parentId: product._id,
145
+ quantity: product.quantity,
146
+ num: product.num
147
+ });
148
+ if (product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0) {
149
+ product.bundle.forEach((bundleItem, bundleIndex) => {
150
+ flattened.push({
151
+ type: "bundle",
152
+ originProduct,
153
+ parentProduct: product,
154
+ bundleItem,
155
+ bundleIndex,
156
+ // 虚拟商品属性
157
+ price: Number(bundleItem.price || 0),
158
+ id: bundleItem._bundle_product_id,
159
+ // 🔥 使用 _bundle_product_id
160
+ _id: `${product._id}_bundle_${bundleIndex}`,
161
+ parentId: product._id,
162
+ num: bundleItem.num || 1,
163
+ quantity: bundleItem.num || 1,
164
+ total: new import_decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
165
+ origin_total: new import_decimal.default(bundleItem.price || 0).mul(bundleItem.num || 1).toNumber(),
166
+ original_price: bundleItem.original_price,
167
+ // 继承主商品属性
168
+ booking_id: product.booking_id,
169
+ discount_list: []
170
+ });
171
+ });
172
+ }
173
+ });
174
+ return flattened;
175
+ };
133
176
  const sortedDiscountList = [...filteredDiscountList].sort((a, b) => {
134
177
  var _a, _b;
135
178
  if (a.tag === "good_pass" && b.tag !== "good_pass")
@@ -156,7 +199,7 @@ var RulesModule = class extends import_BaseModule.BaseModule {
156
199
  if (a.par_value !== b.par_value) {
157
200
  const valueA = new import_decimal.default(100).minus(a.par_value || 0);
158
201
  const valueB = new import_decimal.default(100).minus(b.par_value || 0);
159
- return valueB.minus(valueA).toNumber();
202
+ return valueA.minus(valueB).toNumber();
160
203
  }
161
204
  }
162
205
  return compareByExpireTime(a, b);
@@ -171,19 +214,26 @@ var RulesModule = class extends import_BaseModule.BaseModule {
171
214
  return itemA.expire_time ? -1 : itemB.expire_time ? 1 : 0;
172
215
  }
173
216
  });
174
- const sortedProductList = [...productList].sort((a, b) => {
217
+ const flattenedList = flattenProductsWithBundle(productList);
218
+ const sortedFlattenedList = flattenedList.sort((a, b) => {
175
219
  var _a, _b;
176
- const aProduct = this.hooks.getProduct(a);
177
- const bProduct = this.hooks.getProduct(b);
178
- const priceA = new import_decimal.default(aProduct.price || "0");
179
- const priceB = new import_decimal.default(bProduct.price || "0");
180
- if (priceA.toNumber() === priceB.toNumber()) {
181
- if (aProduct.quantity === bProduct.quantity) {
182
- return ((_a = bProduct.discount_list) == null ? void 0 : _a.length) - ((_b = aProduct.discount_list) == null ? void 0 : _b.length);
220
+ const priceA = new import_decimal.default(a.price || "0");
221
+ const priceB = new import_decimal.default(b.price || "0");
222
+ if (priceA.equals(priceB)) {
223
+ if (a.type !== b.type) {
224
+ return a.type === "main" ? -1 : 1;
225
+ }
226
+ if (a.type === "main" && b.type === "main") {
227
+ if (a.product.quantity === b.product.quantity) {
228
+ return (((_a = b.product.discount_list) == null ? void 0 : _a.length) || 0) - (((_b = a.product.discount_list) == null ? void 0 : _b.length) || 0);
229
+ }
230
+ return a.product.quantity - b.product.quantity;
231
+ }
232
+ if (a.type === "bundle" && b.type === "bundle") {
233
+ return (a.num || 1) - (b.num || 1);
183
234
  }
184
- return aProduct.quantity - bProduct.quantity;
185
235
  }
186
- return priceB.toNumber() - priceA.toNumber();
236
+ return priceB.minus(priceA).toNumber();
187
237
  });
188
238
  const usedDiscounts = /* @__PURE__ */ new Map();
189
239
  const discountApplicability = /* @__PURE__ */ new Map();
@@ -194,15 +244,32 @@ var RulesModule = class extends import_BaseModule.BaseModule {
194
244
  });
195
245
  const processedProductsMap = /* @__PURE__ */ new Map();
196
246
  const appliedDiscountProducts = /* @__PURE__ */ new Map();
197
- sortedProductList.forEach((originProduct) => {
198
- const product = this.hooks.getProduct(originProduct);
247
+ sortedFlattenedList.forEach((flatItem) => {
248
+ let product, originProduct;
249
+ if (flatItem.type === "main") {
250
+ product = flatItem.product;
251
+ originProduct = flatItem.originProduct;
252
+ } else {
253
+ product = {
254
+ _id: flatItem._id,
255
+ id: flatItem.id,
256
+ price: flatItem.price,
257
+ quantity: flatItem.quantity,
258
+ num: flatItem.num,
259
+ total: flatItem.total,
260
+ origin_total: flatItem.origin_total,
261
+ booking_id: flatItem.booking_id,
262
+ discount_list: []
263
+ };
264
+ originProduct = flatItem.originProduct;
265
+ }
199
266
  addModeDiscount.forEach((discount) => {
200
- var _a, _b, _c, _d;
267
+ var _a, _b, _c, _d, _e, _f;
201
268
  const limitedData = discount == null ? void 0 : discount.limited_relation_product_data;
202
269
  const isLimitedProduct = limitedData.type === "product_all" || limitedData.product_ids && limitedData.product_ids.includes(product.id);
203
- const isAvailableProduct = !((product == null ? void 0 : product.booking_id) && ((_a = product == null ? void 0 : product.discount_list) == null ? void 0 : _a.length) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.every((discount2) => discount2.id && ["good_pass", "discount_card", "product_discount_card"].includes(discount2.tag || discount2.type))));
270
+ const isAvailableProduct = flatItem.type === "main" ? !((product == null ? void 0 : product.booking_id) && ((_a = product == null ? void 0 : product.discount_list) == null ? void 0 : _a.length) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.every((discount2) => discount2.id && ["good_pass", "discount_card", "product_discount_card"].includes(discount2.tag || discount2.type)))) : !((flatItem == null ? void 0 : flatItem.booking_id) && ((_d = (_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.metadata) == null ? void 0 : _d.custom_product_bundle_map_id));
204
271
  if (isAvailableProduct && isLimitedProduct) {
205
- (_c = discountApplicability.get(discount.id)) == null ? void 0 : _c.push(product.id);
272
+ (_e = discountApplicability.get(discount.id)) == null ? void 0 : _e.push(product.id);
206
273
  const applicableProducts = discountApplicableProducts.get(discount.id) || [];
207
274
  const discountType = discount.tag || discount.type;
208
275
  const productData = {
@@ -210,11 +277,11 @@ var RulesModule = class extends import_BaseModule.BaseModule {
210
277
  type: discountType,
211
278
  tag: discountType,
212
279
  discount: {
213
- discount_card_type: (_d = discount == null ? void 0 : discount.metadata) == null ? void 0 : _d.discount_card_type,
280
+ discount_card_type: (_f = discount == null ? void 0 : discount.metadata) == null ? void 0 : _f.discount_card_type,
214
281
  fixed_amount: product.price,
215
282
  resource_id: discount.id,
216
283
  title: discount.format_title,
217
- original_amount: product.origin_total,
284
+ original_amount: product.price || product.origin_total,
218
285
  pre_value: discount.par_value,
219
286
  product_id: originProduct.id
220
287
  }
@@ -227,17 +294,42 @@ var RulesModule = class extends import_BaseModule.BaseModule {
227
294
  }
228
295
  });
229
296
  });
230
- console.log(sortedProductList, "sortedProductListsortedProductList");
231
- sortedProductList.forEach((originProduct, index) => {
232
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
233
- const product = this.hooks.getProduct(originProduct);
234
- if ((product == null ? void 0 : product.booking_id) && ((_a = product.discount_list) == null ? void 0 : _a.length) && ((_b = product == null ? void 0 : product.discount_list) == null ? void 0 : _b.every((discount) => discount.id && ["good_pass", "discount_card", "product_discount_card"].includes(discount.tag || discount.type)))) {
235
- processedProductsMap.set(product._id, [originProduct]);
297
+ const processedFlatItemsMap = /* @__PURE__ */ new Map();
298
+ sortedFlattenedList.forEach((flatItem, index) => {
299
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
300
+ let product, originProduct;
301
+ if (flatItem.type === "main") {
302
+ product = flatItem.product;
303
+ originProduct = flatItem.originProduct;
304
+ } else {
305
+ product = {
306
+ _id: flatItem._id,
307
+ id: flatItem.id,
308
+ price: flatItem.price,
309
+ quantity: flatItem.quantity,
310
+ num: flatItem.num,
311
+ total: flatItem.total,
312
+ original_price: (_a = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _a.original_price,
313
+ origin_total: (_b = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _b.original_price,
314
+ booking_id: flatItem.booking_id,
315
+ discount_list: ((_c = flatItem == null ? void 0 : flatItem.bundleItem) == null ? void 0 : _c.discount_list) || []
316
+ };
317
+ originProduct = flatItem.originProduct;
318
+ }
319
+ if ((product == null ? void 0 : product.booking_id) && ((_d = product.discount_list) == null ? void 0 : _d.length) && ((_e = product == null ? void 0 : product.discount_list) == null ? void 0 : _e.every((discount) => discount.id && ["good_pass", "discount_card", "product_discount_card"].includes(discount.tag || discount.type)))) {
320
+ if (flatItem.type === "main") {
321
+ processedProductsMap.set(product._id, [originProduct]);
322
+ } else {
323
+ processedFlatItemsMap.set(flatItem._id, [{
324
+ ...flatItem,
325
+ processed: true
326
+ }]);
327
+ }
236
328
  return;
237
329
  }
238
330
  const applicableDiscounts = sortedDiscountList.filter((discount) => {
239
331
  var _a2;
240
- if ((Number(product.price) <= 0 || !product.price) && (discount.tag || discount.type) === "good_pass")
332
+ if ((Number(product.price) <= 0 || !product.price) && flatItem.type === "main" && (discount.tag || discount.type) === "good_pass")
241
333
  return false;
242
334
  if ((Number(product.total) <= 0 || !product.total) && !((_a2 = product.discount_list) == null ? void 0 : _a2.find((n) => {
243
335
  var _a3;
@@ -249,22 +341,31 @@ var RulesModule = class extends import_BaseModule.BaseModule {
249
341
  return false;
250
342
  const limitedData = discount.limited_relation_product_data;
251
343
  if (limitedData.type === "product_all") {
344
+ if (!this.checkPackageSubItemUsageRules(discount, flatItem)) {
345
+ return false;
346
+ }
252
347
  return true;
253
348
  } else if (limitedData.product_ids && limitedData.product_ids.includes(product.id)) {
349
+ if (!this.checkPackageSubItemUsageRules(discount, flatItem)) {
350
+ return false;
351
+ }
254
352
  return true;
255
353
  }
256
354
  return false;
257
355
  });
258
356
  const selectedDiscountCard = applicableDiscounts.find((n) => n.isScan && n.isSelected && (n.tag || n.type) !== "good_pass");
259
357
  const selectedDiscount = selectedDiscountCard || applicableDiscounts[0];
260
- let isManualDiscount = typeof product.isManualDiscount === "boolean" ? product.isManualDiscount : product.total != product.origin_total && (!((_c = product.discount_list) == null ? void 0 : _c.length) || ((_e = (_d = product == null ? void 0 : product.discount_list) == null ? void 0 : _d.every) == null ? void 0 : _e.call(_d, (item) => item.type === "product")));
261
- if ((options == null ? void 0 : options.discountId) && ((_f = product.discount_list) == null ? void 0 : _f.some((item) => {
358
+ let isManualDiscount = typeof product.isManualDiscount === "boolean" ? product.isManualDiscount : product.total != product.origin_total && (flatItem.type === "main" && (product.bundle || []).every((item) => {
359
+ var _a2;
360
+ return !((_a2 = item.discount_list || []) == null ? void 0 : _a2.length);
361
+ })) && (!((_f = product.discount_list) == null ? void 0 : _f.length) || ((_h = (_g = product == null ? void 0 : product.discount_list) == null ? void 0 : _g.every) == null ? void 0 : _h.call(_g, (item) => item.type === "product")));
362
+ if ((options == null ? void 0 : options.discountId) && ((_i = product.discount_list) == null ? void 0 : _i.some((item) => {
262
363
  var _a2;
263
364
  return ((_a2 = item.discount) == null ? void 0 : _a2.resource_id) === options.discountId;
264
365
  }))) {
265
366
  isManualDiscount = false;
266
367
  }
267
- if ((options == null ? void 0 : options.selectedList) && ((_g = product.discount_list) == null ? void 0 : _g.some((item) => {
368
+ if ((options == null ? void 0 : options.selectedList) && ((_j = product.discount_list) == null ? void 0 : _j.some((item) => {
268
369
  var _a2;
269
370
  return (_a2 = options == null ? void 0 : options.selectedList) == null ? void 0 : _a2.some((n) => {
270
371
  var _a3;
@@ -274,44 +375,53 @@ var RulesModule = class extends import_BaseModule.BaseModule {
274
375
  isManualDiscount = false;
275
376
  }
276
377
  if (applicableDiscounts.length === 0 || isManualDiscount || (0, import_lodash_es.isBoolean)(product.vouchersApplicable) && !product.vouchersApplicable) {
277
- if (product.isClient) {
278
- processedProductsMap.set(
279
- product._id,
280
- [this.hooks.setProduct(originProduct, {
281
- ...isManualDiscount ? {} : {
282
- origin_total: (0, import_utils2.getProductOriginTotalPrice)({
283
- product: {
284
- original_price: product.original_price
285
- },
286
- bundle: product.bundle,
287
- options: product.options
288
- }),
289
- variant: originProduct._productInit.variant,
290
- original_price: originProduct._productInit.original_price,
291
- total: (0, import_utils2.getProductTotalPrice)({
292
- product: {
293
- price: product.price
294
- },
295
- bundle: product.bundle,
296
- options: product.options
297
- }),
298
- price: product.price
299
- },
300
- discount_list: []
301
- })]
302
- );
378
+ if (flatItem.type === "main") {
379
+ if (product.isClient) {
380
+ processedProductsMap.set(
381
+ product._id,
382
+ [this.hooks.setProduct(originProduct, {
383
+ ...isManualDiscount ? {} : {
384
+ origin_total: (0, import_utils2.getProductOriginTotalPrice)({
385
+ product: {
386
+ original_price: product.original_price
387
+ },
388
+ bundle: product.bundle,
389
+ options: product.options
390
+ }),
391
+ variant: originProduct._productInit.variant,
392
+ original_price: originProduct._productInit.original_price,
393
+ total: (0, import_utils2.getProductTotalPrice)({
394
+ product: {
395
+ price: product.price
396
+ },
397
+ bundle: product.bundle,
398
+ options: product.options
399
+ }),
400
+ price: product.price
401
+ },
402
+ discount_list: []
403
+ })]
404
+ );
405
+ } else {
406
+ processedProductsMap.set(
407
+ product._id,
408
+ [this.hooks.setProduct(originProduct, {
409
+ ...isManualDiscount ? {} : {
410
+ _id: product._id.split("___")[0] + "___" + index,
411
+ total: product.origin_total || product.total,
412
+ price: product.price
413
+ },
414
+ discount_list: []
415
+ })]
416
+ );
417
+ }
303
418
  } else {
304
- processedProductsMap.set(
305
- product._id,
306
- [this.hooks.setProduct(originProduct, {
307
- ...isManualDiscount ? {} : {
308
- _id: product._id.split("___")[0] + "___" + index,
309
- total: product.origin_total || product.total,
310
- price: product.price
311
- },
312
- discount_list: []
313
- })]
314
- );
419
+ processedFlatItemsMap.set(flatItem._id, [{
420
+ ...flatItem,
421
+ discount_list: [],
422
+ price: flatItem.bundleItem.original_price,
423
+ processed: true
424
+ }]);
315
425
  }
316
426
  return;
317
427
  }
@@ -319,113 +429,465 @@ var RulesModule = class extends import_BaseModule.BaseModule {
319
429
  return;
320
430
  }
321
431
  const isNeedSplit = (selectedDiscount.tag || selectedDiscount.type) === "good_pass";
322
- const splitCount = isNeedSplit ? Math.min(product.quantity || product.num || 1, applicableDiscounts.filter((item) => (item.tag || item.type) === "good_pass").length) : 1;
432
+ const totalQuantity = product.quantity || product.num || 1;
433
+ const availableGoodPassCount = applicableDiscounts.filter((item) => (item.tag || item.type) === "good_pass").length;
434
+ const splitCount = isNeedSplit ? Math.min(totalQuantity, availableGoodPassCount) : 1;
323
435
  const arr = [];
324
- if (splitCount < product.quantity && isNeedSplit) {
325
- arr.push(this.hooks.setProduct(originProduct, {
326
- discount_list: [],
327
- quantity: product.quantity - splitCount,
328
- _id: product._id.split("___")[0]
329
- }));
330
- }
331
- for (let i = 0; i < splitCount; i++) {
332
- const selectedDiscount2 = selectedDiscountCard || applicableDiscounts[i];
333
- usedDiscounts.set(selectedDiscount2.id, true);
334
- const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
335
- let productOriginTotal = product.origin_total || product.total || 0;
336
- if (((_h = product.discount_list) == null ? void 0 : _h.length) && product.origin_total) {
337
- productOriginTotal = product.origin_total;
338
- }
339
- if (Number(((_i = originProduct == null ? void 0 : originProduct._productInit) == null ? void 0 : _i.original_price) || 0) > 0 && product.origin_total && product.total && product.origin_total !== product.total) {
340
- productOriginTotal = product.total;
436
+ if (flatItem.type === "main") {
437
+ if (splitCount < totalQuantity && isNeedSplit) {
438
+ arr.push(this.hooks.setProduct(originProduct, {
439
+ discount_list: [],
440
+ quantity: totalQuantity - splitCount,
441
+ _id: product._id.split("___")[0]
442
+ }));
341
443
  }
342
- const targetProductTotal = (0, import_utils.getDiscountAmount)(selectedDiscount2, productOriginTotal, product.price);
343
- const discountType = selectedDiscount2.tag === "product_discount_card" ? "discount_card" : selectedDiscount2.tag;
344
- const discountDetail = {
345
- amount: new import_decimal.default(productOriginTotal).minus(new import_decimal.default(targetProductTotal)).toNumber(),
346
- type: discountType,
347
- discount: {
348
- discount_card_type: (_j = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _j.discount_card_type,
349
- fixed_amount: new import_decimal.default(productOriginTotal).minus(new import_decimal.default(targetProductTotal)).toNumber(),
350
- resource_id: selectedDiscount2.id,
351
- title: selectedDiscount2.format_title,
352
- original_amount: productOriginTotal,
353
- product_id: originProduct.id,
354
- percent: selectedDiscount2.par_value
444
+ for (let i = 0; i < splitCount; i++) {
445
+ const selectedDiscount2 = selectedDiscountCard || applicableDiscounts[i];
446
+ usedDiscounts.set(selectedDiscount2.id, true);
447
+ const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
448
+ let productOriginTotal = product.origin_total || product.total || 0;
449
+ if (((_k = product.discount_list) == null ? void 0 : _k.length) && product.origin_total) {
450
+ productOriginTotal = product.origin_total;
451
+ }
452
+ if (Number(((_l = originProduct == null ? void 0 : originProduct._productInit) == null ? void 0 : _l.original_price) || 0) > 0 && product.origin_total && product.total && product.origin_total !== product.total) {
453
+ productOriginTotal = product.total;
454
+ }
455
+ const targetProductTotal = (0, import_utils.getDiscountAmount)(selectedDiscount2, product.price, product.price);
456
+ const discountDetail = {
457
+ amount: new import_decimal.default(product.price).minus(new import_decimal.default(targetProductTotal)).toNumber(),
458
+ type: selectedDiscount2.tag === "product_discount_card" ? "discount_card" : selectedDiscount2.tag,
459
+ discount: {
460
+ discount_card_type: (_m = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _m.discount_card_type,
461
+ fixed_amount: new import_decimal.default(product.price).minus(new import_decimal.default(targetProductTotal)).toNumber(),
462
+ resource_id: selectedDiscount2.id,
463
+ title: selectedDiscount2.format_title,
464
+ original_amount: product.price,
465
+ product_id: originProduct.id,
466
+ percent: selectedDiscount2.par_value
467
+ }
468
+ };
469
+ if ((selectedDiscount2.tag || selectedDiscount2.type) !== "good_pass") {
470
+ discountDetail.num = product.num || 1;
471
+ }
472
+ appliedProducts.push(discountDetail);
473
+ appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
474
+ if (product.isClient) {
475
+ debugger;
476
+ arr.push(this.hooks.setProduct(originProduct, {
477
+ discount_list: [discountDetail],
478
+ price: selectedDiscount2.tag === "good_pass" ? 0 : product.price,
479
+ quantity: isNeedSplit ? 1 : product.quantity,
480
+ origin_total: (0, import_utils2.getProductOriginTotalPrice)({
481
+ product: {
482
+ original_price: product.original_price
483
+ },
484
+ bundle: product.bundle,
485
+ options: product.options
486
+ }),
487
+ variant: originProduct._productInit.variant,
488
+ original_price: new import_decimal.default(product.price || 0).toNumber(),
489
+ total: targetProductTotal
490
+ }));
491
+ } else {
492
+ arr.push(this.hooks.setProduct(originProduct, {
493
+ discount_list: [discountDetail],
494
+ _id: product._id.split("___")[0] + "___" + selectedDiscount2.id + index,
495
+ price: selectedDiscount2.tag === "good_pass" ? 0 : product.price,
496
+ quantity: isNeedSplit ? 1 : product.quantity,
497
+ total: targetProductTotal,
498
+ origin_total: productOriginTotal
499
+ }));
355
500
  }
356
- };
357
- if ((selectedDiscount2.tag || selectedDiscount2.type) !== "good_pass") {
358
- discountDetail.num = product.num || 1;
359
501
  }
360
- appliedProducts.push(discountDetail);
361
- appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
362
- if (product.isClient) {
363
- arr.push(this.hooks.setProduct(originProduct, {
364
- discount_list: [discountDetail],
365
- price: selectedDiscount2.tag === "good_pass" ? 0 : product.price,
366
- quantity: isNeedSplit ? 1 : product.quantity,
367
- origin_total: (0, import_utils2.getProductOriginTotalPrice)({
368
- product: {
369
- original_price: product.original_price
502
+ processedProductsMap.set(product._id, arr);
503
+ } else {
504
+ const processedItems = [];
505
+ if (isNeedSplit) {
506
+ const discountNum = splitCount;
507
+ const normalNum = totalQuantity - discountNum;
508
+ for (let i = 0; i < discountNum; i++) {
509
+ const selectedDiscount2 = applicableDiscounts[i];
510
+ usedDiscounts.set(selectedDiscount2.id, true);
511
+ const uniqueId = `${flatItem._id}_split_${i}`;
512
+ const discountDetail = {
513
+ amount: product.origin_total,
514
+ type: "good_pass",
515
+ discount: {
516
+ resource_id: selectedDiscount2.id,
517
+ title: selectedDiscount2.format_title,
518
+ original_amount: product.origin_total,
519
+ product_id: product.id
370
520
  },
371
- bundle: product.bundle,
372
- options: product.options
373
- }),
374
- variant: originProduct._productInit.variant,
375
- original_price: new import_decimal.default(product.price || 0).toNumber(),
376
- total: targetProductTotal
377
- }));
521
+ metadata: {
522
+ // 🔥 使用拆分后的唯一 _id
523
+ custom_product_bundle_map_id: uniqueId,
524
+ num: 1
525
+ },
526
+ num: 1
527
+ };
528
+ const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
529
+ appliedProducts.push(discountDetail);
530
+ appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
531
+ processedItems.push({
532
+ ...flatItem,
533
+ // 🔥 使用唯一的 _id
534
+ _id: uniqueId,
535
+ num: 1,
536
+ quantity: 1,
537
+ price: 0,
538
+ // 商品券价格为0
539
+ total: 0,
540
+ discount_list: [discountDetail],
541
+ processed: true,
542
+ _discountId: selectedDiscount2.id
543
+ });
544
+ }
545
+ if (normalNum > 0) {
546
+ processedItems.push({
547
+ ...flatItem,
548
+ // 🔥 为剩余商品生成唯一的 _id
549
+ _id: `${flatItem._id}_split_rest`,
550
+ num: normalNum,
551
+ quantity: normalNum,
552
+ discount_list: [],
553
+ processed: true
554
+ });
555
+ }
378
556
  } else {
379
- arr.push(this.hooks.setProduct(originProduct, {
380
- discount_list: [discountDetail],
381
- _id: product._id.split("___")[0] + "___" + selectedDiscount2.id + "___" + index,
382
- price: selectedDiscount2.tag === "good_pass" ? 0 : product.price,
383
- quantity: isNeedSplit ? 1 : product.quantity,
557
+ const selectedDiscount2 = selectedDiscountCard || applicableDiscounts[0];
558
+ usedDiscounts.set(selectedDiscount2.id, true);
559
+ const productOriginTotal = product.original_price || product.price || 0;
560
+ const targetProductTotal = (0, import_utils.getDiscountAmount)(
561
+ selectedDiscount2,
562
+ productOriginTotal,
563
+ productOriginTotal
564
+ );
565
+ const uniqueId = flatItem._id;
566
+ const discountDetail = {
567
+ amount: new import_decimal.default(productOriginTotal).minus(targetProductTotal).toNumber(),
568
+ type: selectedDiscount2.tag === "product_discount_card" ? "discount_card" : selectedDiscount2.tag,
569
+ discount: {
570
+ discount_card_type: (_n = selectedDiscount2 == null ? void 0 : selectedDiscount2.metadata) == null ? void 0 : _n.discount_card_type,
571
+ fixed_amount: new import_decimal.default(productOriginTotal).minus(targetProductTotal).toNumber(),
572
+ resource_id: selectedDiscount2.id,
573
+ title: selectedDiscount2.format_title,
574
+ original_amount: product.original_price,
575
+ product_id: product.id,
576
+ percent: selectedDiscount2.par_value
577
+ },
578
+ metadata: {
579
+ // 🔥 使用唯一的 _id
580
+ custom_product_bundle_map_id: uniqueId,
581
+ num: product.num || 1
582
+ },
583
+ num: product.num || 1
584
+ };
585
+ const appliedProducts = appliedDiscountProducts.get(selectedDiscount2.id) || [];
586
+ appliedProducts.push(discountDetail);
587
+ appliedDiscountProducts.set(selectedDiscount2.id, appliedProducts);
588
+ processedItems.push({
589
+ ...flatItem,
384
590
  total: targetProductTotal,
385
- origin_total: productOriginTotal
386
- }));
591
+ price: new import_decimal.default(productOriginTotal || 0).minus(discountDetail.amount).toNumber(),
592
+ discount_list: [discountDetail],
593
+ processed: true
594
+ });
387
595
  }
596
+ processedFlatItemsMap.set(flatItem._id, processedItems);
388
597
  }
389
- console.log(arr, "arrarrarr");
390
- processedProductsMap.set(product._id, arr);
391
598
  });
392
- const processedProductList = [];
393
- productList.forEach((originProduct) => {
394
- const product = this.hooks.getProduct(originProduct);
395
- const getDefaultProduct = () => {
396
- if (product.isClient) {
397
- return this.hooks.setProduct(originProduct, {
398
- discount_list: [],
399
- price: product.price,
400
- origin_total: (0, import_utils2.getProductOriginTotalPrice)({
401
- product: {
402
- original_price: product.original_price
403
- },
404
- bundle: product.bundle,
405
- options: product.options
406
- }),
407
- variant: originProduct._productInit.variant,
408
- original_price: originProduct._productInit.original_price,
409
- total: (0, import_utils2.getProductTotalPrice)({
410
- product: {
599
+ const reconstructProductsWithBundle = (processedProductsMap2, processedFlatItemsMap2, originalProductList) => {
600
+ const result = [];
601
+ originalProductList.forEach((originProduct) => {
602
+ const product = this.hooks.getProduct(originProduct);
603
+ const mainProductArr = processedProductsMap2.get(product._id);
604
+ if (!mainProductArr || mainProductArr.length === 0) {
605
+ const getDefaultProduct = () => {
606
+ if (product.isClient) {
607
+ return this.hooks.setProduct(originProduct, {
608
+ discount_list: [],
609
+ price: product.price,
610
+ origin_total: (0, import_utils2.getProductOriginTotalPrice)({
611
+ product: {
612
+ original_price: product.original_price
613
+ },
614
+ bundle: product.bundle,
615
+ options: product.options
616
+ }),
617
+ variant: originProduct._productInit.variant,
618
+ original_price: originProduct._productInit.original_price,
619
+ total: (0, import_utils2.getProductTotalPrice)({
620
+ product: {
621
+ price: product.price
622
+ },
623
+ bundle: product.bundle,
624
+ options: product.options
625
+ })
626
+ });
627
+ } else {
628
+ return this.hooks.setProduct(originProduct, {
629
+ discount_list: [],
630
+ total: product.total,
631
+ origin_total: product.origin_total,
411
632
  price: product.price
412
- },
413
- bundle: product.bundle,
414
- options: product.options
415
- })
416
- });
633
+ });
634
+ }
635
+ };
636
+ result.push(getDefaultProduct());
637
+ return;
638
+ }
639
+ const hasBundle = product.bundle && Array.isArray(product.bundle) && product.bundle.length > 0;
640
+ if (!hasBundle) {
641
+ result.push(...mainProductArr);
417
642
  } else {
418
- return this.hooks.setProduct(originProduct, {
419
- discount_list: [],
420
- total: product.total,
421
- origin_total: product.origin_total,
422
- price: product.price
423
- });
643
+ const bundleProcessingInfo = /* @__PURE__ */ new Map();
644
+ let hasGoodPassApplied = false;
645
+ if (product.bundle && Array.isArray(product.bundle)) {
646
+ product.bundle.forEach((bundleItem, bundleIndex) => {
647
+ const bundleItemId = `${product._id}_bundle_${bundleIndex}`;
648
+ const processedBundleItems = processedFlatItemsMap2.get(bundleItemId);
649
+ if (!processedBundleItems || processedBundleItems.length === 0) {
650
+ bundleProcessingInfo.set(bundleIndex, [bundleItem]);
651
+ } else {
652
+ bundleProcessingInfo.set(bundleIndex, processedBundleItems);
653
+ const hasGoodPass = processedBundleItems.some(
654
+ (item) => {
655
+ var _a;
656
+ return (_a = item.discount_list) == null ? void 0 : _a.some(
657
+ (discount) => discount.type === "good_pass" || discount.tag === "good_pass"
658
+ );
659
+ }
660
+ );
661
+ if (hasGoodPass) {
662
+ hasGoodPassApplied = true;
663
+ }
664
+ }
665
+ });
666
+ }
667
+ const mainProductQuantity = mainProductArr[0] ? this.hooks.getProduct(mainProductArr[0]).quantity : 1;
668
+ if (hasGoodPassApplied && mainProductArr.length === 1 && mainProductQuantity > 1) {
669
+ const mainProduct = mainProductArr[0];
670
+ const mainProductData = this.hooks.getProduct(mainProduct);
671
+ const newBundleWithDiscount = [];
672
+ (product.bundle || []).forEach((bundleItem, bundleIndex) => {
673
+ const processedItems = bundleProcessingInfo.get(bundleIndex) || [bundleItem];
674
+ if (processedItems.length > 1) {
675
+ processedItems.forEach((item) => {
676
+ const updatedDiscountList2 = (item.discount_list || []).map((discount) => ({
677
+ ...discount,
678
+ num: item.num
679
+ // 使用拆分后的 num
680
+ }));
681
+ newBundleWithDiscount.push({
682
+ ...bundleItem,
683
+ _id: item._id,
684
+ product_id: bundleItem.product_id,
685
+ price: item.price,
686
+ num: item.num,
687
+ discount_list: updatedDiscountList2
688
+ });
689
+ });
690
+ } else {
691
+ const item = processedItems[0];
692
+ if (item.processed) {
693
+ const updatedDiscountList2 = (item.discount_list || []).map((discount) => ({
694
+ ...discount,
695
+ num: item.num
696
+ // 使用当前的 num
697
+ }));
698
+ newBundleWithDiscount.push({
699
+ ...bundleItem,
700
+ _id: item._id,
701
+ product_id: bundleItem.product_id,
702
+ price: item.price,
703
+ num: item.num,
704
+ discount_list: updatedDiscountList2
705
+ });
706
+ } else {
707
+ newBundleWithDiscount.push(item);
708
+ }
709
+ }
710
+ });
711
+ let newTotalWithDiscount = Number(mainProductData.price || 0);
712
+ let newOriginTotalWithDiscount = Number(mainProductData.original_price || mainProductData.price || 0);
713
+ if (newBundleWithDiscount.length > 0) {
714
+ newBundleWithDiscount.forEach((item) => {
715
+ newTotalWithDiscount += Number(item.price) * Number(item.num);
716
+ });
717
+ newBundleWithDiscount.forEach((item) => {
718
+ var _a, _b, _c;
719
+ const originalPrice = ((_c = (_b = (_a = item.discount_list) == null ? void 0 : _a[0]) == null ? void 0 : _b.discount) == null ? void 0 : _c.original_amount) || item.price;
720
+ newOriginTotalWithDiscount += Number(originalPrice) * Number(item.num);
721
+ });
722
+ }
723
+ const updatedMainDiscountList = mainProductData.discount_list.map((discount) => {
724
+ var _a;
725
+ if ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.custom_product_bundle_map_id) {
726
+ return discount;
727
+ }
728
+ return {
729
+ ...discount,
730
+ num: 1
731
+ };
732
+ });
733
+ const mainDiscountList = updatedMainDiscountList.filter((item) => {
734
+ var _a;
735
+ return !((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id);
736
+ });
737
+ if (mainDiscountList && mainDiscountList.length > 0) {
738
+ const allDiscountAmount = (0, import_utils.getDiscountListAmountTotal)(mainDiscountList);
739
+ newTotalWithDiscount = new import_decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalWithDiscount;
740
+ newOriginTotalWithDiscount = mainProductData.origin_total ?? newOriginTotalWithDiscount;
741
+ if (newBundleWithDiscount.length > 0) {
742
+ newBundleWithDiscount.forEach((item) => {
743
+ var _a, _b, _c;
744
+ newTotalWithDiscount += Number(item.price) * Number(item.num);
745
+ const originalPrice = ((_c = (_b = (_a = item.discount_list) == null ? void 0 : _a[0]) == null ? void 0 : _b.discount) == null ? void 0 : _c.original_amount) || item.price;
746
+ newOriginTotalWithDiscount += Number(originalPrice) * Number(item.num);
747
+ });
748
+ }
749
+ }
750
+ result.push(
751
+ this.hooks.setProduct(mainProduct, {
752
+ ...mainProductData,
753
+ _id: `${mainProductData._id.split("___")[0]}___split_discount`,
754
+ quantity: 1,
755
+ discount_list: updatedMainDiscountList,
756
+ bundle: newBundleWithDiscount,
757
+ total: newTotalWithDiscount,
758
+ origin_total: newOriginTotalWithDiscount
759
+ })
760
+ );
761
+ if (mainProductQuantity > 1) {
762
+ const newBundleOriginal = [];
763
+ (product.bundle || []).forEach((bundleItem, bundleIndex) => {
764
+ newBundleOriginal.push({
765
+ ...bundleItem,
766
+ discount_list: []
767
+ });
768
+ });
769
+ let newTotalOriginal = Number(mainProductData.price || 0);
770
+ let newOriginTotalOriginal = Number(mainProductData.original_price || mainProductData.price || 0);
771
+ if (newBundleOriginal.length > 0) {
772
+ newBundleOriginal.forEach((item) => {
773
+ newTotalOriginal += Number(item.price) * Number(item.num);
774
+ newOriginTotalOriginal += Number(item.price) * Number(item.num);
775
+ });
776
+ }
777
+ const updatedMainDiscountListOriginal = mainProductData.discount_list.map((discount) => {
778
+ var _a;
779
+ if ((_a = discount == null ? void 0 : discount.metadata) == null ? void 0 : _a.custom_product_bundle_map_id) {
780
+ return discount;
781
+ }
782
+ return {
783
+ ...discount,
784
+ num: mainProductQuantity - 1
785
+ };
786
+ });
787
+ const mainDiscountListOriginal = updatedMainDiscountListOriginal.filter((item) => {
788
+ var _a;
789
+ return !((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id);
790
+ });
791
+ if (mainDiscountListOriginal && mainDiscountListOriginal.length > 0) {
792
+ const allDiscountAmount = (0, import_utils.getDiscountListAmount)(mainDiscountListOriginal);
793
+ newTotalOriginal = new import_decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotalOriginal;
794
+ newOriginTotalOriginal = mainProductData.origin_total ?? newOriginTotalOriginal;
795
+ if (newBundleOriginal.length > 0) {
796
+ newBundleOriginal.forEach((item) => {
797
+ newTotalOriginal += Number(item.price) * Number(item.num);
798
+ newOriginTotalOriginal += Number(item.price) * Number(item.num);
799
+ });
800
+ }
801
+ }
802
+ result.push(
803
+ this.hooks.setProduct(mainProduct, {
804
+ ...mainProductData,
805
+ _id: `${mainProductData._id.split("___")[0]}___split_normal`,
806
+ quantity: mainProductQuantity - 1,
807
+ discount_list: updatedMainDiscountListOriginal,
808
+ bundle: newBundleOriginal,
809
+ total: newTotalOriginal,
810
+ origin_total: newOriginTotalOriginal
811
+ })
812
+ );
813
+ }
814
+ } else {
815
+ mainProductArr.forEach((mainProduct) => {
816
+ const mainProductData = this.hooks.getProduct(mainProduct);
817
+ const newBundle = [];
818
+ if (product.bundle && Array.isArray(product.bundle)) {
819
+ product.bundle.forEach((bundleItem, bundleIndex) => {
820
+ const bundleItemId = `${product._id}_bundle_${bundleIndex}`;
821
+ const processedBundleItems = processedFlatItemsMap2.get(bundleItemId);
822
+ if (!processedBundleItems || processedBundleItems.length === 0) {
823
+ newBundle.push(bundleItem);
824
+ } else {
825
+ processedBundleItems.forEach((item) => {
826
+ const updatedDiscountList2 = (item.discount_list || []).map((discount) => ({
827
+ ...discount,
828
+ num: item.num
829
+ // 使用拆分后的 num
830
+ }));
831
+ newBundle.push({
832
+ ...bundleItem,
833
+ _id: item._id,
834
+ product_id: bundleItem.product_id,
835
+ price: item.price,
836
+ num: item.num,
837
+ discount_list: updatedDiscountList2
838
+ });
839
+ });
840
+ }
841
+ });
842
+ }
843
+ let newTotal = Number(mainProductData.price || 0);
844
+ let newOriginTotal = Number(mainProductData.original_price || mainProductData.price || 0);
845
+ if (newBundle.length > 0) {
846
+ newBundle.forEach((item) => {
847
+ newTotal += Number(item.price) * Number(item.num);
848
+ });
849
+ newBundle.forEach((item) => {
850
+ var _a, _b, _c;
851
+ const originalPrice = ((_c = (_b = (_a = item.discount_list) == null ? void 0 : _a[0]) == null ? void 0 : _b.discount) == null ? void 0 : _c.original_amount) || item.price;
852
+ newOriginTotal += Number(originalPrice) * Number(item.num);
853
+ });
854
+ }
855
+ const mainDiscountList = mainProductData.discount_list.filter((item) => {
856
+ var _a;
857
+ return !((_a = item == null ? void 0 : item.metadata) == null ? void 0 : _a.custom_product_bundle_map_id);
858
+ });
859
+ if (mainDiscountList && mainDiscountList.length > 0) {
860
+ const allDiscountAmount = (0, import_utils.getDiscountListAmount)(mainDiscountList);
861
+ newTotal = new import_decimal.default(mainProductData.price || 0).minus(allDiscountAmount).toNumber() ?? newTotal;
862
+ newOriginTotal = mainProductData.origin_total ?? newOriginTotal;
863
+ if (newBundle.length > 0) {
864
+ newBundle.forEach((item) => {
865
+ var _a, _b, _c;
866
+ newTotal += Number(item.price) * Number(item.num);
867
+ const originalPrice = ((_c = (_b = (_a = item.discount_list) == null ? void 0 : _a[0]) == null ? void 0 : _b.discount) == null ? void 0 : _c.original_amount) || item.price;
868
+ newOriginTotal += Number(originalPrice) * Number(item.num);
869
+ });
870
+ }
871
+ }
872
+ result.push(
873
+ this.hooks.setProduct(mainProduct, {
874
+ ...mainProductData,
875
+ bundle: newBundle,
876
+ total: newTotal,
877
+ origin_total: newOriginTotal
878
+ })
879
+ );
880
+ });
881
+ }
424
882
  }
425
- };
426
- const arr = processedProductsMap.get(product._id);
427
- (arr == null ? void 0 : arr.length) ? processedProductList.push(...arr) : processedProductList.push(getDefaultProduct());
428
- });
883
+ });
884
+ return result;
885
+ };
886
+ const processedProductList = reconstructProductsWithBundle(
887
+ processedProductsMap,
888
+ processedFlatItemsMap,
889
+ productList
890
+ );
429
891
  const updatedDiscountList = addModeDiscount.map((discount) => {
430
892
  const applicableProducts = discountApplicability.get(discount.id) || [];
431
893
  const applicableProductDetails = discountApplicableProducts.get(discount.id) || [];
@@ -486,6 +948,64 @@ var RulesModule = class extends import_BaseModule.BaseModule {
486
948
  discountList: [...editModeDiscount, ...updatedDiscountList]
487
949
  };
488
950
  }
951
+ /**
952
+ * 检查优惠是否符合 PackageSubItemUsageRules 配置
953
+ * @param discount 优惠券
954
+ * @param flatItem 扁平化后的商品项(可能是主商品或bundle子商品)
955
+ * @returns 是否可用
956
+ */
957
+ checkPackageSubItemUsageRules(discount, flatItem) {
958
+ var _a, _b, _c, _d;
959
+ const limitedData = discount.limited_relation_product_data;
960
+ const usageRules = limitedData == null ? void 0 : limitedData.package_sub_item_usage_rules;
961
+ const rules = ["original_price", ...(usageRules == null ? void 0 : usageRules.rules) || []];
962
+ if (!usageRules) {
963
+ return true;
964
+ }
965
+ const ruleType = usageRules.type;
966
+ const isMainProduct = flatItem.type === "main";
967
+ const isBundleItem = flatItem.type === "bundle";
968
+ if (isMainProduct) {
969
+ return true;
970
+ }
971
+ if (ruleType === "universal_discount") {
972
+ if (isMainProduct) {
973
+ return true;
974
+ }
975
+ if (isBundleItem) {
976
+ const priceType = (_a = flatItem.bundleItem) == null ? void 0 : _a.price_type;
977
+ const priceTypeExt = (_b = flatItem.bundleItem) == null ? void 0 : _b.price_type_ext;
978
+ const isOriginalPrice = priceType === "markup" && priceTypeExt === "product_price";
979
+ const isMarkupPrice = priceType === "markup" && (priceTypeExt === "" || !priceTypeExt);
980
+ if (rules.length > 0) {
981
+ if (isOriginalPrice && rules.includes("original_price")) {
982
+ return true;
983
+ }
984
+ if (isMarkupPrice && rules.includes("markup_price")) {
985
+ return true;
986
+ }
987
+ return false;
988
+ }
989
+ return isOriginalPrice;
990
+ }
991
+ return true;
992
+ }
993
+ if (ruleType === "package_exclusive") {
994
+ if (isMainProduct) {
995
+ return false;
996
+ }
997
+ if (isBundleItem) {
998
+ const priceType = (_c = flatItem.bundleItem) == null ? void 0 : _c.price_type;
999
+ const priceTypeExt = (_d = flatItem.bundleItem) == null ? void 0 : _d.price_type_ext;
1000
+ return priceType === "markup" && priceTypeExt === "product_price";
1001
+ }
1002
+ return false;
1003
+ }
1004
+ if (ruleType === "single_item_promo") {
1005
+ return isMainProduct;
1006
+ }
1007
+ return true;
1008
+ }
489
1009
  async destroy() {
490
1010
  this.core.effects.offByModuleDestroy(this.name);
491
1011
  await this.core.effects.emit(`${this.name}:onDestroy`, {});