@pisell/pisellos 2.1.17 → 2.1.19

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.
@@ -1,6 +1,8 @@
1
+ var __create = Object.create;
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
4
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
5
7
  var __export = (target, all) => {
6
8
  for (var name in all)
@@ -14,18 +16,30 @@ var __copyProps = (to, from, except, desc) => {
14
16
  }
15
17
  return to;
16
18
  };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
17
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
28
 
19
29
  // src/solution/BookingByStep/utils/capacity.ts
20
30
  var capacity_exports = {};
21
31
  __export(capacity_exports, {
32
+ calculateCartItemsCapacityUsageByResourceType: () => calculateCartItemsCapacityUsageByResourceType,
22
33
  checkResourceCanUseByCapacity: () => checkResourceCanUseByCapacity,
23
34
  checkSubResourcesCapacity: () => checkSubResourcesCapacity,
35
+ checkTimeSlotCapacity: () => checkTimeSlotCapacity,
24
36
  formatDefaultCapacitys: () => formatDefaultCapacitys,
25
37
  getCapacityInfoByCartItem: () => getCapacityInfoByCartItem,
38
+ getResourcesIdsByProduct: () => getResourcesIdsByProduct,
26
39
  getSumCapacity: () => getSumCapacity
27
40
  });
28
41
  module.exports = __toCommonJS(capacity_exports);
42
+ var import_dayjs = __toESM(require("dayjs"));
29
43
  var formatDefaultCapacitys = ({
30
44
  capacity,
31
45
  product_bundle
@@ -96,11 +110,154 @@ var checkResourceCanUseByCapacity = (currentCapacity, requiredCapacity, maxCapac
96
110
  }
97
111
  return currentCapacity + requiredCapacity <= maxCapacity;
98
112
  };
113
+ function calculateCartItemsCapacityUsageByResourceType({
114
+ cartItems,
115
+ timeSlotStart,
116
+ timeSlotEnd,
117
+ allProductResources
118
+ }) {
119
+ const resourceTypeMap = {};
120
+ allProductResources.forEach((resource) => {
121
+ var _a;
122
+ const formId = ((_a = resource.form_id) == null ? void 0 : _a.toString()) || "default";
123
+ if (!resourceTypeMap[formId]) {
124
+ resourceTypeMap[formId] = [];
125
+ }
126
+ resourceTypeMap[formId].push(resource);
127
+ });
128
+ const capacityUsageByType = {};
129
+ Object.keys(resourceTypeMap).forEach((formId) => {
130
+ let totalUsage = 0;
131
+ const resourcesInThisType = resourceTypeMap[formId];
132
+ const resourceIdsInThisType = resourcesInThisType.map((r) => r.id);
133
+ cartItems.forEach((cartItem) => {
134
+ if (!cartItem.start_time || !cartItem.end_time)
135
+ return;
136
+ const itemStart = `${cartItem.start_date} ${cartItem.start_time}`;
137
+ const itemEnd = `${cartItem.end_date || cartItem.start_date} ${cartItem.end_time}`;
138
+ const hasTimeOverlap = !((0, import_dayjs.default)(itemEnd).isBefore((0, import_dayjs.default)(timeSlotStart)) || (0, import_dayjs.default)(itemStart).isAfter((0, import_dayjs.default)(timeSlotEnd)));
139
+ if (!hasTimeOverlap)
140
+ return;
141
+ const productResourceIds = getResourcesIdsByProduct(cartItem._productOrigin);
142
+ const hasResourceTypeOverlap = productResourceIds.some(
143
+ (id) => resourceIdsInThisType.includes(id)
144
+ );
145
+ if (!hasResourceTypeOverlap)
146
+ return;
147
+ const { currentCapacity } = getCapacityInfoByCartItem(cartItem);
148
+ totalUsage += currentCapacity;
149
+ });
150
+ capacityUsageByType[formId] = totalUsage;
151
+ });
152
+ return capacityUsageByType;
153
+ }
154
+ function getResourcesIdsByProduct(product) {
155
+ var _a, _b, _c;
156
+ const tempResourceIds = [];
157
+ (_c = (_b = (_a = product == null ? void 0 : product.product_resource) == null ? void 0 : _a.resources) == null ? void 0 : _b.forEach) == null ? void 0 : _c.call(_b, (resource) => {
158
+ var _a2, _b2;
159
+ if ((resource == null ? void 0 : resource.status) == 1) {
160
+ if ((_a2 = resource == null ? void 0 : resource.default_resource) == null ? void 0 : _a2.length) {
161
+ tempResourceIds.push(...resource == null ? void 0 : resource.default_resource);
162
+ } else if ((_b2 = resource == null ? void 0 : resource.optional_resource) == null ? void 0 : _b2.length) {
163
+ tempResourceIds.push(...resource == null ? void 0 : resource.optional_resource);
164
+ }
165
+ }
166
+ });
167
+ return tempResourceIds;
168
+ }
169
+ function checkTimeSlotCapacity(timeSlotStart, timeSlotEnd, cartItems, allResources) {
170
+ var _a, _b;
171
+ const resourceTypeMap = {};
172
+ allResources.forEach((resource) => {
173
+ var _a2;
174
+ const formId = ((_a2 = resource.form_id) == null ? void 0 : _a2.toString()) || "default";
175
+ if (!resourceTypeMap[formId]) {
176
+ resourceTypeMap[formId] = [];
177
+ }
178
+ resourceTypeMap[formId].push(resource);
179
+ });
180
+ const requiredCapacityByType = {};
181
+ cartItems.forEach((cartItem) => {
182
+ const productResourceIds = getResourcesIdsByProduct(cartItem._productOrigin);
183
+ const { currentCapacity } = getCapacityInfoByCartItem(cartItem);
184
+ Object.keys(resourceTypeMap).forEach((formId) => {
185
+ const resourcesInType = resourceTypeMap[formId];
186
+ const resourceIdsInType = resourcesInType.map((r) => r.id);
187
+ const needsThisResourceType = productResourceIds.some(
188
+ (id) => resourceIdsInType.includes(id)
189
+ );
190
+ if (needsThisResourceType) {
191
+ requiredCapacityByType[formId] = (requiredCapacityByType[formId] || 0) + currentCapacity;
192
+ }
193
+ });
194
+ });
195
+ for (const [formId, requiredCapacity] of Object.entries(requiredCapacityByType)) {
196
+ const resourcesInType = resourceTypeMap[formId];
197
+ if (resourcesInType.length === 0)
198
+ continue;
199
+ let resourceTypeConfig = null;
200
+ for (const cartItem of cartItems) {
201
+ if ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) {
202
+ resourceTypeConfig = cartItem._productOrigin.product_resource.resources.find(
203
+ (r) => {
204
+ var _a2;
205
+ return ((_a2 = r.id) == null ? void 0 : _a2.toString()) === formId && r.status === 1;
206
+ }
207
+ );
208
+ if (resourceTypeConfig)
209
+ break;
210
+ }
211
+ }
212
+ const isMultipleBooking = (resourceTypeConfig == null ? void 0 : resourceTypeConfig.type) === "multiple";
213
+ console.log(`capacity.ts - 资源类型 ${formId} 配置:`, {
214
+ resourceTypeConfig,
215
+ type: resourceTypeConfig == null ? void 0 : resourceTypeConfig.type,
216
+ isMultipleBooking,
217
+ requiredCapacity
218
+ });
219
+ if (isMultipleBooking) {
220
+ let totalAvailableCapacity = 0;
221
+ resourcesInType.forEach((resource) => {
222
+ const availableTimes = resource.times.filter((time) => {
223
+ return !(0, import_dayjs.default)(time.start_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute") && !(0, import_dayjs.default)(time.end_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") || (0, import_dayjs.default)(time.start_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") && (0, import_dayjs.default)(time.end_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute");
224
+ });
225
+ if (availableTimes.length > 0) {
226
+ totalAvailableCapacity += resource.capacity || 0;
227
+ }
228
+ });
229
+ console.log(`capacity.ts - 资源类型 ${formId} 多个预约检查: 总容量 ${totalAvailableCapacity}, 需求 ${requiredCapacity}`);
230
+ if (totalAvailableCapacity < requiredCapacity) {
231
+ console.log(`资源类型 ${formId} 容量不足: 需要 ${requiredCapacity}, 可用 ${totalAvailableCapacity}`);
232
+ return false;
233
+ }
234
+ } else {
235
+ let availableResourceCount = 0;
236
+ resourcesInType.forEach((resource) => {
237
+ const availableTimes = resource.times.filter((time) => {
238
+ return !(0, import_dayjs.default)(time.start_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute") && !(0, import_dayjs.default)(time.end_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") || (0, import_dayjs.default)(time.start_at).isBefore((0, import_dayjs.default)(timeSlotEnd), "minute") && (0, import_dayjs.default)(time.end_at).isAfter((0, import_dayjs.default)(timeSlotStart), "minute");
239
+ });
240
+ if (availableTimes.length > 0) {
241
+ availableResourceCount++;
242
+ }
243
+ });
244
+ console.log(`capacity.ts - 资源类型 ${formId} 单个预约检查: 可用资源数 ${availableResourceCount}, 需求 ${requiredCapacity}`);
245
+ if (availableResourceCount < requiredCapacity) {
246
+ console.log(`资源类型 ${formId} 数量不足: 需要 ${requiredCapacity}, 可用 ${availableResourceCount}`);
247
+ return false;
248
+ }
249
+ }
250
+ }
251
+ return true;
252
+ }
99
253
  // Annotate the CommonJS export names for ESM import in node:
100
254
  0 && (module.exports = {
255
+ calculateCartItemsCapacityUsageByResourceType,
101
256
  checkResourceCanUseByCapacity,
102
257
  checkSubResourcesCapacity,
258
+ checkTimeSlotCapacity,
103
259
  formatDefaultCapacitys,
104
260
  getCapacityInfoByCartItem,
261
+ getResourcesIdsByProduct,
105
262
  getSumCapacity
106
263
  });
@@ -0,0 +1,29 @@
1
+ import { CartItem } from '../../../modules';
2
+ /**
3
+ * 检测商品库存是否足够
4
+ *
5
+ * 只有同时满足以下条件时才会进行库存检测:
6
+ * - is_track 开启(值为 1 或 true)
7
+ * - over_sold 为 0(不允许超卖)
8
+ *
9
+ * 对于多规格商品:
10
+ * - 如果有 product_variant_id,则从 productData.variant 数组中查找对应规格
11
+ * - 使用规格的 is_track, over_sold, stock_quantity 而不是主商品的
12
+ *
13
+ * @param productData 商品数据(需包含 is_track, over_sold, stock_quantity 字段,多规格商品需包含 variant 数组)
14
+ * @param product_variant_id 商品变体ID,如果存在则为多规格商品
15
+ * @param quantity 需要添加的数量
16
+ * @param bundle 套餐配置(子商品需包含 is_track, over_sold, stock_quantity 字段)
17
+ * @param currentCartItems 当前购物车商品列表
18
+ * @returns 库存检测结果
19
+ */
20
+ export declare function checkProductStock({ productData, product_variant_id, quantity, bundle, currentCartItems }: {
21
+ productData: any;
22
+ product_variant_id?: any;
23
+ quantity: number;
24
+ bundle?: any[];
25
+ currentCartItems: CartItem[];
26
+ }): {
27
+ success: boolean;
28
+ errorCode?: string;
29
+ };
@@ -0,0 +1,89 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/solution/BookingByStep/utils/stock.ts
20
+ var stock_exports = {};
21
+ __export(stock_exports, {
22
+ checkProductStock: () => checkProductStock
23
+ });
24
+ module.exports = __toCommonJS(stock_exports);
25
+ function checkProductStock({
26
+ productData,
27
+ product_variant_id,
28
+ quantity,
29
+ bundle,
30
+ currentCartItems
31
+ }) {
32
+ let mainProductConfig = productData;
33
+ if (product_variant_id && productData.variant && Array.isArray(productData.variant)) {
34
+ const variant = productData.variant.find((v) => v.id === product_variant_id);
35
+ if (variant) {
36
+ mainProductConfig = variant;
37
+ }
38
+ }
39
+ const isMainProductTrackingEnabled = mainProductConfig.is_track === 1 || mainProductConfig.is_track === true;
40
+ const isMainProductOverSoldDisabled = mainProductConfig.over_sold === 0;
41
+ if (isMainProductTrackingEnabled && isMainProductOverSoldDisabled) {
42
+ const existingQuantity = currentCartItems.reduce((total, cartItem) => {
43
+ var _a, _b, _c;
44
+ const isSameProduct = ((_a = cartItem._productOrigin) == null ? void 0 : _a.id) === productData.id;
45
+ const isSameVariant = !product_variant_id && !((_b = cartItem._productOrigin) == null ? void 0 : _b.product_variant_id) || ((_c = cartItem._productOrigin) == null ? void 0 : _c.product_variant_id) === product_variant_id;
46
+ if (isSameProduct && isSameVariant) {
47
+ return total + (cartItem.num || 0);
48
+ }
49
+ return total;
50
+ }, 0);
51
+ const totalQuantity = existingQuantity + quantity;
52
+ const stockQuantity = mainProductConfig.stock_quantity;
53
+ if (stockQuantity !== void 0 && stockQuantity !== null && totalQuantity > stockQuantity) {
54
+ return { success: false, errorCode: "not_enough_stock" };
55
+ }
56
+ }
57
+ if (bundle && Array.isArray(bundle)) {
58
+ for (const bundleItem of bundle) {
59
+ const bundleProductId = bundleItem.bundle_product_id;
60
+ const bundleStockQuantity = bundleItem.stock_quantity;
61
+ const bundleRequiredQuantity = (bundleItem.num || 1) * quantity;
62
+ const isBundleTrackingEnabled = bundleItem.is_track === 1 || bundleItem.is_track === true;
63
+ const isBundleOverSoldDisabled = bundleItem.over_sold === 0;
64
+ if (!isBundleTrackingEnabled || !isBundleOverSoldDisabled)
65
+ continue;
66
+ if (bundleStockQuantity === void 0 || bundleStockQuantity === null)
67
+ continue;
68
+ const existingBundleQuantity = currentCartItems.reduce((total, cartItem) => {
69
+ if (!cartItem._bundleOrigin || !Array.isArray(cartItem._bundleOrigin))
70
+ return total;
71
+ cartItem._bundleOrigin.forEach((cartBundleItem) => {
72
+ if (cartBundleItem.bundle_product_id === bundleProductId) {
73
+ total += (cartBundleItem.num || 1) * (cartItem.num || 1);
74
+ }
75
+ });
76
+ return total;
77
+ }, 0);
78
+ const totalBundleQuantity = existingBundleQuantity + bundleRequiredQuantity;
79
+ if (totalBundleQuantity > bundleStockQuantity) {
80
+ return { success: false, errorCode: "not_enough_stock" };
81
+ }
82
+ }
83
+ }
84
+ return { success: true };
85
+ }
86
+ // Annotate the CommonJS export names for ESM import in node:
87
+ 0 && (module.exports = {
88
+ checkProductStock
89
+ });
@@ -659,13 +659,15 @@ var CheckoutImpl = class extends import_BaseModule.BaseModule {
659
659
  if (Number(remainingAmount) > 0) {
660
660
  this.logInfo("订单金额还有待付的,同步 EFTPOS 支付");
661
661
  const isEftposPayment = ((_a = paymentItem.type) == null ? void 0 : _a.toLowerCase()) === "eftpos" || ((_b = paymentItem.code) == null ? void 0 : _b.toUpperCase().includes("EFTPOS"));
662
+ const isCashPayment2 = paymentItem.code === "CASHMANUAL";
663
+ const isCustomePayment = paymentItem.type === "custom";
662
664
  this.logInfo("EFTPOS 支付检查:", {
663
665
  paymentCode: paymentItem.code,
664
666
  paymentType: paymentItem.type,
665
667
  isEftposPayment,
666
668
  currentOrderSynced: this.store.isOrderSynced
667
669
  });
668
- if (isEftposPayment) {
670
+ if (isEftposPayment || isCashPayment2 || isCustomePayment) {
669
671
  this.logInfo("检测到 EFTPOS 支付,立即同步订单到后端...");
670
672
  try {
671
673
  const syncResult = await this.syncOrderToBackendWithReturn(true);
@@ -794,13 +796,15 @@ var CheckoutImpl = class extends import_BaseModule.BaseModule {
794
796
  }
795
797
  const remainingAmount = await this.calculateRemainingAmountAsync();
796
798
  const remainingValue = new import_decimal.default(remainingAmount);
797
- if (remainingValue.lte(0)) {
798
- this.logInfo("订单已完成支付且修改代金券,跳过操作避免重复同步:", {
799
+ const isOrderSynced = this.store.isOrderSynced;
800
+ if (remainingValue.lte(0) && isOrderSynced && voucherPaymentItems.length === 0) {
801
+ this.logInfo("订单已同步且支付完成,跳过清空代金券操作避免重复同步:", {
799
802
  orderUuid: this.store.currentOrder.uuid,
800
803
  orderId: this.store.currentOrder.order_id,
801
804
  remainingAmount,
805
+ isOrderSynced,
802
806
  voucherPaymentItemsCount: voucherPaymentItems.length,
803
- reason: "Order payment completed, skip clear vouchers"
807
+ reason: "Order synced and payment completed, skip clear vouchers to avoid duplicate sync"
804
808
  });
805
809
  return;
806
810
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "2.1.17",
4
+ "version": "2.1.19",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",