@pisell/pisellos 2.2.314 → 2.2.316

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 (268) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +3 -1
  3. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  4. package/dist/model/strategy/adapter/itemRule/adapter.js +74 -7
  5. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  6. package/dist/model/strategy/adapter/itemRule/evaluator.js +13 -0
  7. package/dist/model/strategy/adapter/itemRule/type.d.ts +40 -1
  8. package/dist/model/strategy/adapter/itemRule/type.js +10 -0
  9. package/dist/model/strategy/adapter/promotion/evaluator.js +89 -104
  10. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
  11. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +28 -4
  12. package/dist/modules/BookingContext/utils/productExtend.d.ts +7 -0
  13. package/dist/modules/BookingContext/utils/productExtend.js +62 -18
  14. package/dist/modules/BookingContext/utils/resources.js +1 -1
  15. package/dist/modules/BusinessAvailability/index.d.ts +30 -0
  16. package/dist/modules/BusinessAvailability/index.js +204 -0
  17. package/dist/modules/Cart/index.js +4 -3
  18. package/dist/modules/Cart/types.d.ts +2 -0
  19. package/dist/modules/Cart/utils/cartProduct.d.ts +3 -1
  20. package/dist/modules/Cart/utils/cartProduct.js +59 -32
  21. package/dist/modules/FulfillmentTiming/index.d.ts +11 -0
  22. package/dist/modules/FulfillmentTiming/index.js +407 -0
  23. package/dist/modules/FulfillmentTiming/types.d.ts +67 -0
  24. package/dist/modules/FulfillmentTiming/types.js +1 -0
  25. package/dist/modules/Holder/utils.d.ts +2 -0
  26. package/dist/modules/Holder/utils.js +32 -2
  27. package/dist/modules/OpenData/contactInfo.d.ts +20 -0
  28. package/dist/modules/OpenData/contactInfo.js +70 -0
  29. package/dist/modules/OpenData/index.d.ts +1 -0
  30. package/dist/modules/OpenData/index.js +1 -0
  31. package/dist/modules/OpenData/types.d.ts +23 -0
  32. package/dist/modules/Order/holderRelations.d.ts +14 -0
  33. package/dist/modules/Order/holderRelations.js +154 -0
  34. package/dist/modules/Order/index.d.ts +16 -4
  35. package/dist/modules/Order/index.js +926 -511
  36. package/dist/modules/Order/localEftposState.d.ts +13 -0
  37. package/dist/modules/Order/localEftposState.js +39 -0
  38. package/dist/modules/Order/pickupTiming.d.ts +46 -0
  39. package/dist/modules/Order/pickupTiming.js +53 -0
  40. package/dist/modules/Order/types.d.ts +49 -3
  41. package/dist/modules/Order/types.js +2 -0
  42. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
  43. package/dist/modules/Order/utils/discountProductLineIdentity.js +142 -7
  44. package/dist/modules/Order/utils/orderCollectionIdentity.js +24 -10
  45. package/dist/modules/Order/utils.d.ts +2 -1
  46. package/dist/modules/Order/utils.js +61 -17
  47. package/dist/modules/Payment/index.js +9 -10
  48. package/dist/modules/Product/types.d.ts +11 -0
  49. package/dist/modules/ProductList/index.js +1 -1
  50. package/dist/modules/ResourcePlanner/planner.d.ts +2 -0
  51. package/dist/modules/ResourcePlanner/planner.js +332 -23
  52. package/dist/modules/ResourcePlanner/types.d.ts +29 -0
  53. package/dist/modules/Rules/index.js +62 -61
  54. package/dist/modules/Schedule/index.d.ts +8 -0
  55. package/dist/modules/Schedule/index.js +141 -39
  56. package/dist/modules/index.d.ts +1 -0
  57. package/dist/modules/index.js +1 -0
  58. package/dist/plugins/request.d.ts +7 -0
  59. package/dist/server/index.d.ts +1 -0
  60. package/dist/server/index.js +1557 -1322
  61. package/dist/server/modules/form/index.d.ts +19 -0
  62. package/dist/server/modules/form/index.js +205 -0
  63. package/dist/server/modules/form/types.d.ts +13 -0
  64. package/dist/server/modules/form/types.js +3 -0
  65. package/dist/server/modules/index.d.ts +3 -0
  66. package/dist/server/modules/index.js +4 -0
  67. package/dist/server/modules/order/index.d.ts +19 -0
  68. package/dist/server/modules/order/index.js +1071 -774
  69. package/dist/server/modules/order/types.d.ts +4 -0
  70. package/dist/server/modules/products/index.d.ts +28 -7
  71. package/dist/server/modules/products/index.js +1297 -770
  72. package/dist/server/modules/products/replication.d.ts +8 -0
  73. package/dist/server/modules/products/replication.js +69 -0
  74. package/dist/server/modules/products/types.d.ts +12 -1
  75. package/dist/server/modules/products/types.js +4 -0
  76. package/dist/server/test.json +1 -1
  77. package/dist/server/utils/small-ticket.d.ts +1 -85
  78. package/dist/server/utils/small-ticket.js +2 -2542
  79. package/dist/shared/payment/loadPaymentMethods.d.ts +9 -0
  80. package/dist/shared/payment/loadPaymentMethods.js +66 -0
  81. package/dist/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  82. package/dist/shared/receipt/customerInvoiceLanguages.js +60 -0
  83. package/dist/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  84. package/dist/shared/receipt/loadCustomerInvoiceLayout.js +184 -0
  85. package/dist/shared/receipt/small-ticket.d.ts +96 -0
  86. package/dist/shared/receipt/small-ticket.js +2763 -0
  87. package/dist/shared/receipt/templateVisibility.d.ts +26 -0
  88. package/dist/shared/receipt/templateVisibility.js +68 -0
  89. package/dist/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  90. package/dist/shared/sales/loadSalesOrderSnapshot.js +21 -0
  91. package/dist/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  92. package/dist/solution/BaseSales/fulfillmentItemRules.js +750 -0
  93. package/dist/solution/BaseSales/index.d.ts +43 -16
  94. package/dist/solution/BaseSales/index.js +2028 -1247
  95. package/dist/solution/BaseSales/pickupTiming.d.ts +47 -0
  96. package/dist/solution/BaseSales/pickupTiming.js +616 -0
  97. package/dist/solution/BaseSales/types.d.ts +12 -0
  98. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
  99. package/dist/solution/BaseSales/utils/parseSalesResponse.js +10 -3
  100. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -4
  101. package/dist/solution/BookingByStep/index.d.ts +4 -2
  102. package/dist/solution/BookingByStep/index.js +8 -3
  103. package/dist/solution/BookingTicket/index.d.ts +23 -3
  104. package/dist/solution/BookingTicket/index.js +867 -507
  105. package/dist/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  106. package/dist/solution/BookingTicket/utils/addProductDecision.js +1 -1
  107. package/dist/solution/BookingTicket/utils/cartView.js +3 -1
  108. package/dist/solution/OrderInvoicePreview/index.d.ts +66 -0
  109. package/dist/solution/OrderInvoicePreview/index.js +340 -0
  110. package/dist/solution/RegisterAndLogin/config.js +54 -11
  111. package/dist/solution/RegisterAndLogin/index.d.ts +2 -0
  112. package/dist/solution/RegisterAndLogin/index.js +1 -1
  113. package/dist/solution/RegisterAndLogin/utils.d.ts +12 -4
  114. package/dist/solution/RegisterAndLogin/utils.js +36 -16
  115. package/dist/solution/ScanOrder/index.js +65 -31
  116. package/dist/solution/ScanOrder/types.d.ts +3 -0
  117. package/dist/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  118. package/dist/solution/UnifiedBookingSales/businessAvailability.js +292 -0
  119. package/dist/solution/UnifiedBookingSales/index.d.ts +36 -4
  120. package/dist/solution/UnifiedBookingSales/index.js +1715 -906
  121. package/dist/solution/UnifiedBookingSales/types.d.ts +16 -2
  122. package/dist/solution/VenueBooking/index.d.ts +15 -2
  123. package/dist/solution/VenueBooking/index.js +1062 -785
  124. package/dist/solution/VenueBooking/types.d.ts +2 -1
  125. package/dist/solution/VenueBooking/types.js +1 -0
  126. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  127. package/dist/solution/VenueBooking/utils/dateSummary.js +7 -4
  128. package/dist/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  129. package/dist/solution/VenueBooking/utils/smartPricing.js +273 -0
  130. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  131. package/dist/solution/VenueBooking/utils/timeSlot.js +6 -3
  132. package/dist/solution/index.d.ts +1 -0
  133. package/dist/solution/index.js +2 -1
  134. package/lib/index.d.ts +2 -0
  135. package/lib/index.js +21 -1
  136. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +3 -1
  137. package/lib/model/strategy/adapter/itemRule/adapter.js +54 -4
  138. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +3 -1
  139. package/lib/model/strategy/adapter/itemRule/evaluator.js +9 -0
  140. package/lib/model/strategy/adapter/itemRule/type.d.ts +40 -1
  141. package/lib/model/strategy/adapter/itemRule/type.js +10 -0
  142. package/lib/model/strategy/adapter/promotion/evaluator.js +9 -14
  143. package/lib/model/strategy/adapter/promotion/index.js +46 -1
  144. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
  145. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +17 -1
  146. package/lib/modules/BookingContext/utils/productExtend.d.ts +7 -0
  147. package/lib/modules/BookingContext/utils/productExtend.js +45 -2
  148. package/lib/modules/BookingContext/utils/resources.js +1 -1
  149. package/lib/modules/BusinessAvailability/index.d.ts +30 -0
  150. package/lib/modules/BusinessAvailability/index.js +146 -0
  151. package/lib/modules/Cart/index.js +4 -2
  152. package/lib/modules/Cart/types.d.ts +2 -0
  153. package/lib/modules/Cart/utils/cartProduct.d.ts +3 -1
  154. package/lib/modules/Cart/utils/cartProduct.js +39 -20
  155. package/lib/modules/FulfillmentTiming/index.d.ts +11 -0
  156. package/lib/modules/FulfillmentTiming/index.js +359 -0
  157. package/lib/modules/FulfillmentTiming/types.d.ts +67 -0
  158. package/lib/modules/FulfillmentTiming/types.js +5 -0
  159. package/lib/modules/Holder/utils.d.ts +2 -0
  160. package/lib/modules/Holder/utils.js +27 -1
  161. package/lib/modules/OpenData/contactInfo.d.ts +20 -0
  162. package/lib/modules/OpenData/contactInfo.js +56 -0
  163. package/lib/modules/OpenData/index.d.ts +1 -0
  164. package/lib/modules/OpenData/index.js +12 -0
  165. package/lib/modules/OpenData/types.d.ts +23 -0
  166. package/lib/modules/Order/holderRelations.d.ts +14 -0
  167. package/lib/modules/Order/holderRelations.js +98 -0
  168. package/lib/modules/Order/index.d.ts +16 -4
  169. package/lib/modules/Order/index.js +284 -50
  170. package/lib/modules/Order/localEftposState.d.ts +13 -0
  171. package/lib/modules/Order/localEftposState.js +44 -0
  172. package/lib/modules/Order/pickupTiming.d.ts +46 -0
  173. package/lib/modules/Order/pickupTiming.js +61 -0
  174. package/lib/modules/Order/types.d.ts +49 -3
  175. package/lib/modules/Order/types.js +1 -0
  176. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
  177. package/lib/modules/Order/utils/discountProductLineIdentity.js +51 -2
  178. package/lib/modules/Order/utils/orderCollectionIdentity.js +5 -0
  179. package/lib/modules/Order/utils.d.ts +2 -1
  180. package/lib/modules/Order/utils.js +49 -11
  181. package/lib/modules/Payment/index.js +3 -4
  182. package/lib/modules/Product/types.d.ts +11 -0
  183. package/lib/modules/ProductList/index.js +1 -1
  184. package/lib/modules/ResourcePlanner/planner.d.ts +2 -0
  185. package/lib/modules/ResourcePlanner/planner.js +252 -8
  186. package/lib/modules/ResourcePlanner/types.d.ts +29 -0
  187. package/lib/modules/Rules/index.js +2 -1
  188. package/lib/modules/Schedule/index.d.ts +8 -0
  189. package/lib/modules/Schedule/index.js +68 -12
  190. package/lib/modules/index.d.ts +1 -0
  191. package/lib/modules/index.js +11 -0
  192. package/lib/plugins/request.d.ts +7 -0
  193. package/lib/server/index.d.ts +1 -0
  194. package/lib/server/index.js +166 -39
  195. package/lib/server/modules/form/index.d.ts +19 -0
  196. package/lib/server/modules/form/index.js +73 -0
  197. package/lib/server/modules/form/types.d.ts +13 -0
  198. package/lib/server/modules/form/types.js +9 -0
  199. package/lib/server/modules/index.d.ts +3 -0
  200. package/lib/server/modules/index.js +15 -1
  201. package/lib/server/modules/order/index.d.ts +19 -0
  202. package/lib/server/modules/order/index.js +160 -7
  203. package/lib/server/modules/order/types.d.ts +4 -0
  204. package/lib/server/modules/products/index.d.ts +28 -7
  205. package/lib/server/modules/products/index.js +226 -63
  206. package/lib/server/modules/products/replication.d.ts +8 -0
  207. package/lib/server/modules/products/replication.js +30 -0
  208. package/lib/server/modules/products/types.d.ts +12 -1
  209. package/lib/server/modules/products/types.js +3 -0
  210. package/lib/server/test.json +1 -1
  211. package/lib/server/utils/small-ticket.d.ts +1 -85
  212. package/lib/server/utils/small-ticket.js +9 -2305
  213. package/lib/shared/payment/loadPaymentMethods.d.ts +9 -0
  214. package/lib/shared/payment/loadPaymentMethods.js +40 -0
  215. package/lib/shared/receipt/customerInvoiceLanguages.d.ts +8 -0
  216. package/lib/shared/receipt/customerInvoiceLanguages.js +58 -0
  217. package/lib/shared/receipt/loadCustomerInvoiceLayout.d.ts +27 -0
  218. package/lib/shared/receipt/loadCustomerInvoiceLayout.js +124 -0
  219. package/lib/shared/receipt/small-ticket.d.ts +96 -0
  220. package/lib/shared/receipt/small-ticket.js +2555 -0
  221. package/lib/shared/receipt/templateVisibility.d.ts +26 -0
  222. package/lib/shared/receipt/templateVisibility.js +67 -0
  223. package/lib/shared/sales/loadSalesOrderSnapshot.d.ts +9 -0
  224. package/lib/shared/sales/loadSalesOrderSnapshot.js +22 -0
  225. package/lib/solution/BaseSales/fulfillmentItemRules.d.ts +27 -0
  226. package/lib/solution/BaseSales/fulfillmentItemRules.js +259 -0
  227. package/lib/solution/BaseSales/index.d.ts +43 -16
  228. package/lib/solution/BaseSales/index.js +401 -33
  229. package/lib/solution/BaseSales/pickupTiming.d.ts +47 -0
  230. package/lib/solution/BaseSales/pickupTiming.js +290 -0
  231. package/lib/solution/BaseSales/types.d.ts +12 -0
  232. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
  233. package/lib/solution/BaseSales/utils/parseSalesResponse.js +7 -0
  234. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -8
  235. package/lib/solution/BookingByStep/index.d.ts +4 -2
  236. package/lib/solution/BookingByStep/index.js +7 -3
  237. package/lib/solution/BookingTicket/index.d.ts +23 -3
  238. package/lib/solution/BookingTicket/index.js +197 -9
  239. package/lib/solution/BookingTicket/utils/addProductDecision.d.ts +0 -1
  240. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -1
  241. package/lib/solution/BookingTicket/utils/cartView.js +3 -1
  242. package/lib/solution/OrderInvoicePreview/index.d.ts +66 -0
  243. package/lib/solution/OrderInvoicePreview/index.js +246 -0
  244. package/lib/solution/RegisterAndLogin/config.js +57 -11
  245. package/lib/solution/RegisterAndLogin/index.d.ts +2 -0
  246. package/lib/solution/RegisterAndLogin/index.js +9 -1
  247. package/lib/solution/RegisterAndLogin/utils.d.ts +12 -4
  248. package/lib/solution/RegisterAndLogin/utils.js +24 -17
  249. package/lib/solution/ScanOrder/index.js +59 -20
  250. package/lib/solution/ScanOrder/types.d.ts +3 -0
  251. package/lib/solution/UnifiedBookingSales/businessAvailability.d.ts +27 -0
  252. package/lib/solution/UnifiedBookingSales/businessAvailability.js +138 -0
  253. package/lib/solution/UnifiedBookingSales/index.d.ts +36 -4
  254. package/lib/solution/UnifiedBookingSales/index.js +562 -75
  255. package/lib/solution/UnifiedBookingSales/types.d.ts +16 -2
  256. package/lib/solution/VenueBooking/index.d.ts +15 -2
  257. package/lib/solution/VenueBooking/index.js +243 -96
  258. package/lib/solution/VenueBooking/types.d.ts +2 -1
  259. package/lib/solution/VenueBooking/types.js +1 -0
  260. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +1 -0
  261. package/lib/solution/VenueBooking/utils/dateSummary.js +7 -4
  262. package/lib/solution/VenueBooking/utils/smartPricing.d.ts +71 -0
  263. package/lib/solution/VenueBooking/utils/smartPricing.js +224 -0
  264. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +1 -0
  265. package/lib/solution/VenueBooking/utils/timeSlot.js +5 -2
  266. package/lib/solution/index.d.ts +1 -0
  267. package/lib/solution/index.js +11 -0
  268. package/package.json +1 -1
@@ -21,6 +21,7 @@ export declare const formatProductToCartItem: (params: {
21
21
  product_variant_id?: number;
22
22
  quantity?: number;
23
23
  discounts?: any[];
24
+ isLegacyOrder?: boolean;
24
25
  }) => CartItem;
25
26
  export declare const formatProductToCartItemOrigin: (params: {
26
27
  cartItem: CartItem;
@@ -29,6 +30,7 @@ export declare const formatProductToCartItemOrigin: (params: {
29
30
  options?: any;
30
31
  product_variant_id?: number;
31
32
  quantity?: number;
33
+ isLegacyOrder?: boolean;
32
34
  }) => any;
33
35
  /**
34
36
  * 获取商品总价
@@ -61,7 +63,7 @@ export declare const getProductOriginTotalPrice: (params: {
61
63
  * @param options 套餐规格信息
62
64
  * @returns 格式化后的套餐规格信息
63
65
  */
64
- export declare const formatOptions: (options: any) => any;
66
+ export declare const formatOptions: (options: any, product?: ProductData) => any;
65
67
  export declare const formatOptionsToOrigin: (options: any) => any;
66
68
  /**
67
69
  * 格式化商品套餐信息
@@ -106,7 +106,7 @@ const formatProductToCartItem = params => {
106
106
  cartItem.bundle = formatBundle(bundle);
107
107
  }
108
108
  if (options?.length) {
109
- cartItem.options = formatOptions(options);
109
+ cartItem.options = formatOptions(options, product);
110
110
  }
111
111
  // 拼装出 product_option_string
112
112
  if (product_variant_id) {
@@ -148,22 +148,32 @@ const formatProductToCartItemOrigin = params => {
148
148
  bundle,
149
149
  options,
150
150
  product_variant_id,
151
- quantity = 1
151
+ quantity = 1,
152
+ isLegacyOrder = false
152
153
  } = params;
153
154
  let origin = cartItem._origin;
154
155
  const product_discount_difference = (origin.product?.discount_list || []).filter(item => !item?.metadata?.custom_product_bundle_map_id).reduce((pre, cur) => {
155
156
  return pre + (cur?.metadata?.product_discount_difference || 0);
156
157
  }, 0);
157
158
  if (product) {
159
+ const {
160
+ option: _option,
161
+ ...legacyProductSku
162
+ } = origin.product?.product_sku || {};
158
163
  origin.product = {
159
164
  ...(origin.product || {}),
160
165
  num: quantity,
161
166
  product_id: product.id,
162
167
  product_variant_id: product_variant_id || 0,
163
168
  product_bundle: origin.product?.product_bundle || [],
164
- product_sku: origin.product?.product_sku || {
165
- option: []
166
- },
169
+ ...(isLegacyOrder ? {
170
+ product_sku: legacyProductSku,
171
+ product_option_item: origin.product?.product_option_item || []
172
+ } : {
173
+ product_sku: origin.product?.product_sku || {
174
+ option: []
175
+ }
176
+ }),
167
177
  metadata: {
168
178
  product_discount_difference
169
179
  }
@@ -176,17 +186,22 @@ const formatProductToCartItemOrigin = params => {
176
186
  origin.product.product_bundle = formatBundleToOrigin(bundle);
177
187
  }
178
188
  if (options?.length) {
179
- origin.product.product_sku = {
180
- ...(origin.product.product_sku || {}),
181
- option: formatOptionsToOrigin(options).map(option => {
182
- const next = {
183
- ...option,
184
- add_price: option.add_price ?? option.price
185
- };
186
- delete next.price;
187
- return next;
188
- })
189
- };
189
+ const formattedOptions = formatOptionsToOrigin(options);
190
+ if (isLegacyOrder) {
191
+ origin.product.product_option_item = formattedOptions;
192
+ } else {
193
+ origin.product.product_sku = {
194
+ ...(origin.product.product_sku || {}),
195
+ option: formattedOptions.map(option => {
196
+ const next = {
197
+ ...option,
198
+ add_price: option.add_price ?? option.price
199
+ };
200
+ delete next.price;
201
+ return next;
202
+ })
203
+ };
204
+ }
190
205
  }
191
206
  }
192
207
  return origin;
@@ -299,12 +314,16 @@ const getProductOriginTotalPrice = params => {
299
314
  * @returns 格式化后的套餐规格信息
300
315
  */
301
316
  exports.getProductOriginTotalPrice = getProductOriginTotalPrice;
302
- const formatOptions = options => {
317
+ const formatOptions = (options, product) => {
303
318
  if (!options?.length) return [];
304
319
  return options.map(item => {
320
+ const optionGroupId = item?.option_group_id;
321
+ const optionItemId = item?.id ?? item?.option_group_item_id ?? item?.product_option_item_id;
322
+ const optionGroup = product?.option_group?.find(group => String(group?.id) === String(optionGroupId));
323
+ const optionItem = optionGroup?.option_item?.find(candidate => String(candidate?.id) === String(optionItemId));
305
324
  return {
306
- id: item?.id,
307
- name: item?.name,
325
+ id: optionItemId,
326
+ name: item?.name ?? item?.title ?? optionItem?.name ?? optionItem?.title,
308
327
  num: item?.num,
309
328
  price: item?.price,
310
329
  total: item?.price,
@@ -320,7 +339,7 @@ const formatOptionsToOrigin = options => {
320
339
  return options.map(d => {
321
340
  return {
322
341
  num: d.num,
323
- option_group_item_id: d.option_group_item_id,
342
+ option_group_item_id: d?.option_group_item_id || d?.product_option_item_id,
324
343
  option_group_id: d.option_group_id
325
344
  };
326
345
  });
@@ -0,0 +1,11 @@
1
+ import type { PickupTimingAvailability, PickupTimingBookingTimes, PickupTimingClockInput, PickupTimingComputeInput, PickupTimingConfig, PickupTimingSelection, PickupTimingSlot, PickupTimingValidationResult } from './types';
2
+ export * from './types';
3
+ /** Consume effective OpenData values only; legacy switches never enable Pickup. */
4
+ export declare function normalizePickupTimingConfig(openData: Record<string, unknown>): PickupTimingConfig;
5
+ export declare function resolvePickupTimingDateTime(date: string, time: string, timezone: string, instant?: string): PickupTimingSlot | undefined;
6
+ export declare function getAsapPickupTiming({ config, timezone, now }: PickupTimingClockInput): PickupTimingSlot;
7
+ export declare function pickupTimingSlotToBookingTimes(slot: PickupTimingSlot): PickupTimingBookingTimes;
8
+ export declare function computePickupTimingAvailability(input: PickupTimingComputeInput): PickupTimingAvailability;
9
+ export declare function validatePickupTimingSelection(selection: PickupTimingSelection, input: PickupTimingComputeInput & {
10
+ allowManualOverride?: boolean;
11
+ }): PickupTimingValidationResult;
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _exportNames = {
7
+ normalizePickupTimingConfig: true,
8
+ resolvePickupTimingDateTime: true,
9
+ getAsapPickupTiming: true,
10
+ pickupTimingSlotToBookingTimes: true,
11
+ computePickupTimingAvailability: true,
12
+ validatePickupTimingSelection: true
13
+ };
14
+ exports.computePickupTimingAvailability = computePickupTimingAvailability;
15
+ exports.getAsapPickupTiming = getAsapPickupTiming;
16
+ exports.normalizePickupTimingConfig = normalizePickupTimingConfig;
17
+ exports.pickupTimingSlotToBookingTimes = pickupTimingSlotToBookingTimes;
18
+ exports.resolvePickupTimingDateTime = resolvePickupTimingDateTime;
19
+ exports.validatePickupTimingSelection = validatePickupTimingSelection;
20
+ var _dayjs = _interopRequireDefault(require("dayjs"));
21
+ var _isSameOrAfter = _interopRequireDefault(require("dayjs/plugin/isSameOrAfter"));
22
+ var _isSameOrBefore = _interopRequireDefault(require("dayjs/plugin/isSameOrBefore"));
23
+ var _getDateIsInSchedule = require("../Schedule/getDateIsInSchedule");
24
+ var _types = require("./types");
25
+ Object.keys(_types).forEach(function (key) {
26
+ if (key === "default" || key === "__esModule") return;
27
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
28
+ if (key in exports && exports[key] === _types[key]) return;
29
+ Object.defineProperty(exports, key, {
30
+ enumerable: true,
31
+ get: function () {
32
+ return _types[key];
33
+ }
34
+ });
35
+ });
36
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
37
+ // The shared Schedule resolver uses these comparisons without registering them.
38
+ _dayjs.default.extend(_isSameOrAfter.default);
39
+ _dayjs.default.extend(_isSameOrBefore.default);
40
+ const MINUTE = 60_000;
41
+ const DAY = 24 * 60 * MINUTE;
42
+ const integerSetting = (value, min, max, fallback) => typeof value === 'number' && Number.isInteger(value) && value >= min && value <= max ? value : fallback;
43
+
44
+ /** Consume effective OpenData values only; legacy switches never enable Pickup. */
45
+ function normalizePickupTimingConfig(openData) {
46
+ const handovers = openData['fulfillment.handover_mode'];
47
+ const scheduleIds = openData['fulfillment.pickup.schedule'];
48
+ const operatingHoursScheduleIds = openData['availability.operating_hours'];
49
+ const mode = openData['fulfillment.pickup.timing_mode'];
50
+ return {
51
+ handoverModes: Array.isArray(handovers) ? [...new Set(handovers.filter(value => typeof value === 'string' && value.length > 0))] : [],
52
+ timingMode: mode === 'scheduled_only' || mode === 'asap_and_scheduled' ? mode : 'asap_only',
53
+ scheduleIds: Array.isArray(scheduleIds) ? [...new Set(scheduleIds.filter(value => typeof value === 'number' && Number.isInteger(value) && value > 0))] : [],
54
+ operatingHoursScheduleIds: Array.isArray(operatingHoursScheduleIds) ? [...new Set(operatingHoursScheduleIds.map(value => typeof value === 'number' || typeof value === 'string' ? Number(value) : NaN).filter(value => Number.isInteger(value) && value > 0))] : [],
55
+ slotIntervalMinutes: integerSetting(openData['fulfillment.pickup.slot_interval_minutes'], 1, 1440, 15),
56
+ preparationTimeMinutes: integerSetting(openData['fulfillment.pickup.preparation_time_minutes'], 0, 1440, 0),
57
+ advanceDays: integerSetting(openData['fulfillment.pickup.advance_days'], 0, 365, 7),
58
+ fulfillmentRefMode: typeof openData['fulfillment.fulfillment_ref_mode'] === 'string' ? openData['fulfillment.fulfillment_ref_mode'] : undefined,
59
+ manualInputType: typeof openData['fulfillment.manual_input_type'] === 'string' ? openData['fulfillment.manual_input_type'] : undefined
60
+ };
61
+ }
62
+ function dateStamp(date) {
63
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return NaN;
64
+ const value = Date.parse(`${date}T00:00:00Z`);
65
+ return Number.isFinite(value) && new Date(value).toISOString().slice(0, 10) === date ? value : NaN;
66
+ }
67
+ function addDays(date, days) {
68
+ return new Date(dateStamp(date) + days * DAY).toISOString().slice(0, 10);
69
+ }
70
+ function timeMinutes(time, allowDayEnd = false) {
71
+ if (!/^\d{2}:\d{2}(?::00)?$/.test(time)) return NaN;
72
+ const [hours, minutes] = time.split(':').map(Number);
73
+ if (allowDayEnd && hours === 24 && minutes === 0) return 1440;
74
+ return hours < 24 && minutes < 60 ? hours * 60 + minutes : NaN;
75
+ }
76
+ function instantStamp(value) {
77
+ // A local string would silently use the device timezone instead of the store.
78
+ if (typeof value === 'string' && !/(Z|[+-]\d{2}:?\d{2})$/i.test(value)) return NaN;
79
+ return value instanceof Date ? value.getTime() : new Date(value).getTime();
80
+ }
81
+
82
+ /** Per-query timezone adapter; no device-offset arithmetic or global time cache. */
83
+ function createClock(timezone) {
84
+ if (!timezone || typeof timezone !== 'string') throw new Error('Store timezone is unavailable.');
85
+ let formatter;
86
+ try {
87
+ formatter = new Intl.DateTimeFormat('en-GB', {
88
+ timeZone: timezone,
89
+ year: 'numeric',
90
+ month: '2-digit',
91
+ day: '2-digit',
92
+ hour: '2-digit',
93
+ minute: '2-digit',
94
+ second: '2-digit',
95
+ hourCycle: 'h23'
96
+ });
97
+ } catch {
98
+ throw new Error('Store timezone is invalid.');
99
+ }
100
+ const offsetsByDate = new Map();
101
+ const local = timestamp => {
102
+ const parts = {};
103
+ formatter.formatToParts(timestamp).forEach(part => {
104
+ parts[part.type] = part.value;
105
+ });
106
+ return {
107
+ date: `${parts.year}-${parts.month}-${parts.day}`,
108
+ time: `${parts.hour}:${parts.minute}`,
109
+ second: parts.second
110
+ };
111
+ };
112
+ const offsets = date => {
113
+ const cached = offsetsByDate.get(date);
114
+ if (cached) return cached;
115
+ const result = new Set();
116
+ const nominal = dateStamp(date);
117
+ // Sampling both sides of the target day discovers pre/post-transition offsets.
118
+ for (let hours = -36; hours <= 36; hours += 6) {
119
+ const sample = nominal + hours * 60 * MINUTE;
120
+ const wall = local(sample);
121
+ result.add(Date.parse(`${wall.date}T${wall.time}:${wall.second}Z`) - sample);
122
+ }
123
+ const values = [...result];
124
+ offsetsByDate.set(date, values);
125
+ return values;
126
+ };
127
+ const resolve = (date, time) => {
128
+ const day = dateStamp(date);
129
+ const minutes = timeMinutes(time);
130
+ if (!Number.isFinite(day) || !Number.isFinite(minutes)) return [];
131
+ const label = time.slice(0, 5);
132
+ const nominal = day + minutes * MINUTE;
133
+ return offsets(date).map(offset => nominal - offset).filter(timestamp => {
134
+ const wall = local(timestamp);
135
+ return wall.date === date && wall.time === label;
136
+ }).sort((a, b) => a - b);
137
+ };
138
+ const slot = timestamp => {
139
+ const {
140
+ date,
141
+ time
142
+ } = local(timestamp);
143
+ const instant = new Date(timestamp).toISOString();
144
+ return {
145
+ id: instant,
146
+ date,
147
+ time,
148
+ instant
149
+ };
150
+ };
151
+ return {
152
+ local,
153
+ resolve,
154
+ slot,
155
+ hasOffsetTransition: date => offsets(date).length > 1
156
+ };
157
+ }
158
+ function resolvePickupTimingDateTime(date, time, timezone, instant) {
159
+ const clock = createClock(timezone);
160
+ const matches = clock.resolve(date, time);
161
+ const selected = instant ? instantStamp(instant) : matches.length === 1 ? matches[0] : NaN;
162
+ return matches.includes(selected) ? clock.slot(selected) : undefined;
163
+ }
164
+ function getAsapPickupTiming({
165
+ config,
166
+ timezone,
167
+ now
168
+ }) {
169
+ const timestamp = instantStamp(now);
170
+ if (!Number.isFinite(timestamp)) throw new Error('Current time is invalid.');
171
+ return createClock(timezone).slot(timestamp + config.preparationTimeMinutes * MINUTE);
172
+ }
173
+ function pickupTimingSlotToBookingTimes(slot) {
174
+ return {
175
+ start_date: slot.date,
176
+ start_time: slot.time,
177
+ end_date: slot.date,
178
+ end_time: slot.time
179
+ };
180
+ }
181
+ function createEvaluation(input) {
182
+ const {
183
+ config,
184
+ timezone
185
+ } = input;
186
+ const clock = createClock(timezone);
187
+ const now = instantStamp(input.now);
188
+ if (!Number.isFinite(now)) throw new Error('Current time is invalid.');
189
+ const today = clock.local(now).date;
190
+ const maxDate = addDays(today, config.advanceDays);
191
+ const earliest = now + config.preparationTimeMinutes * MINUTE;
192
+ const schedules = input.schedules.filter(schedule => config.scheduleIds.includes(schedule.id));
193
+ const windowCache = new Map();
194
+ const windows = date => {
195
+ if (!windowCache.has(date)) {
196
+ windowCache.set(date, (0, _getDateIsInSchedule.getScheduleStartEndTimePoints)(date, schedules));
197
+ }
198
+ return windowCache.get(date);
199
+ };
200
+ const operatingIds = config.operatingHoursScheduleIds || [];
201
+ const operatingSchedules = input.schedules.filter(schedule => operatingIds.includes(schedule.id));
202
+ const operatingWindowCache = new Map();
203
+ const operatingWindows = date => {
204
+ if (!operatingWindowCache.has(date)) {
205
+ const ranges = [];
206
+ for (const offset of [-1, 0]) {
207
+ for (const window of (0, _getDateIsInSchedule.getScheduleStartEndTimePoints)(addDays(date, offset), operatingSchedules)) {
208
+ const start = timeMinutes(window.start_time);
209
+ let end = timeMinutes(window.end_time, true);
210
+ if (!Number.isFinite(start) || !Number.isFinite(end)) continue;
211
+ // Store hours use equal endpoints for a full operating day, while
212
+ // the Pickup Schedule may deliberately contain a single time point.
213
+ if (end <= start) end += 1440;
214
+ ranges.push({
215
+ start: start + offset * 1440,
216
+ end: end + offset * 1440
217
+ });
218
+ }
219
+ }
220
+ operatingWindowCache.set(date, ranges);
221
+ }
222
+ return operatingWindowCache.get(date);
223
+ };
224
+ const slotsForDate = (date, firstOnly = false) => {
225
+ if (!Number.isFinite(dateStamp(date)) || date < today || date > maxDate || !config.handoverModes.includes('pick_up') || config.timingMode === 'asap_only') return [];
226
+ const found = new Map();
227
+ // Missing hours configuration preserves the existing all-day convention.
228
+ // Referenced but missing schedules yield no windows, never an all-day fallback.
229
+ const businessWindows = operatingIds.length ? operatingWindows(date) : undefined;
230
+ // Include the prior day's windows so overnight tails belong to their actual date.
231
+ for (const windowDate of [addDays(date, -1), date]) {
232
+ for (const window of windows(windowDate)) {
233
+ const start = timeMinutes(window.start_time);
234
+ let end = timeMinutes(window.end_time, true);
235
+ if (!Number.isFinite(start) || !Number.isFinite(end)) continue;
236
+ if (end < start) end += 1440;
237
+ let firstFoundInWindow = false;
238
+ for (let minute = start; minute <= end; minute += config.slotIntervalMinutes) {
239
+ const targetDate = minute >= 1440 ? addDays(windowDate, 1) : windowDate;
240
+ if (targetDate !== date) continue;
241
+ const localMinute = minute % 1440;
242
+ // Filter the original Pickup grid rather than moving its anchor to
243
+ // the store opening time. A zero-duration pickup may be at closing.
244
+ if (businessWindows && !businessWindows.some(({
245
+ start,
246
+ end
247
+ }) => localMinute >= start && localMinute <= end)) continue;
248
+ const time = `${String(Math.floor(localMinute / 60)).padStart(2, '0')}:${String(localMinute % 60).padStart(2, '0')}`;
249
+ for (const timestamp of clock.resolve(date, time)) {
250
+ if (timestamp < earliest) continue;
251
+ found.set(timestamp, clock.slot(timestamp));
252
+ firstFoundInWindow = true;
253
+ }
254
+ // Summary needs only an available candidate, not a full year's slots.
255
+ // During a repeated hour, an earlier wall label's second occurrence can
256
+ // be later than a subsequent label's first occurrence. Sort them all.
257
+ if (firstOnly && firstFoundInWindow && !clock.hasOffsetTransition(date)) break;
258
+ }
259
+ }
260
+ }
261
+ const result = [...found.entries()].sort(([a], [b]) => a - b).map(([, slot]) => slot);
262
+ return firstOnly ? result.slice(0, 1) : result;
263
+ };
264
+ return {
265
+ clock,
266
+ now,
267
+ today,
268
+ maxDate,
269
+ slotsForDate
270
+ };
271
+ }
272
+ function computePickupTimingAvailability(input) {
273
+ if (!input.config.handoverModes.includes('pick_up')) {
274
+ const now = instantStamp(input.now);
275
+ if (!Number.isFinite(now)) throw new Error('Current time is invalid.');
276
+ return {
277
+ config: input.config,
278
+ timezone: input.timezone,
279
+ now: new Date(now).toISOString(),
280
+ today: '',
281
+ maxDate: '',
282
+ date: input.date || '',
283
+ dates: [],
284
+ slots: []
285
+ };
286
+ }
287
+ const evaluation = createEvaluation(input);
288
+ const {
289
+ today,
290
+ maxDate,
291
+ slotsForDate
292
+ } = evaluation;
293
+ const date = input.date || today;
294
+ if (!Number.isFinite(dateStamp(date))) throw new Error('Pickup date is invalid.');
295
+ const slots = slotsForDate(date);
296
+ const dates = [];
297
+ let firstSlot;
298
+ for (let day = today; day <= maxDate; day = addDays(day, 1)) {
299
+ const first = day === date ? slots[0] : slotsForDate(day, true)[0];
300
+ dates.push({
301
+ date: day,
302
+ status: first ? 'available' : 'unavailable'
303
+ });
304
+ if (!firstSlot && first) firstSlot = first;
305
+ }
306
+ return {
307
+ config: input.config,
308
+ timezone: input.timezone,
309
+ now: new Date(evaluation.now).toISOString(),
310
+ today,
311
+ maxDate,
312
+ date,
313
+ dates,
314
+ slots,
315
+ firstSlot
316
+ };
317
+ }
318
+ function validatePickupTimingSelection(selection, input) {
319
+ const fail = (code, message) => ({
320
+ valid: false,
321
+ code,
322
+ message
323
+ });
324
+ const {
325
+ config
326
+ } = input;
327
+ if (config.handoverModes.length === 0) return {
328
+ valid: true
329
+ };
330
+ if (!config.handoverModes.includes(selection.serviceType)) {
331
+ return fail('handover_unavailable', 'Choose an available handover method.');
332
+ }
333
+ if (selection.serviceType !== 'pick_up') return {
334
+ valid: true
335
+ };
336
+ if (selection.mode === 'asap') {
337
+ return config.timingMode === 'scheduled_only' ? fail('scheduled_required', 'Choose a pickup date and time.') : {
338
+ valid: true,
339
+ slot: getAsapPickupTiming(input)
340
+ };
341
+ }
342
+ if (selection.mode !== 'scheduled' || config.timingMode === 'asap_only') {
343
+ return fail('mode_unavailable', 'The selected pickup timing mode is unavailable.');
344
+ }
345
+ const slot = resolvePickupTimingDateTime(selection.date || '', selection.time || '', input.timezone, selection.instant);
346
+ if (!slot) return fail('invalid_time', 'Choose a valid pickup date and time.');
347
+ const now = instantStamp(input.now);
348
+ if (!Number.isFinite(now)) throw new Error('Current time is invalid.');
349
+ if (instantStamp(slot.instant) < now) return fail('time_in_past', 'Pickup time cannot be in the past.');
350
+ if (selection.source === 'pos_manual' && input.allowManualOverride) return {
351
+ valid: true,
352
+ slot
353
+ };
354
+ const legal = createEvaluation(input).slotsForDate(slot.date).some(candidate => candidate.instant === slot.instant);
355
+ return legal ? {
356
+ valid: true,
357
+ slot
358
+ } : fail('time_unavailable', 'This pickup time is no longer available. Choose another time.');
359
+ }
@@ -0,0 +1,67 @@
1
+ import type { ScheduleItem } from '../Schedule/types';
2
+ export type PickupTimingMode = 'asap_only' | 'scheduled_only' | 'asap_and_scheduled';
3
+ export interface PickupTimingConfig {
4
+ handoverModes: string[];
5
+ timingMode: PickupTimingMode;
6
+ scheduleIds: number[];
7
+ /** Empty or absent means no additional store-hours restriction. */
8
+ operatingHoursScheduleIds?: number[];
9
+ slotIntervalMinutes: number;
10
+ preparationTimeMinutes: number;
11
+ advanceDays: number;
12
+ fulfillmentRefMode?: string;
13
+ manualInputType?: string;
14
+ }
15
+ export interface PickupTimingSelection {
16
+ serviceType: string;
17
+ mode: 'asap' | 'scheduled';
18
+ date?: string;
19
+ time?: string;
20
+ /** The absolute instant disambiguates a repeated local minute during DST. */
21
+ instant?: string;
22
+ source?: 'schedule' | 'pos_manual' | 'asap';
23
+ }
24
+ export interface PickupTimingSlot {
25
+ id: string;
26
+ date: string;
27
+ time: string;
28
+ instant: string;
29
+ }
30
+ export interface PickupTimingAvailability {
31
+ /** Config remains available when Schedule or store timezone cannot be loaded. */
32
+ error?: string;
33
+ config: PickupTimingConfig;
34
+ timezone: string;
35
+ now: string;
36
+ today: string;
37
+ maxDate: string;
38
+ date: string;
39
+ dates: Array<{
40
+ date: string;
41
+ status: 'available' | 'unavailable';
42
+ }>;
43
+ slots: PickupTimingSlot[];
44
+ /** Earliest legal candidate across all permitted dates, for POS prefill. */
45
+ firstSlot?: PickupTimingSlot;
46
+ }
47
+ export interface PickupTimingClockInput {
48
+ config: PickupTimingConfig;
49
+ timezone: string;
50
+ now: Date | string | number;
51
+ }
52
+ export interface PickupTimingComputeInput extends PickupTimingClockInput {
53
+ schedules: ScheduleItem[];
54
+ date?: string;
55
+ }
56
+ export interface PickupTimingValidationResult {
57
+ valid: boolean;
58
+ code?: string;
59
+ message?: string;
60
+ slot?: PickupTimingSlot;
61
+ }
62
+ export interface PickupTimingBookingTimes {
63
+ start_date: string;
64
+ start_time: string;
65
+ end_date: string;
66
+ end_time: string;
67
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
@@ -1,5 +1,7 @@
1
1
  import { ProductData } from '../Product/types';
2
2
  import { IFormItemData, IHolderConfig } from './types';
3
+ /** 保留显式禁用配置;仅在新配置缺失时兼容商品旧 holder 定义。 */
4
+ export declare function resolveProductHolderConfig(product?: ProductData | Record<string, any> | null): Record<string, any> | null;
3
5
  export declare function getProductHolderConfig(product?: ProductData | Record<string, any> | null): IHolderConfig | null;
4
6
  export declare function getFormIdFromHolderConfig(config: IHolderConfig): number;
5
7
  export declare function normalizeFormId(formId: number | string): number;
@@ -8,9 +8,35 @@ exports.getFormIdFromHolderConfig = getFormIdFromHolderConfig;
8
8
  exports.getProductHolderConfig = getProductHolderConfig;
9
9
  exports.normalizeFormId = normalizeFormId;
10
10
  exports.resolveFormMetaFromHolderItem = resolveFormMetaFromHolderItem;
11
+ exports.resolveProductHolderConfig = resolveProductHolderConfig;
12
+ /** 保留显式禁用配置;仅在新配置缺失时兼容商品旧 holder 定义。 */
13
+ function resolveProductHolderConfig(product) {
14
+ if (!product || typeof product !== 'object') return null;
15
+ const source = product;
16
+ const configSources = [source.holder_config, source.metadata?.holder_config, source.origin?.holder_config, source.metadata?.origin?.holder_config, source._origin?.holder_config, source._extend?.holder_config, source._extend?.product?.holder_config, source._extend?.product?.origin?.holder_config, source._extend?.product?.metadata?.holder_config, source._extend?.product?.metadata?.origin?.holder_config, source._extend?.product?._origin?.holder_config, source._extend?.product?._extend?.holder_config];
17
+ const config = configSources.find(value => value !== null && typeof value === 'object');
18
+ if (config) return config;
19
+
20
+ // metadata.holder / _extend.holder 是选择结果,不能作为商品配置读取。
21
+ const legacySources = [source.holder, source.origin?.holder, source.metadata?.origin?.holder, source._origin?.holder, source._extend?.product?.holder, source._extend?.product?.origin?.holder, source._extend?.product?.metadata?.origin?.holder, source._extend?.product?._origin?.holder];
22
+ const legacy = legacySources.find(value => value && typeof value === 'object' && !Array.isArray(value) && typeof value.type === 'string');
23
+ if (!legacy) return null;
24
+ const formId = legacy.custom?.custom_id;
25
+ if (legacy.type === 'custom' && legacy.custom?.type === 'form' && (typeof formId === 'number' || typeof formId === 'string') && Number.isInteger(Number(formId)) && Number(formId) > 0) {
26
+ return {
27
+ status: 'enable',
28
+ required: 0,
29
+ resource_id: formId
30
+ };
31
+ }
32
+ return {
33
+ status: 'disable',
34
+ required: 0
35
+ };
36
+ }
11
37
  function getProductHolderConfig(product) {
12
38
  if (!product) return null;
13
- const config = product?.holder_config ?? product?.origin?.holder_config;
39
+ const config = resolveProductHolderConfig(product);
14
40
  if (config?.status && config?.status !== 'enable') return null;
15
41
  if (!config?.resource_id) return null;
16
42
  return config;
@@ -0,0 +1,20 @@
1
+ import type { OpenDataConfig } from './types';
2
+ export declare const CONTACT_INFO_FIELDS: readonly ["first_name", "last_name", "phone", "email"];
3
+ export type ContactInfoField = typeof CONTACT_INFO_FIELDS[number];
4
+ export interface ContactInfoConfig {
5
+ enabled: boolean;
6
+ fields: Record<ContactInfoField, {
7
+ visible: boolean;
8
+ required: boolean;
9
+ }>;
10
+ }
11
+ export declare function resolveContactInfoConfig(data?: OpenDataConfig | null): ContactInfoConfig;
12
+ export declare function getMissingContactInfoFields(config: ContactInfoConfig, value: unknown): ContactInfoField[];
13
+ export declare function isContactRecord(value: unknown): value is Record<string, any>;
14
+ /** Customer relations wrap the contact in value; sales orders store the object itself. */
15
+ export declare function extractCustomerContactInfo(customer: unknown): Record<string, any> | null;
16
+ export declare class ContactInfoRequiredError extends Error {
17
+ readonly fields: ContactInfoField[];
18
+ readonly code = "CONTACT_INFO_REQUIRED";
19
+ constructor(fields: ContactInfoField[]);
20
+ }