@pisell/pisellos 0.0.271 → 0.0.273

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.
@@ -47,6 +47,7 @@ var import_utils4 = require("../../modules/Product/utils");
47
47
  var import_timeslots = require("./utils/timeslots");
48
48
  var import_changePrice = require("../../modules/Cart/utils/changePrice");
49
49
  var import_capacity = require("./utils/capacity");
50
+ var import_stock = require("./utils/stock");
50
51
  import_dayjs.default.extend(import_isSameOrBefore.default);
51
52
  import_dayjs.default.extend(import_isSameOrAfter.default);
52
53
  var BookingByStepImpl = class extends import_BaseModule.BaseModule {
@@ -560,9 +561,9 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
560
561
  * @param {ProductData} productData
561
562
  * @memberof BookingByStepImpl
562
563
  */
563
- async storeProduct(productData) {
564
+ storeProduct(productData) {
564
565
  const activeAccount = this.getActiveAccount();
565
- this.addProductToCart({
566
+ return this.addProductToCart({
566
567
  product: productData,
567
568
  account: activeAccount
568
569
  });
@@ -596,6 +597,17 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
596
597
  quantity = 1
597
598
  } = product || {};
598
599
  const productData = { ...origin, product_variant_id };
600
+ const currentCartItems = this.store.cart.getItems();
601
+ const stockCheckResult = (0, import_stock.checkProductStock)({
602
+ productData,
603
+ product_variant_id,
604
+ quantity,
605
+ bundle,
606
+ currentCartItems
607
+ });
608
+ if (!stockCheckResult.success) {
609
+ return stockCheckResult;
610
+ }
599
611
  if (!account) {
600
612
  const activeAccount = this.getActiveAccount();
601
613
  if (activeAccount) {
@@ -608,7 +620,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
608
620
  account: account || void 0
609
621
  });
610
622
  if (flag) {
611
- return;
623
+ return { success: true };
612
624
  }
613
625
  const addItemParams = {
614
626
  product: productData,
@@ -624,6 +636,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
624
636
  }
625
637
  this.addProductCheck({ date });
626
638
  this.store.cart.addItem(addItemParams);
639
+ return { success: true };
627
640
  }
628
641
  /**
629
642
  * 添加完购物车以后做的一些检测,比如日期是否在同一天
@@ -1569,10 +1582,6 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1569
1582
  });
1570
1583
  });
1571
1584
  }
1572
- clearCache() {
1573
- }
1574
- clearCacheByModule(module2) {
1575
- }
1576
1585
  getScheduleDataByIds(scheduleIds) {
1577
1586
  const targetSchedules = this.store.schedule.getScheduleListByIds(scheduleIds);
1578
1587
  const targetSchedulesData = targetSchedules.map((item) => {
@@ -1627,6 +1636,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1627
1636
  }
1628
1637
  this.store.currentProduct = void 0;
1629
1638
  }
1639
+ // 通过商品和 schedule 来获取视频可用的时间片、时间片内资源可用的数据
1630
1640
  getTimeslotBySchedule({
1631
1641
  date,
1632
1642
  scheduleIds,
@@ -1726,6 +1736,67 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1726
1736
  }
1727
1737
  }
1728
1738
  });
1739
+ const cartItems2 = this.store.cart.getItems();
1740
+ productResources.forEach((n) => {
1741
+ if (n.type === "single") {
1742
+ const currentResourcesSet = /* @__PURE__ */ new Set([...n.optional_resource, ...n.default_resource]);
1743
+ const sameCartItems = cartItems2.filter((m) => {
1744
+ var _a2, _b2, _c2;
1745
+ return ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.id) == null ? void 0 : _b2.toString()) === ((_c2 = targetProductData == null ? void 0 : targetProductData.id) == null ? void 0 : _c2.toString()) && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
1746
+ });
1747
+ if (sameCartItems.length > 0 && sameCartItems.length >= currentResourcesSet.size) {
1748
+ bookingLeft = 0;
1749
+ }
1750
+ const otherCartItems = cartItems2.filter((m) => {
1751
+ var _a2, _b2, _c2;
1752
+ return ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.id) == null ? void 0 : _b2.toString()) !== ((_c2 = targetProductData == null ? void 0 : targetProductData.id) == null ? void 0 : _c2.toString()) && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
1753
+ });
1754
+ otherCartItems.forEach((m) => {
1755
+ var _a2, _b2, _c2;
1756
+ const sameTypeResources = (_c2 = (_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) == null ? void 0 : _c2.find((m2) => m2.type === n.type);
1757
+ const sameTypeResourcesSet = /* @__PURE__ */ new Set([...(sameTypeResources == null ? void 0 : sameTypeResources.optional_resource) || [], ...(sameTypeResources == null ? void 0 : sameTypeResources.default_resource) || []]);
1758
+ sameTypeResourcesSet.forEach((resource) => currentResourcesSet.add(resource));
1759
+ });
1760
+ if (currentResourcesSet.size > 0 && otherCartItems.length + sameCartItems.length >= currentResourcesSet.size) {
1761
+ bookingLeft = 0;
1762
+ }
1763
+ } else {
1764
+ const sameCartItems = cartItems2.filter((m) => {
1765
+ var _a2, _b2, _c2;
1766
+ return ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.id) == null ? void 0 : _b2.toString()) === ((_c2 = targetProductData == null ? void 0 : targetProductData.id) == null ? void 0 : _c2.toString()) && `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end;
1767
+ });
1768
+ const sameCartNeedCapacity = sameCartItems.reduce((acc, curr) => acc + (0, import_capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
1769
+ const currentProductResourcesCapacity = n.renderList.reduce((acc, curr) => !curr.onlyComputed ? acc + curr.capacity || 0 : acc, 0);
1770
+ if (sameCartNeedCapacity >= currentProductResourcesCapacity) {
1771
+ bookingLeft = 0;
1772
+ }
1773
+ const otherSameTimesCartItems = cartItems2.filter((m) => `${m.start_date} ${m.start_time}` === item.start && `${m.start_date} ${m.end_time}` === item.end);
1774
+ const otherCartNeedCapacity = otherSameTimesCartItems.reduce((acc, curr) => acc + (0, import_capacity.getCapacityInfoByCartItem)(curr).currentCapacity, 0);
1775
+ const allRenderList = [...n.renderList.filter((m) => !m.onlyComputed)];
1776
+ otherSameTimesCartItems.forEach((m) => {
1777
+ var _a2, _b2;
1778
+ const productResources2 = (0, import_resources.getResourcesByProduct)(
1779
+ (0, import_utils.getResourcesMap)((targetResourceDate == null ? void 0 : targetResourceDate.resource) || []),
1780
+ ((_b2 = (_a2 = m._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b2.resources) || [],
1781
+ selectedResources,
1782
+ 1
1783
+ );
1784
+ productResources2.forEach((m2) => {
1785
+ if (m2.id === n.id) {
1786
+ m2.renderList.forEach((n2) => {
1787
+ if (!n2.onlyComputed && !allRenderList.find((m3) => m3.id === n2.id)) {
1788
+ allRenderList.push(n2);
1789
+ }
1790
+ });
1791
+ }
1792
+ });
1793
+ });
1794
+ const currentTypeResourcesCapacity = allRenderList.reduce((acc, curr) => acc + curr.capacity || 0, 0);
1795
+ if (sameCartNeedCapacity + otherCartNeedCapacity >= currentTypeResourcesCapacity) {
1796
+ bookingLeft = 0;
1797
+ }
1798
+ }
1799
+ });
1729
1800
  const startDayJs = (0, import_dayjs.default)(item.start);
1730
1801
  const endDayJs = (0, import_dayjs.default)(item.end);
1731
1802
  return {
@@ -1739,6 +1810,112 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1739
1810
  });
1740
1811
  return formatScheduleTimeSlots;
1741
1812
  }
1813
+ // 提供给 UI的方法,当前步骤是选择商品,下一步不管是什么都需要在这里做一次检测
1814
+ // 时长类商品关联的资源为多个预约时,在点击进入"选择资源"步骤之前,需要检测当前所有资源的总容量
1815
+ // 选择商品数量大于所有资源配置的总容量时,不能进入下一步,需要在"选择商品"这一步时提示。
1816
+ // 注意 资源分为多个种类,需要每个种类单独检测,不能一股脑把所有资源的容量加起来检测
1817
+ checkMaxDurationCapacity() {
1818
+ const cartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems());
1819
+ if (cartItems.length === 0)
1820
+ return true;
1821
+ const itemsWithTime = [];
1822
+ const itemsWithoutTime = [];
1823
+ cartItems.forEach((cartItem) => {
1824
+ if (cartItem.start_time && cartItem.end_time && cartItem.start_date) {
1825
+ itemsWithTime.push(cartItem);
1826
+ } else {
1827
+ itemsWithoutTime.push(cartItem);
1828
+ }
1829
+ });
1830
+ const processedItemsWithoutTime = [];
1831
+ if (itemsWithoutTime.length > 0) {
1832
+ const itemsByResourceType = {};
1833
+ itemsWithoutTime.forEach((cartItem) => {
1834
+ var _a;
1835
+ if (!cartItem._productOrigin)
1836
+ return;
1837
+ const resourceTypes = ((_a = cartItem._productOrigin.product_resource) == null ? void 0 : _a.resources) || [];
1838
+ resourceTypes.forEach((resourceType) => {
1839
+ var _a2;
1840
+ if (resourceType.status === 1) {
1841
+ const resourceCode = resourceType.code || ((_a2 = resourceType.id) == null ? void 0 : _a2.toString());
1842
+ if (!itemsByResourceType[resourceCode]) {
1843
+ itemsByResourceType[resourceCode] = [];
1844
+ }
1845
+ if (!itemsByResourceType[resourceCode].find((item) => item._id === cartItem._id)) {
1846
+ itemsByResourceType[resourceCode].push(cartItem);
1847
+ }
1848
+ }
1849
+ });
1850
+ });
1851
+ for (const [resourceCode, items] of Object.entries(itemsByResourceType)) {
1852
+ try {
1853
+ const commonTimeSlots = this.getTimeSlotByAllResources(resourceCode);
1854
+ if (commonTimeSlots && commonTimeSlots.length > 0) {
1855
+ const firstTimeSlot = commonTimeSlots[0];
1856
+ const startDate = (0, import_dayjs.default)(firstTimeSlot.start_at).format("YYYY-MM-DD");
1857
+ const startTime = firstTimeSlot.start_time;
1858
+ const endTime = firstTimeSlot.end_time;
1859
+ items.forEach((cartItem) => {
1860
+ const processedItem = {
1861
+ ...cartItem,
1862
+ start_date: startDate,
1863
+ start_time: startTime,
1864
+ end_time: endTime,
1865
+ end_date: startDate
1866
+ };
1867
+ processedItemsWithoutTime.push(processedItem);
1868
+ });
1869
+ } else {
1870
+ console.log(`资源类型 ${resourceCode} 没有公共可用时间`);
1871
+ return false;
1872
+ }
1873
+ } catch (error) {
1874
+ console.warn(`获取资源类型 ${resourceCode} 的公共可用时间失败:`, error);
1875
+ continue;
1876
+ }
1877
+ }
1878
+ }
1879
+ const allProcessedItems = [...itemsWithTime, ...processedItemsWithoutTime];
1880
+ const cartItemsByTimeSlot = {};
1881
+ allProcessedItems.forEach((cartItem) => {
1882
+ if (!cartItem.start_time || !cartItem.end_time || !cartItem.start_date)
1883
+ return;
1884
+ const timeSlotKey = `${cartItem.start_date}_${cartItem.start_time}_${cartItem.end_date || cartItem.start_date}_${cartItem.end_time}`;
1885
+ if (!cartItemsByTimeSlot[timeSlotKey]) {
1886
+ cartItemsByTimeSlot[timeSlotKey] = [];
1887
+ }
1888
+ cartItemsByTimeSlot[timeSlotKey].push(cartItem);
1889
+ });
1890
+ for (const [timeSlotKey, itemsInTimeSlot] of Object.entries(cartItemsByTimeSlot)) {
1891
+ const [startDate, startTime, endDate, endTime] = timeSlotKey.split("_");
1892
+ const timeSlotStart = `${startDate} ${startTime}`;
1893
+ const timeSlotEnd = `${endDate} ${endTime}`;
1894
+ const allResourcesForTimeSlot = [];
1895
+ const resourcesIdSet = /* @__PURE__ */ new Set();
1896
+ const dateRange = this.store.date.getDateRange();
1897
+ const resourcesDates = this.store.date.getDateList();
1898
+ const targetResourceDate = resourcesDates.find((n) => n.date === startDate);
1899
+ if (!targetResourceDate)
1900
+ continue;
1901
+ const resourcesMap = (0, import_utils.getResourcesMap)(targetResourceDate.resource || []);
1902
+ itemsInTimeSlot.forEach((cartItem) => {
1903
+ if (!cartItem._productOrigin)
1904
+ return;
1905
+ const productResourceIds = (0, import_capacity.getResourcesIdsByProduct)(cartItem._productOrigin);
1906
+ productResourceIds.forEach((resourceId) => {
1907
+ if (resourcesMap[resourceId] && !resourcesIdSet.has(resourceId)) {
1908
+ resourcesIdSet.add(resourceId);
1909
+ allResourcesForTimeSlot.push(resourcesMap[resourceId]);
1910
+ }
1911
+ });
1912
+ });
1913
+ if (!(0, import_capacity.checkTimeSlotCapacity)(timeSlotStart, timeSlotEnd, itemsInTimeSlot, allResourcesForTimeSlot)) {
1914
+ return false;
1915
+ }
1916
+ }
1917
+ return true;
1918
+ }
1742
1919
  setOtherData(key, value) {
1743
1920
  this.otherData[key] = value;
1744
1921
  this.checkSaveCache({
@@ -1956,7 +2133,7 @@ var BookingByStepImpl = class extends import_BaseModule.BaseModule {
1956
2133
  startDate || "",
1957
2134
  endDate || ""
1958
2135
  );
1959
- const tempResourceIds = (0, import_resources.getResourcesIdsByProduct)(tempProducts);
2136
+ const tempResourceIds = (0, import_capacity.getResourcesIdsByProduct)(tempProducts);
1960
2137
  const res = await this.store.date.fetchResourceDates({
1961
2138
  query: {
1962
2139
  start_date: startDate || "",
@@ -45,3 +45,26 @@ export declare const checkSubResourcesCapacity: (resource: ResourceItem) => void
45
45
  * @returns 如果资源可以容纳额外的容量则返回 true
46
46
  */
47
47
  export declare const checkResourceCanUseByCapacity: (currentCapacity: number, requiredCapacity: number, maxCapacity: number) => boolean;
48
+ /**
49
+ * 计算按资源类型分组的容量占用情况
50
+ *
51
+ * @param {CartItem[]} cartItems 购物车商品列表
52
+ * @param {string} timeSlotStart 时间段开始时间
53
+ * @param {string} timeSlotEnd 时间段结束时间
54
+ * @param {ResourceItem[]} allProductResources 当前商品的所有资源列表
55
+ * @return {Record<string, number>} 返回每种资源类型(form_id)的容量占用
56
+ */
57
+ export declare function calculateCartItemsCapacityUsageByResourceType({ cartItems, timeSlotStart, timeSlotEnd, allProductResources }: {
58
+ cartItems: CartItem[];
59
+ timeSlotStart: string;
60
+ timeSlotEnd: string;
61
+ allProductResources: ResourceItem[];
62
+ }): Record<string, number>;
63
+ /**
64
+ * 获取商品的资源ID列表
65
+ */
66
+ export declare function getResourcesIdsByProduct(product: any): number[];
67
+ /**
68
+ * 检查特定时间段的容量是否足够
69
+ */
70
+ export declare function checkTimeSlotCapacity(timeSlotStart: string, timeSlotEnd: string, cartItems: CartItem[], allResources: ResourceItem[]): boolean;
@@ -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,133 @@ 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
+ const resourceTypeMap = {};
171
+ allResources.forEach((resource) => {
172
+ var _a;
173
+ const formId = ((_a = resource.form_id) == null ? void 0 : _a.toString()) || "default";
174
+ if (!resourceTypeMap[formId]) {
175
+ resourceTypeMap[formId] = [];
176
+ }
177
+ resourceTypeMap[formId].push(resource);
178
+ });
179
+ const requiredCapacityByType = {};
180
+ cartItems.forEach((cartItem) => {
181
+ const productResourceIds = getResourcesIdsByProduct(cartItem._productOrigin);
182
+ const { currentCapacity } = getCapacityInfoByCartItem(cartItem);
183
+ Object.keys(resourceTypeMap).forEach((formId) => {
184
+ const resourcesInType = resourceTypeMap[formId];
185
+ const resourceIdsInType = resourcesInType.map((r) => r.id);
186
+ const needsThisResourceType = productResourceIds.some(
187
+ (id) => resourceIdsInType.includes(id)
188
+ );
189
+ if (needsThisResourceType) {
190
+ requiredCapacityByType[formId] = (requiredCapacityByType[formId] || 0) + currentCapacity;
191
+ }
192
+ });
193
+ });
194
+ for (const [formId, requiredCapacity] of Object.entries(requiredCapacityByType)) {
195
+ const resourcesInType = resourceTypeMap[formId];
196
+ if (resourcesInType.length === 0)
197
+ continue;
198
+ const firstResource = resourcesInType[0];
199
+ const isMultipleBooking = firstResource.resourceType === "multiple";
200
+ if (isMultipleBooking) {
201
+ let totalAvailableCapacity = 0;
202
+ resourcesInType.forEach((resource) => {
203
+ const availableTimes = resource.times.filter((time) => {
204
+ 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");
205
+ });
206
+ if (availableTimes.length > 0) {
207
+ totalAvailableCapacity += resource.capacity || 0;
208
+ }
209
+ });
210
+ if (totalAvailableCapacity < requiredCapacity) {
211
+ console.log(`资源类型 ${formId} 容量不足: 需要 ${requiredCapacity}, 可用 ${totalAvailableCapacity}`);
212
+ return false;
213
+ }
214
+ } else {
215
+ let availableResourceCount = 0;
216
+ resourcesInType.forEach((resource) => {
217
+ const availableTimes = resource.times.filter((time) => {
218
+ 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");
219
+ });
220
+ if (availableTimes.length > 0) {
221
+ availableResourceCount++;
222
+ }
223
+ });
224
+ if (availableResourceCount < requiredCapacity) {
225
+ console.log(`资源类型 ${formId} 数量不足: 需要 ${requiredCapacity}, 可用 ${availableResourceCount}`);
226
+ return false;
227
+ }
228
+ }
229
+ }
230
+ return true;
231
+ }
99
232
  // Annotate the CommonJS export names for ESM import in node:
100
233
  0 && (module.exports = {
234
+ calculateCartItemsCapacityUsageByResourceType,
101
235
  checkResourceCanUseByCapacity,
102
236
  checkSubResourcesCapacity,
237
+ checkTimeSlotCapacity,
103
238
  formatDefaultCapacitys,
104
239
  getCapacityInfoByCartItem,
240
+ getResourcesIdsByProduct,
105
241
  getSumCapacity
106
242
  });
@@ -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
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "0.0.271",
4
+ "version": "0.0.273",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",