@pisell/pisellos 2.1.119 → 2.1.121

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 (231) hide show
  1. package/dist/apis/picoding.d.ts +0 -0
  2. package/dist/apis/picoding.js +1 -0
  3. package/dist/model/index.d.ts +1 -0
  4. package/dist/model/index.js +1 -0
  5. package/dist/model/strategy/adapter/index.d.ts +7 -0
  6. package/dist/model/strategy/adapter/index.js +7 -0
  7. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +59 -0
  8. package/dist/model/strategy/adapter/itemRule/adapter.js +439 -0
  9. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +43 -0
  10. package/dist/model/strategy/adapter/itemRule/evaluator.js +169 -0
  11. package/dist/model/strategy/adapter/itemRule/examples.d.ts +64 -0
  12. package/dist/model/strategy/adapter/itemRule/examples.js +315 -0
  13. package/dist/model/strategy/adapter/itemRule/index.d.ts +5 -0
  14. package/dist/model/strategy/adapter/itemRule/index.js +5 -0
  15. package/dist/model/strategy/adapter/itemRule/type.d.ts +206 -0
  16. package/dist/model/strategy/adapter/itemRule/type.js +101 -0
  17. package/dist/model/strategy/adapter/promotion/adapter.d.ts +66 -0
  18. package/dist/model/strategy/adapter/promotion/adapter.js +271 -0
  19. package/dist/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
  20. package/dist/model/strategy/adapter/promotion/evaluator.js +1206 -0
  21. package/dist/model/strategy/adapter/promotion/examples.d.ts +138 -0
  22. package/dist/model/strategy/adapter/promotion/examples.js +166 -0
  23. package/dist/model/strategy/adapter/promotion/index.d.ts +4 -0
  24. package/dist/model/strategy/adapter/promotion/index.js +0 -0
  25. package/dist/model/strategy/adapter/promotion/type.d.ts +447 -0
  26. package/dist/model/strategy/adapter/promotion/type.js +209 -0
  27. package/dist/model/strategy/adapter/type.d.ts +28 -0
  28. package/dist/model/strategy/adapter/type.js +1 -0
  29. package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +84 -0
  30. package/dist/model/strategy/adapter/walletPass/evaluator.js +502 -0
  31. package/dist/model/strategy/adapter/walletPass/example.d.ts +4 -0
  32. package/dist/model/strategy/adapter/walletPass/example.js +258 -0
  33. package/dist/model/strategy/adapter/walletPass/index.d.ts +32 -0
  34. package/dist/model/strategy/adapter/walletPass/index.js +182 -0
  35. package/dist/model/strategy/adapter/walletPass/locales.d.ts +1 -0
  36. package/dist/model/strategy/adapter/walletPass/locales.js +26 -0
  37. package/dist/model/strategy/adapter/walletPass/type.d.ts +187 -0
  38. package/dist/model/strategy/adapter/walletPass/type.js +1 -0
  39. package/dist/model/strategy/adapter/walletPass/utils.d.ts +50 -0
  40. package/dist/model/strategy/adapter/walletPass/utils.js +1104 -0
  41. package/dist/model/strategy/engine.d.ts +106 -0
  42. package/dist/model/strategy/engine.js +611 -0
  43. package/dist/model/strategy/index.d.ts +3 -0
  44. package/dist/model/strategy/index.js +8 -0
  45. package/dist/model/strategy/strategy-example.d.ts +5 -0
  46. package/dist/model/strategy/strategy-example.js +331 -0
  47. package/dist/model/strategy/type.d.ts +228 -0
  48. package/dist/model/strategy/type.js +94 -0
  49. package/dist/modules/Cart/utils/cartProduct.js +1 -0
  50. package/dist/modules/OpenData/index.d.ts +24 -0
  51. package/dist/modules/OpenData/index.js +173 -0
  52. package/dist/modules/OpenData/types.d.ts +73 -0
  53. package/dist/modules/OpenData/types.js +1 -0
  54. package/dist/modules/OpenData/utils.d.ts +2 -0
  55. package/dist/modules/OpenData/utils.js +75 -0
  56. package/dist/modules/Order/index.d.ts +58 -1
  57. package/dist/modules/Order/index.js +796 -29
  58. package/dist/modules/Order/types.d.ts +144 -12
  59. package/dist/modules/Order/utils.d.ts +28 -0
  60. package/dist/modules/Order/utils.js +250 -1
  61. package/dist/modules/Product/index.d.ts +1 -1
  62. package/dist/modules/Product/utils.js +2 -2
  63. package/dist/modules/ProductList/index.d.ts +1 -1
  64. package/dist/modules/ProductList/index.js +2 -1
  65. package/dist/modules/Quotation/index.d.ts +48 -0
  66. package/dist/modules/Quotation/index.js +245 -0
  67. package/dist/modules/Quotation/types.d.ts +42 -0
  68. package/dist/modules/Quotation/types.js +1 -0
  69. package/dist/modules/Rules/index.js +4 -1
  70. package/dist/modules/SalesSummary/index.d.ts +63 -0
  71. package/dist/modules/SalesSummary/index.js +174 -0
  72. package/dist/modules/SalesSummary/types.d.ts +59 -0
  73. package/dist/modules/SalesSummary/types.js +1 -0
  74. package/dist/modules/SalesSummary/utils.d.ts +30 -0
  75. package/dist/modules/SalesSummary/utils.js +513 -0
  76. package/dist/modules/ScanOrderLogger/index.d.ts +21 -0
  77. package/dist/modules/ScanOrderLogger/index.js +161 -0
  78. package/dist/modules/ScanOrderLogger/providers/feishu.d.ts +2 -0
  79. package/dist/modules/ScanOrderLogger/providers/feishu.js +95 -0
  80. package/dist/modules/ScanOrderLogger/providers/grafana.d.ts +2 -0
  81. package/dist/modules/ScanOrderLogger/providers/grafana.js +50 -0
  82. package/dist/modules/ScanOrderLogger/types.d.ts +46 -0
  83. package/dist/modules/ScanOrderLogger/types.js +1 -0
  84. package/dist/modules/Schedule/getDateIsInSchedule.js +11 -18
  85. package/dist/modules/Summary/utils.d.ts +3 -3
  86. package/dist/modules/Summary/utils.js +4 -4
  87. package/dist/modules/index.d.ts +4 -0
  88. package/dist/modules/index.js +5 -1
  89. package/dist/solution/BookingByStep/index.d.ts +1 -1
  90. package/dist/solution/BookingByStep/types.d.ts +3 -1
  91. package/dist/solution/BookingByStep/types.js +5 -1
  92. package/dist/solution/BookingTicket/index.d.ts +1 -1
  93. package/dist/solution/ScanOrder/index.d.ts +90 -0
  94. package/dist/solution/ScanOrder/index.js +1853 -0
  95. package/dist/solution/ScanOrder/types.d.ts +210 -0
  96. package/dist/solution/ScanOrder/types.js +16 -0
  97. package/dist/solution/ScanOrder/utils.d.ts +93 -0
  98. package/dist/solution/ScanOrder/utils.js +397 -0
  99. package/dist/solution/VenueBooking/index.d.ts +163 -0
  100. package/dist/solution/VenueBooking/index.js +2931 -0
  101. package/dist/solution/VenueBooking/sales-section-4-annotated.json +343 -0
  102. package/dist/solution/VenueBooking/types.d.ts +130 -0
  103. package/dist/solution/VenueBooking/types.js +21 -0
  104. package/dist/solution/VenueBooking/utils/dateSummary.d.ts +10 -0
  105. package/dist/solution/VenueBooking/utils/dateSummary.js +102 -0
  106. package/dist/solution/VenueBooking/utils/resource.d.ts +4 -0
  107. package/dist/solution/VenueBooking/utils/resource.js +94 -0
  108. package/dist/solution/VenueBooking/utils/slotMerge.d.ts +29 -0
  109. package/dist/solution/VenueBooking/utils/slotMerge.js +203 -0
  110. package/dist/solution/VenueBooking/utils/timeSlot.d.ts +32 -0
  111. package/dist/solution/VenueBooking/utils/timeSlot.js +256 -0
  112. package/dist/solution/VenueBooking/utils.d.ts +1 -0
  113. package/dist/solution/VenueBooking/utils.js +1 -0
  114. package/dist/solution/index.d.ts +2 -0
  115. package/dist/solution/index.js +3 -1
  116. package/lib/apis/picoding.d.ts +0 -0
  117. package/lib/apis/picoding.js +0 -0
  118. package/lib/model/index.d.ts +1 -0
  119. package/lib/model/index.js +23 -0
  120. package/lib/model/strategy/adapter/index.d.ts +7 -0
  121. package/lib/model/strategy/adapter/index.js +57 -0
  122. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +59 -0
  123. package/lib/model/strategy/adapter/itemRule/adapter.js +338 -0
  124. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +43 -0
  125. package/lib/model/strategy/adapter/itemRule/evaluator.js +124 -0
  126. package/lib/model/strategy/adapter/itemRule/examples.d.ts +64 -0
  127. package/lib/model/strategy/adapter/itemRule/examples.js +269 -0
  128. package/lib/model/strategy/adapter/itemRule/index.d.ts +5 -0
  129. package/lib/model/strategy/adapter/itemRule/index.js +58 -0
  130. package/lib/model/strategy/adapter/itemRule/type.d.ts +206 -0
  131. package/lib/model/strategy/adapter/itemRule/type.js +46 -0
  132. package/lib/model/strategy/adapter/promotion/adapter.d.ts +66 -0
  133. package/lib/model/strategy/adapter/promotion/adapter.js +217 -0
  134. package/lib/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
  135. package/lib/model/strategy/adapter/promotion/evaluator.js +844 -0
  136. package/lib/model/strategy/adapter/promotion/examples.d.ts +138 -0
  137. package/lib/model/strategy/adapter/promotion/examples.js +192 -0
  138. package/lib/model/strategy/adapter/promotion/index.d.ts +4 -0
  139. package/lib/model/strategy/adapter/promotion/index.js +49 -0
  140. package/lib/model/strategy/adapter/promotion/type.d.ts +447 -0
  141. package/lib/model/strategy/adapter/promotion/type.js +51 -0
  142. package/lib/model/strategy/adapter/type.d.ts +28 -0
  143. package/lib/model/strategy/adapter/type.js +17 -0
  144. package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +84 -0
  145. package/lib/model/strategy/adapter/walletPass/evaluator.js +424 -0
  146. package/lib/model/strategy/adapter/walletPass/example.d.ts +4 -0
  147. package/lib/model/strategy/adapter/walletPass/example.js +207 -0
  148. package/lib/model/strategy/adapter/walletPass/index.d.ts +32 -0
  149. package/lib/model/strategy/adapter/walletPass/index.js +142 -0
  150. package/lib/model/strategy/adapter/walletPass/locales.d.ts +1 -0
  151. package/lib/model/strategy/adapter/walletPass/locales.js +54 -0
  152. package/lib/model/strategy/adapter/walletPass/type.d.ts +187 -0
  153. package/lib/model/strategy/adapter/walletPass/type.js +17 -0
  154. package/lib/model/strategy/adapter/walletPass/utils.d.ts +50 -0
  155. package/lib/model/strategy/adapter/walletPass/utils.js +791 -0
  156. package/lib/model/strategy/engine.d.ts +106 -0
  157. package/lib/model/strategy/engine.js +450 -0
  158. package/lib/model/strategy/index.d.ts +3 -0
  159. package/lib/model/strategy/index.js +38 -0
  160. package/lib/model/strategy/strategy-example.d.ts +5 -0
  161. package/lib/model/strategy/strategy-example.js +318 -0
  162. package/lib/model/strategy/type.d.ts +228 -0
  163. package/lib/model/strategy/type.js +44 -0
  164. package/lib/modules/Cart/utils/cartProduct.js +1 -0
  165. package/lib/modules/OpenData/index.d.ts +24 -0
  166. package/lib/modules/OpenData/index.js +119 -0
  167. package/lib/modules/OpenData/types.d.ts +73 -0
  168. package/lib/modules/OpenData/types.js +17 -0
  169. package/lib/modules/OpenData/utils.d.ts +2 -0
  170. package/lib/modules/OpenData/utils.js +111 -0
  171. package/lib/modules/Order/index.d.ts +58 -1
  172. package/lib/modules/Order/index.js +437 -1
  173. package/lib/modules/Order/types.d.ts +144 -12
  174. package/lib/modules/Order/utils.d.ts +28 -0
  175. package/lib/modules/Order/utils.js +250 -2
  176. package/lib/modules/Product/index.d.ts +1 -1
  177. package/lib/modules/Product/utils.js +2 -2
  178. package/lib/modules/ProductList/index.d.ts +1 -1
  179. package/lib/modules/ProductList/index.js +2 -1
  180. package/lib/modules/Quotation/index.d.ts +48 -0
  181. package/lib/modules/Quotation/index.js +149 -0
  182. package/lib/modules/Quotation/types.d.ts +42 -0
  183. package/lib/modules/Quotation/types.js +17 -0
  184. package/lib/modules/Rules/index.js +4 -1
  185. package/lib/modules/SalesSummary/index.d.ts +63 -0
  186. package/lib/modules/SalesSummary/index.js +105 -0
  187. package/lib/modules/SalesSummary/types.d.ts +59 -0
  188. package/lib/modules/SalesSummary/types.js +17 -0
  189. package/lib/modules/SalesSummary/utils.d.ts +30 -0
  190. package/lib/modules/SalesSummary/utils.js +452 -0
  191. package/lib/modules/ScanOrderLogger/index.d.ts +21 -0
  192. package/lib/modules/ScanOrderLogger/index.js +135 -0
  193. package/lib/modules/ScanOrderLogger/providers/feishu.d.ts +2 -0
  194. package/lib/modules/ScanOrderLogger/providers/feishu.js +82 -0
  195. package/lib/modules/ScanOrderLogger/providers/grafana.d.ts +2 -0
  196. package/lib/modules/ScanOrderLogger/providers/grafana.js +52 -0
  197. package/lib/modules/ScanOrderLogger/types.d.ts +46 -0
  198. package/lib/modules/ScanOrderLogger/types.js +17 -0
  199. package/lib/modules/Schedule/getDateIsInSchedule.js +9 -11
  200. package/lib/modules/Summary/utils.d.ts +3 -3
  201. package/lib/modules/Summary/utils.js +4 -4
  202. package/lib/modules/index.d.ts +4 -0
  203. package/lib/modules/index.js +9 -1
  204. package/lib/solution/BookingByStep/index.d.ts +1 -1
  205. package/lib/solution/BookingByStep/types.d.ts +3 -1
  206. package/lib/solution/BookingByStep/types.js +10 -0
  207. package/lib/solution/BookingTicket/index.d.ts +1 -1
  208. package/lib/solution/ScanOrder/index.d.ts +90 -0
  209. package/lib/solution/ScanOrder/index.js +1071 -0
  210. package/lib/solution/ScanOrder/types.d.ts +210 -0
  211. package/lib/solution/ScanOrder/types.js +36 -0
  212. package/lib/solution/ScanOrder/utils.d.ts +93 -0
  213. package/lib/solution/ScanOrder/utils.js +359 -0
  214. package/lib/solution/VenueBooking/index.d.ts +163 -0
  215. package/lib/solution/VenueBooking/index.js +1578 -0
  216. package/lib/solution/VenueBooking/sales-section-4-annotated.json +343 -0
  217. package/lib/solution/VenueBooking/types.d.ts +130 -0
  218. package/lib/solution/VenueBooking/types.js +44 -0
  219. package/lib/solution/VenueBooking/utils/dateSummary.d.ts +10 -0
  220. package/lib/solution/VenueBooking/utils/dateSummary.js +101 -0
  221. package/lib/solution/VenueBooking/utils/resource.d.ts +4 -0
  222. package/lib/solution/VenueBooking/utils/resource.js +80 -0
  223. package/lib/solution/VenueBooking/utils/slotMerge.d.ts +29 -0
  224. package/lib/solution/VenueBooking/utils/slotMerge.js +208 -0
  225. package/lib/solution/VenueBooking/utils/timeSlot.d.ts +32 -0
  226. package/lib/solution/VenueBooking/utils/timeSlot.js +200 -0
  227. package/lib/solution/VenueBooking/utils.d.ts +1 -0
  228. package/lib/solution/VenueBooking/utils.js +69 -0
  229. package/lib/solution/index.d.ts +2 -0
  230. package/lib/solution/index.js +5 -1
  231. package/package.json +1 -1
@@ -0,0 +1,1578 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/solution/VenueBooking/index.ts
31
+ var VenueBooking_exports = {};
32
+ __export(VenueBooking_exports, {
33
+ VenueBookingImpl: () => VenueBookingImpl
34
+ });
35
+ module.exports = __toCommonJS(VenueBooking_exports);
36
+ var import_BaseModule = require("../../modules/BaseModule");
37
+ var import_types = require("./types");
38
+ var import_utils = require("./utils");
39
+ var import_types2 = require("../BookingByStep/types");
40
+ var import_ProductList = require("../../modules/ProductList");
41
+ var import_Date = require("../../modules/Date");
42
+ var import_Schedule = require("../../modules/Schedule");
43
+ var import_Quotation = require("../../modules/Quotation");
44
+ var import_OpenData = require("../../modules/OpenData");
45
+ var import_types3 = require("../../modules/Account/types");
46
+ var import_dayjs = __toESM(require("dayjs"));
47
+ var import_itemRule = require("../../model/strategy/adapter/itemRule");
48
+ var import_resource = require("./utils/resource");
49
+ var import_timeSlot = require("./utils/timeSlot");
50
+ var import_dateSummary = require("./utils/dateSummary");
51
+ var import_slotMerge = require("./utils/slotMerge");
52
+ var import_utils2 = require("../../modules/Order/utils");
53
+ var import_Order = require("../../modules/Order");
54
+ var import_types4 = require("../RegisterAndLogin/types");
55
+ var import_decimal = __toESM(require("decimal.js"));
56
+ __reExport(VenueBooking_exports, require("./types"), module.exports);
57
+ var OPEN_DATA_SECTION_CODES = [
58
+ "basic",
59
+ "fulfillment",
60
+ "reservation",
61
+ "sale",
62
+ "menu",
63
+ "availability",
64
+ "workflow",
65
+ "checkout"
66
+ ];
67
+ function cloneCustomDepositData(customDepositData) {
68
+ if (!customDepositData || typeof customDepositData !== "object")
69
+ return void 0;
70
+ return {
71
+ ...customDepositData,
72
+ self_deposit_policy_ids: Array.isArray(customDepositData.self_deposit_policy_ids) ? [...customDepositData.self_deposit_policy_ids] : [],
73
+ deposit_policy_ids: Array.isArray(customDepositData.deposit_policy_ids) ? [...customDepositData.deposit_policy_ids] : [],
74
+ deposit_policy_data: Array.isArray(customDepositData.deposit_policy_data) ? [...customDepositData.deposit_policy_data] : []
75
+ };
76
+ }
77
+ var _VenueBookingImpl = class extends import_BaseModule.BaseModule {
78
+ constructor(name, version) {
79
+ super(name, version);
80
+ this.defaultName = "venueBooking";
81
+ this.defaultVersion = "1.0.0";
82
+ this.isSolution = true;
83
+ this.initializeOptions = {};
84
+ this.store = {
85
+ entryContext: null,
86
+ status: "idle",
87
+ flow: {},
88
+ error: null,
89
+ products: void 0,
90
+ rawResourceData: [],
91
+ slotConfig: { ...import_types.DEFAULT_SLOT_CONFIG },
92
+ itemRuleQuantityLimits: [],
93
+ cartValidation: {
94
+ passed: null,
95
+ failures: []
96
+ }
97
+ };
98
+ this.otherParams = {};
99
+ this.itemRuleEvaluator = new import_itemRule.ItemRuleEvaluator();
100
+ this.itemRuleConfigs = [];
101
+ this.itemRuleConfigsPromise = null;
102
+ this.itemRulePrefillApplied = false;
103
+ this.itemRuleRuntimeConfig = {};
104
+ this.resourceProductMap = /* @__PURE__ */ new Map();
105
+ this.loginEffectDisposers = [];
106
+ this.customerLoginRefreshInFlight = null;
107
+ this.customerLoginRefreshIdInFlight = null;
108
+ this.loadAllProductsInFlight = null;
109
+ this.productsLoaded = false;
110
+ this.loadOpenDataConfigInFlight = null;
111
+ }
112
+ getLoggerContext() {
113
+ return {
114
+ cacheId: this.cacheId,
115
+ solutionName: this.name,
116
+ moduleName: "venueBooking"
117
+ };
118
+ }
119
+ serializeError(error) {
120
+ if (error instanceof Error) {
121
+ return {
122
+ name: error.name,
123
+ message: error.message,
124
+ stack: error.stack
125
+ };
126
+ }
127
+ return {
128
+ message: String(error)
129
+ };
130
+ }
131
+ async addVenueBookingLog(params) {
132
+ const payload = {
133
+ cacheId: this.cacheId,
134
+ ...params.payload || {}
135
+ };
136
+ const extra = {
137
+ ...params.extra || {}
138
+ };
139
+ const logger = this.store.scanOrderLogger;
140
+ if (!logger) {
141
+ if ((params.level || "info") === "error") {
142
+ console.error("[VenueBooking][log-fallback]", params.title, { payload, extra });
143
+ } else {
144
+ console.log("[VenueBooking][log-fallback]", params.title, { payload, extra });
145
+ }
146
+ return;
147
+ }
148
+ await logger.addLog({
149
+ ...params,
150
+ payload,
151
+ extra
152
+ });
153
+ }
154
+ logMethodStart(method, payload = {}) {
155
+ void this.addVenueBookingLog({
156
+ level: "info",
157
+ title: `[VenueBooking] ${method} start`,
158
+ payload: {
159
+ method,
160
+ ...payload
161
+ }
162
+ });
163
+ }
164
+ logMethodSuccess(method, payload = {}) {
165
+ void this.addVenueBookingLog({
166
+ level: "info",
167
+ title: `[VenueBooking] ${method} success`,
168
+ payload: {
169
+ method,
170
+ ...payload
171
+ }
172
+ });
173
+ }
174
+ logMethodError(method, error, payload = {}) {
175
+ void this.addVenueBookingLog({
176
+ level: "error",
177
+ title: `[VenueBooking] ${method} failed`,
178
+ payload: {
179
+ method,
180
+ ...payload,
181
+ error: this.serializeError(error)
182
+ }
183
+ });
184
+ }
185
+ async addLog(params) {
186
+ await this.addVenueBookingLog({
187
+ ...params,
188
+ payload: {
189
+ source: "ui-bridge",
190
+ ...params.payload || {}
191
+ }
192
+ });
193
+ }
194
+ normalizeCustomerId(value) {
195
+ const customerId = Number(value);
196
+ if (!Number.isFinite(customerId) || customerId <= 0)
197
+ return null;
198
+ return customerId;
199
+ }
200
+ resolveCustomerIdFromLoginPayload(payload) {
201
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
202
+ const candidates = [
203
+ payload == null ? void 0 : payload.customerId,
204
+ payload == null ? void 0 : payload.customer_id,
205
+ payload == null ? void 0 : payload.id,
206
+ (_a = payload == null ? void 0 : payload.user) == null ? void 0 : _a.customerId,
207
+ (_b = payload == null ? void 0 : payload.user) == null ? void 0 : _b.customer_id,
208
+ (_c = payload == null ? void 0 : payload.user) == null ? void 0 : _c.id,
209
+ (_e = (_d = payload == null ? void 0 : payload.user) == null ? void 0 : _d._origin) == null ? void 0 : _e.customer_id,
210
+ (_f = payload == null ? void 0 : payload.account) == null ? void 0 : _f.customerId,
211
+ (_g = payload == null ? void 0 : payload.account) == null ? void 0 : _g.customer_id,
212
+ (_h = payload == null ? void 0 : payload.account) == null ? void 0 : _h.id,
213
+ (_i = payload == null ? void 0 : payload._origin) == null ? void 0 : _i.customer_id
214
+ ];
215
+ for (const candidate of candidates) {
216
+ const customerId = this.normalizeCustomerId(candidate);
217
+ if (customerId)
218
+ return customerId;
219
+ }
220
+ return null;
221
+ }
222
+ clearLoginEffectListeners() {
223
+ for (const dispose of this.loginEffectDisposers) {
224
+ dispose();
225
+ }
226
+ this.loginEffectDisposers = [];
227
+ }
228
+ registerLoginEffect(event, callback) {
229
+ var _a;
230
+ const effects = (_a = this.core) == null ? void 0 : _a.effects;
231
+ if (!(effects == null ? void 0 : effects.on))
232
+ return;
233
+ effects.on(event, callback);
234
+ this.loginEffectDisposers.push(() => {
235
+ if (typeof effects.off === "function") {
236
+ effects.off(event, callback);
237
+ }
238
+ });
239
+ }
240
+ registerCustomerLoginListeners() {
241
+ var _a, _b, _c, _d;
242
+ this.clearLoginEffectListeners();
243
+ const accountModule = (_a = this.core) == null ? void 0 : _a.getModule("account");
244
+ const registerAndLoginModule = (_b = this.core) == null ? void 0 : _b.getModule("registerAndLogin");
245
+ const currentAccount = ((_c = accountModule == null ? void 0 : accountModule.getCurrentAccount) == null ? void 0 : _c.call(accountModule)) || ((_d = accountModule == null ? void 0 : accountModule.getAccount) == null ? void 0 : _d.call(accountModule)) || null;
246
+ const createHandleLogin = (eventName) => async (payload) => {
247
+ const customerId = this.resolveCustomerIdFromLoginPayload(payload);
248
+ if (!customerId)
249
+ return;
250
+ await this.refreshOrderMarketingAfterLogin({ customerId });
251
+ };
252
+ this.registerLoginEffect(import_types3.AccountHooks.OnLogin, createHandleLogin(import_types3.AccountHooks.OnLogin));
253
+ this.registerLoginEffect(import_types4.RegisterAndLoginHooks.onLoginSuccess, createHandleLogin(import_types4.RegisterAndLoginHooks.onLoginSuccess));
254
+ }
255
+ async refreshOrderMarketingAfterLogin(params) {
256
+ if (!this.store.order)
257
+ throw new Error("order 模块未初始化");
258
+ if (this.customerLoginRefreshInFlight) {
259
+ if (this.customerLoginRefreshIdInFlight === params.customerId) {
260
+ await this.customerLoginRefreshInFlight;
261
+ return;
262
+ }
263
+ await this.customerLoginRefreshInFlight;
264
+ }
265
+ this.customerLoginRefreshIdInFlight = params.customerId;
266
+ const refreshTask = (async () => {
267
+ var _a;
268
+ if (this.store.quotation) {
269
+ await this.store.quotation.loadQuotations({
270
+ channel: (_a = this.otherParams) == null ? void 0 : _a.channel
271
+ });
272
+ }
273
+ this.recalculateOrderPricesFromQuotation();
274
+ await this.store.order.loadDiscountConfig({
275
+ customerId: params.customerId
276
+ });
277
+ await this.store.order.recalculateSummary({ createIfMissing: true });
278
+ this.store.order.persistTempOrder();
279
+ await this.refreshItemRuleQuantityLimits();
280
+ await this.refreshCartValidationPassed();
281
+ })();
282
+ this.customerLoginRefreshInFlight = refreshTask;
283
+ try {
284
+ await refreshTask;
285
+ } catch (error) {
286
+ throw error;
287
+ } finally {
288
+ if (this.customerLoginRefreshInFlight === refreshTask) {
289
+ this.customerLoginRefreshInFlight = null;
290
+ this.customerLoginRefreshIdInFlight = null;
291
+ }
292
+ }
293
+ }
294
+ async initialize(core, options = {}) {
295
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
296
+ this.logMethodStart("initialize");
297
+ this.core = core;
298
+ this.initializeOptions = options || {};
299
+ this.store = { ...this.store, ...options.store };
300
+ this.store.entryContext = ((_a = options.otherParams) == null ? void 0 : _a.entryContext) || this.store.entryContext;
301
+ this.store.status = "initializing";
302
+ this.store.error = null;
303
+ this.store.rawResourceData = [];
304
+ this.store.slotConfig = {
305
+ ...import_types.DEFAULT_SLOT_CONFIG,
306
+ ...((_b = options.otherParams) == null ? void 0 : _b.slotConfig) || {}
307
+ };
308
+ this.otherParams = options.otherParams || {};
309
+ this.cacheId = (_c = this.otherParams) == null ? void 0 : _c.cacheId;
310
+ this.itemRuleRuntimeConfig = ((_d = this.otherParams) == null ? void 0 : _d.venueBookingItemRule) || ((_e = this.otherParams) == null ? void 0 : _e.itemRule) || {};
311
+ this.itemRuleConfigs = [];
312
+ this.itemRuleConfigsPromise = null;
313
+ this.itemRulePrefillApplied = false;
314
+ this.store.itemRuleQuantityLimits = [];
315
+ this.store.cartValidation = {
316
+ passed: null,
317
+ failures: []
318
+ };
319
+ this.window = core.getPlugin("window");
320
+ this.request = core.getPlugin("request");
321
+ if (!this.window) {
322
+ this.logMethodError("initialize", "window plugin missing");
323
+ throw new Error("venueBooking解决方案需要 window 插件支持");
324
+ }
325
+ if (!this.request) {
326
+ this.logMethodError("initialize", "request plugin missing");
327
+ throw new Error("venueBooking解决方案需要 request 插件支持");
328
+ }
329
+ const baseModules = [
330
+ "scanOrderLogger",
331
+ "products",
332
+ "order",
333
+ "salesSummary"
334
+ ];
335
+ baseModules.forEach((step) => {
336
+ var _a2, _b2, _c2, _d2, _e2, _f2;
337
+ const targetModule = (0, import_types2.createModule)(step, this.name);
338
+ if (targetModule) {
339
+ this.store[step] = targetModule;
340
+ const initialState = step === "salesSummary" ? {
341
+ summary: ((_b2 = (_a2 = this.store.order) == null ? void 0 : _a2.getTempOrder()) == null ? void 0 : _b2.summary) || (0, import_utils.createEmptySummary)()
342
+ } : {};
343
+ const loggerProvider = ((_c2 = this.otherParams) == null ? void 0 : _c2.loggerProvider) || "feishu";
344
+ const loggerConfig = ((_d2 = this.otherParams) == null ? void 0 : _d2.loggerConfig) || {
345
+ feishu: {}
346
+ };
347
+ this.core.registerModule(targetModule, {
348
+ initialState,
349
+ otherParams: {
350
+ ...this.otherParams,
351
+ fatherModule: this.name,
352
+ openCache: ((_e2 = this.otherParams) == null ? void 0 : _e2.cacheId) ? true : false,
353
+ cacheId: (_f2 = this.otherParams) == null ? void 0 : _f2.cacheId,
354
+ salesSummaryModuleName: `${this.name}_salesSummary`,
355
+ provider: loggerProvider,
356
+ providerConfig: loggerConfig,
357
+ context: this.getLoggerContext()
358
+ }
359
+ });
360
+ } else {
361
+ this.logMethodError("initialize", `module ${step} missing`);
362
+ throw new Error(`模块 ${step} 不存在`);
363
+ }
364
+ });
365
+ const venueProductsModule = new import_ProductList.ProductList(`${this.name}_venueProducts`);
366
+ this.store.venueProducts = venueProductsModule;
367
+ this.core.registerModule(venueProductsModule, {
368
+ otherParams: {
369
+ ...this.otherParams,
370
+ fatherModule: this.name
371
+ }
372
+ });
373
+ const addonProductsModule = new import_ProductList.ProductList(`${this.name}_addonProducts`);
374
+ this.store.addonProducts = addonProductsModule;
375
+ this.core.registerModule(addonProductsModule, {
376
+ otherParams: {
377
+ ...this.otherParams,
378
+ fatherModule: this.name
379
+ }
380
+ });
381
+ const dateModule = new import_Date.DateModule(`${this.name}_date`);
382
+ this.store.date = dateModule;
383
+ this.core.registerModule(dateModule, {
384
+ otherParams: {
385
+ ...this.otherParams,
386
+ fatherModule: this.name,
387
+ cacheId: this.cacheId
388
+ }
389
+ });
390
+ const scheduleModule = new import_Schedule.ScheduleModule(`${this.name}_schedule`);
391
+ this.store.schedule = scheduleModule;
392
+ this.core.registerModule(scheduleModule, {
393
+ otherParams: {
394
+ ...this.otherParams,
395
+ fatherModule: this.name
396
+ }
397
+ });
398
+ const quotationModule = new import_Quotation.QuotationModule(`${this.name}_quotation`);
399
+ this.store.quotation = quotationModule;
400
+ this.core.registerModule(quotationModule, {
401
+ otherParams: {
402
+ ...this.otherParams,
403
+ fatherModule: this.name
404
+ }
405
+ });
406
+ const openDataModule = new import_OpenData.OpenDataModule(`${this.name}_openData`);
407
+ this.store.openData = openDataModule;
408
+ this.core.registerModule(openDataModule, {
409
+ otherParams: {
410
+ ...this.otherParams,
411
+ fatherModule: this.name,
412
+ openCache: !!((_f = this.otherParams) == null ? void 0 : _f.cacheId),
413
+ cacheId: (_g = this.otherParams) == null ? void 0 : _g.cacheId
414
+ }
415
+ });
416
+ if (this.store.scanOrderLogger) {
417
+ this.store.scanOrderLogger.setContext(this.getLoggerContext());
418
+ }
419
+ this.registerCustomerLoginListeners();
420
+ console.log("[VenueBooking] 初始化开始");
421
+ try {
422
+ await ((_h = this.store.order) == null ? void 0 : _h.recalculateSummary({ createIfMissing: false }));
423
+ (_i = this.store.order) == null ? void 0 : _i.persistTempOrder();
424
+ await this.loadRuntimeConfigs();
425
+ if (this.store.schedule) {
426
+ await this.store.schedule.loadAllSchedule();
427
+ this.injectScheduleResolverToQuotation();
428
+ }
429
+ this.loadQuotations();
430
+ await this.refreshItemRuleQuantityLimits();
431
+ this.store.status = "ready";
432
+ console.log("[VenueBooking] 初始化完成");
433
+ await this.core.effects.emit(import_types.VenueBookingHooks.onInited, {
434
+ status: this.store.status
435
+ });
436
+ this.logMethodSuccess("initialize", {
437
+ status: this.store.status
438
+ });
439
+ } catch (error) {
440
+ this.store.status = "error";
441
+ this.store.error = error instanceof Error ? error.message : "初始化失败";
442
+ console.error("[VenueBooking] 初始化失败", error);
443
+ this.logMethodError("initialize", error, {
444
+ status: this.store.status
445
+ });
446
+ throw error;
447
+ }
448
+ }
449
+ async destroy() {
450
+ this.logMethodStart("destroy");
451
+ this.clearLoginEffectListeners();
452
+ await this.core.effects.emit(import_types.VenueBookingHooks.onDestroy, {});
453
+ console.log("[VenueBooking] 已销毁");
454
+ this.logMethodSuccess("destroy");
455
+ }
456
+ async retryInit() {
457
+ this.logMethodStart("retryInit");
458
+ console.log("[VenueBooking] retryInit 调用");
459
+ await this.core.effects.emit(import_types.VenueBookingHooks.onRetryInit, {});
460
+ try {
461
+ await this.initialize(this.core, this.initializeOptions);
462
+ this.logMethodSuccess("retryInit");
463
+ } catch (error) {
464
+ this.logMethodError("retryInit", error);
465
+ throw error;
466
+ }
467
+ }
468
+ async refresh() {
469
+ this.logMethodStart("refresh");
470
+ console.log("[VenueBooking] refresh 调用");
471
+ try {
472
+ this.store.status = "initializing";
473
+ await this.loadRuntimeConfigs();
474
+ await this.refreshItemRuleQuantityLimits();
475
+ this.store.status = "ready";
476
+ await this.core.effects.emit(import_types.VenueBookingHooks.onRefresh, {
477
+ status: this.store.status
478
+ });
479
+ this.logMethodSuccess("refresh", {
480
+ status: this.store.status
481
+ });
482
+ } catch (error) {
483
+ this.logMethodError("refresh", error);
484
+ throw error;
485
+ }
486
+ }
487
+ // ─── 状态查询 ───
488
+ getStatus() {
489
+ return this.store.status;
490
+ }
491
+ getEntryContext() {
492
+ return this.store.entryContext;
493
+ }
494
+ getItemRuleQuantityLimits() {
495
+ return this.store.itemRuleQuantityLimits || [];
496
+ }
497
+ getCartValidationPassed() {
498
+ var _a;
499
+ return ((_a = this.store.cartValidation) == null ? void 0 : _a.passed) ?? null;
500
+ }
501
+ getCartValidation() {
502
+ return this.store.cartValidation || { passed: null, failures: [] };
503
+ }
504
+ // ─── 场地商品 & 附加商品 ───
505
+ async loadAllProducts() {
506
+ if (this.loadAllProductsInFlight)
507
+ return this.loadAllProductsInFlight;
508
+ this.loadAllProductsInFlight = this._doLoadAllProducts().finally(() => {
509
+ this.loadAllProductsInFlight = null;
510
+ });
511
+ return this.loadAllProductsInFlight;
512
+ }
513
+ async _doLoadAllProducts() {
514
+ var _a, _b, _c;
515
+ this.logMethodStart("loadAllProducts");
516
+ try {
517
+ if (!this.store.venueProducts)
518
+ throw new Error("venueProducts 模块未初始化");
519
+ if (!this.store.addonProducts)
520
+ throw new Error("addonProducts 模块未初始化");
521
+ const associatedMenus = ((_b = (_a = this.otherParams) == null ? void 0 : _a.openData) == null ? void 0 : _b["menu.associated_menus"]) || [];
522
+ if (!associatedMenus.length) {
523
+ throw new Error("未获取到餐牌配置(menu.associated_menus),请检查 OpenData 配置");
524
+ }
525
+ const menuListIds = associatedMenus.map((n) => Number(n.value));
526
+ const allProducts = await this.store.venueProducts.loadProducts({
527
+ menu_list_ids: menuListIds,
528
+ cacheId: this.cacheId,
529
+ schedule_date: (0, import_dayjs.default)().format("YYYY-MM-DD"),
530
+ schedule_datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
531
+ });
532
+ const list = Array.isArray(allProducts) ? allProducts : [];
533
+ const venueList = list.filter((p) => p.duration != null);
534
+ const addonList = list.filter((p) => p.duration == null);
535
+ const venueStore = (_c = this.store.venueProducts) == null ? void 0 : _c.store;
536
+ if (venueStore) {
537
+ venueStore.list = venueList.slice().sort((a, b) => Number(b.sort) - Number(a.sort));
538
+ }
539
+ this.store.addonProducts.addProduct(addonList);
540
+ this.resourceProductMap = (0, import_resource.buildResourceProductMap)(venueList);
541
+ this.productsLoaded = true;
542
+ this.logMethodSuccess("loadAllProducts", {
543
+ total: list.length,
544
+ venueCount: venueList.length,
545
+ addonCount: addonList.length,
546
+ resourceCount: this.resourceProductMap.size
547
+ });
548
+ return { venueProducts: venueList, addonProducts: addonList };
549
+ } catch (error) {
550
+ this.logMethodError("loadAllProducts", error);
551
+ throw error;
552
+ }
553
+ }
554
+ async loadVenueProducts() {
555
+ const result = await this.loadAllProducts();
556
+ return result.venueProducts;
557
+ }
558
+ async loadAddonProducts() {
559
+ const result = await this.loadAllProducts();
560
+ return result.addonProducts;
561
+ }
562
+ getVenueProducts() {
563
+ var _a, _b;
564
+ return ((_b = (_a = this.store.venueProducts) == null ? void 0 : _a.store) == null ? void 0 : _b.list) || [];
565
+ }
566
+ getAddonProductsList() {
567
+ var _a, _b;
568
+ return ((_b = (_a = this.store.addonProducts) == null ? void 0 : _a.store) == null ? void 0 : _b.list) || [];
569
+ }
570
+ // ─── 报价单 ───
571
+ async loadQuotations(params) {
572
+ this.logMethodStart("loadQuotations");
573
+ try {
574
+ if (!this.store.quotation)
575
+ throw new Error("quotation 模块未初始化");
576
+ await this.store.quotation.loadQuotations(params);
577
+ this.logMethodSuccess("loadQuotations", {
578
+ count: this.store.quotation.getQuotationList().length
579
+ });
580
+ } catch (error) {
581
+ this.logMethodError("loadQuotations", error);
582
+ throw error;
583
+ }
584
+ }
585
+ // ─── 资源可用性 ───
586
+ async fetchResourceAvailability(params) {
587
+ this.logMethodStart("fetchResourceAvailability", params);
588
+ try {
589
+ const venueProducts = this.getVenueProducts();
590
+ if (!venueProducts.length) {
591
+ this.store.rawResourceData = [];
592
+ this.logMethodSuccess("fetchResourceAvailability", { resourceCount: 0 });
593
+ return;
594
+ }
595
+ const resourceIds = (0, import_resource.extractResourceIds)(venueProducts);
596
+ if (!resourceIds.length) {
597
+ this.store.rawResourceData = [];
598
+ this.logMethodSuccess("fetchResourceAvailability", { resourceIds: [] });
599
+ return;
600
+ }
601
+ const config = this.store.slotConfig;
602
+ const crossDay = (0, import_timeSlot.isBusinessHoursCrossDay)(config);
603
+ const effectiveEndDate = crossDay ? (0, import_dayjs.default)(params.endDate).add(1, "day").format("YYYY-MM-DD") : params.endDate;
604
+ if (!this.store.date)
605
+ throw new Error("date 模块未初始化");
606
+ const res = await this.store.date.fetchResourceDates({
607
+ query: {
608
+ start_date: params.startDate,
609
+ end_date: effectiveEndDate,
610
+ resource_ids: resourceIds
611
+ },
612
+ useCache: false
613
+ });
614
+ const rawData = [];
615
+ if ((res == null ? void 0 : res.data) && Array.isArray(res.data)) {
616
+ for (const item of res.data) {
617
+ rawData.push({
618
+ resourceId: item.id,
619
+ formId: item.form_id,
620
+ times: Array.isArray(item.times) ? item.times : [],
621
+ ...item
622
+ });
623
+ }
624
+ }
625
+ this.store.rawResourceData = rawData;
626
+ for (const item of rawData) {
627
+ const mapping = this.resourceProductMap.get(item.resourceId);
628
+ if (mapping && item.main_field) {
629
+ mapping.resourceName = item.main_field;
630
+ }
631
+ if (mapping && item.resource_form_id) {
632
+ mapping.formId = item.resource_form_id;
633
+ }
634
+ }
635
+ this.logMethodSuccess("fetchResourceAvailability", {
636
+ resourceCount: rawData.length,
637
+ totalTimes: rawData.reduce((sum, r) => sum + r.times.length, 0)
638
+ });
639
+ } catch (error) {
640
+ this.store.rawResourceData = [];
641
+ this.logMethodError("fetchResourceAvailability", error);
642
+ throw error;
643
+ }
644
+ }
645
+ // ─── 日期概览 & 时间槽矩阵(纯计算,不发请求) ───
646
+ getDateRangeSummary(params) {
647
+ return (0, import_dateSummary.buildDateRangeSummary)({
648
+ startDate: params.startDate,
649
+ endDate: params.endDate,
650
+ config: this.store.slotConfig,
651
+ rawResources: this.store.rawResourceData,
652
+ resourceProductMap: this.resourceProductMap,
653
+ quotationModule: this.store.quotation
654
+ });
655
+ }
656
+ getTimeSlotGrid(date) {
657
+ let quotationPriceMap;
658
+ if (this.store.quotation) {
659
+ const productIds = [...new Set([...this.resourceProductMap.values()].map((m) => m.productId))];
660
+ const timeLabels = (0, import_timeSlot.generateTimeLabels)(this.store.slotConfig);
661
+ const timePoints = timeLabels.map((label) => `${date} ${label}`);
662
+ quotationPriceMap = this.store.quotation.buildProductPriceMap({ productIds, timePoints });
663
+ }
664
+ return (0, import_timeSlot.buildTimeSlotGrid)({
665
+ date,
666
+ config: this.store.slotConfig,
667
+ rawResources: this.store.rawResourceData,
668
+ resourceProductMap: this.resourceProductMap,
669
+ quotationPriceMap
670
+ });
671
+ }
672
+ // ─── 时间槽订单操作 ───
673
+ /**
674
+ * 切换单个时段的选中状态(选中/取消)。
675
+ * 内部自动处理连续时段的合并与拆分,订单是唯一真相源。
676
+ */
677
+ async toggleSlot(slot) {
678
+ this.logMethodStart("toggleSlot", {
679
+ resourceId: slot.resourceId,
680
+ startTime: slot.startTime
681
+ });
682
+ try {
683
+ const mapping = this.resourceProductMap.get(slot.resourceId);
684
+ if (!mapping)
685
+ throw new Error(`未找到资源 ${slot.resourceId} 的商品映射`);
686
+ if (!this.store.order)
687
+ throw new Error("order 模块未初始化");
688
+ const currentSlots = this.getSelectedSlotsForResource(slot.resourceId);
689
+ const existIndex = currentSlots.findIndex((s) => s.startTime === slot.startTime);
690
+ let nextSlots;
691
+ if (existIndex !== -1) {
692
+ nextSlots = currentSlots.filter((_, i) => i !== existIndex);
693
+ } else {
694
+ nextSlots = [...currentSlots, slot];
695
+ }
696
+ await this.reconcileOrderForResource(slot.resourceId, nextSlots);
697
+ const products = this.store.order.getOrderProducts();
698
+ await this.refreshItemRuleQuantityLimits();
699
+ await this.refreshCartValidationPassed();
700
+ this.logMethodSuccess("toggleSlot", {
701
+ action: existIndex !== -1 ? "remove" : "add",
702
+ resourceId: slot.resourceId,
703
+ slotCount: nextSlots.length
704
+ });
705
+ return products;
706
+ } catch (error) {
707
+ this.logMethodError("toggleSlot", error);
708
+ throw error;
709
+ }
710
+ }
711
+ /**
712
+ * 获取某资源当前选中的所有独立时段(从订单中解析)。
713
+ */
714
+ getSelectedSlotsForResource(resourceId) {
715
+ var _a;
716
+ const tempOrder = (_a = this.store.order) == null ? void 0 : _a.getTempOrder();
717
+ if (!tempOrder)
718
+ return [];
719
+ const venueProducts = tempOrder.products.filter(
720
+ (p) => {
721
+ var _a2, _b;
722
+ return ((_a2 = p.metadata) == null ? void 0 : _a2.venue_booking) && String((_b = p.metadata) == null ? void 0 : _b.resource_id) === String(resourceId);
723
+ }
724
+ );
725
+ const slotDuration = this.store.slotConfig.slotDurationMinutes;
726
+ const slots = [];
727
+ for (const product of venueProducts) {
728
+ slots.push(...(0, import_slotMerge.expandMergedSlotToIndividual)(product, slotDuration));
729
+ }
730
+ return slots.sort((a, b) => a.startTime.localeCompare(b.startTime));
731
+ }
732
+ /**
733
+ * 判断某个时段是否已选中。
734
+ */
735
+ isSlotSelected(resourceId, startTime) {
736
+ return this.getSelectedSlotsForResource(resourceId).some((s) => s.startTime === startTime);
737
+ }
738
+ /**
739
+ * 获取所有已选时段(按资源分组)。
740
+ */
741
+ getAllSelectedSlots() {
742
+ var _a, _b;
743
+ const result = /* @__PURE__ */ new Map();
744
+ const tempOrder = (_a = this.store.order) == null ? void 0 : _a.getTempOrder();
745
+ if (!tempOrder)
746
+ return result;
747
+ const venueProducts = tempOrder.products.filter((p) => {
748
+ var _a2;
749
+ return (_a2 = p.metadata) == null ? void 0 : _a2.venue_booking;
750
+ });
751
+ const slotDuration = this.store.slotConfig.slotDurationMinutes;
752
+ for (const product of venueProducts) {
753
+ const resourceId = (_b = product.metadata) == null ? void 0 : _b.resource_id;
754
+ if (resourceId == null)
755
+ continue;
756
+ const existing = result.get(resourceId) || [];
757
+ existing.push(...(0, import_slotMerge.expandMergedSlotToIndividual)(product, slotDuration));
758
+ result.set(resourceId, existing);
759
+ }
760
+ for (const [key, slots] of result) {
761
+ result.set(key, slots.sort((a, b) => a.startTime.localeCompare(b.startTime)));
762
+ }
763
+ return result;
764
+ }
765
+ /**
766
+ * 对指定资源的订单商品进行 reconcile:
767
+ * 清除旧商品 → 合并连续时段 → 重新写入。
768
+ */
769
+ async reconcileOrderForResource(resourceId, slots) {
770
+ const mapping = this.resourceProductMap.get(resourceId);
771
+ if (!mapping || !this.store.order)
772
+ return;
773
+ const tempOrder = this.store.order.ensureTempOrder();
774
+ tempOrder.products = tempOrder.products.filter(
775
+ (p) => {
776
+ var _a, _b;
777
+ return !(((_a = p.metadata) == null ? void 0 : _a.venue_booking) && String((_b = p.metadata) == null ? void 0 : _b.resource_id) === String(resourceId));
778
+ }
779
+ );
780
+ tempOrder.bookings = (tempOrder.bookings || []).filter(
781
+ (b) => {
782
+ var _a, _b;
783
+ return !(((_a = b.metadata) == null ? void 0 : _a.venue_booking) && String((_b = b.metadata) == null ? void 0 : _b.resource_id) === String(resourceId));
784
+ }
785
+ );
786
+ if (!slots.length) {
787
+ this.store.order.applyDiscount();
788
+ await this.store.order.recalculateSummary({ createIfMissing: true });
789
+ this.store.order.persistTempOrder();
790
+ return;
791
+ }
792
+ const merged = (0, import_slotMerge.mergeConsecutiveSlots)(slots);
793
+ const rawResource = this.store.rawResourceData.find(
794
+ (r) => String(r.resourceId) === String(resourceId)
795
+ );
796
+ const venueProduct = this.getVenueProducts().find((p) => p.id === mapping.productId);
797
+ tempOrder.bookings = tempOrder.bookings || [];
798
+ for (let i = 0; i < merged.length; i++) {
799
+ const group = merged[i];
800
+ const identityKey = (0, import_slotMerge.buildVenueIdentityKey)(resourceId, i);
801
+ const bookingUuid = (0, import_utils2.createUuidV4)();
802
+ const startMoment = (0, import_dayjs.default)(group.startTime, "YYYY-MM-DD HH:mm");
803
+ const endMoment = (0, import_dayjs.default)(group.endTime, "YYYY-MM-DD HH:mm");
804
+ const duration = endMoment.diff(startMoment, "minute");
805
+ const customDepositData = cloneCustomDepositData(venueProduct == null ? void 0 : venueProduct.custom_deposit_data);
806
+ tempOrder.products.push(
807
+ (0, import_utils.normalizeOrderProduct)({
808
+ product_id: mapping.productId,
809
+ product_variant_id: 0,
810
+ identity_key: identityKey,
811
+ num: 1,
812
+ selling_price: group.totalPrice,
813
+ original_price: group.totalPrice,
814
+ payment_price: group.totalPrice,
815
+ is_charge_tax: (venueProduct == null ? void 0 : venueProduct.is_charge_tax) ?? 0,
816
+ metadata: {
817
+ venue_booking: true,
818
+ resource_id: resourceId,
819
+ resource_form_id: mapping.formId,
820
+ resource_name: mapping.resourceName,
821
+ start_time: group.startTime,
822
+ end_time: group.endTime,
823
+ slot_count: group.slotCount,
824
+ booking_uid: bookingUuid,
825
+ price_breakdown: (0, import_slotMerge.buildPriceBreakdown)({
826
+ group,
827
+ productId: mapping.productId,
828
+ quotation: this.store.quotation
829
+ })
830
+ },
831
+ _origin: {
832
+ name: mapping.productTitle,
833
+ cover: (venueProduct == null ? void 0 : venueProduct.cover) || "",
834
+ custom_deposit_data: customDepositData,
835
+ id: 0,
836
+ number: 1,
837
+ registration_type: "all",
838
+ relation_products: [],
839
+ is_all: false,
840
+ product: {
841
+ product_id: mapping.productId,
842
+ product_variant_id: 0,
843
+ num: 1,
844
+ product_bundle: [],
845
+ product_option_item: [],
846
+ discount_list: [],
847
+ custom_deposit_data: customDepositData,
848
+ metadata: {}
849
+ },
850
+ sub_type: "minutes",
851
+ duration,
852
+ like_status: "common",
853
+ resources: [{
854
+ relation_type: "form",
855
+ like_status: "common",
856
+ id: resourceId,
857
+ main_field: mapping.resourceName,
858
+ form_id: (rawResource == null ? void 0 : rawResource.form_id) ?? mapping.formId,
859
+ relation_id: resourceId,
860
+ capacity: 1,
861
+ metadata: {}
862
+ }],
863
+ schedule_id: 0,
864
+ select_date: startMoment.format("YYYY-MM-DD"),
865
+ start_date: startMoment.format("YYYY-MM-DD"),
866
+ start_time: startMoment.format("HH:mm"),
867
+ end_date: endMoment.format("YYYY-MM-DD"),
868
+ end_time: endMoment.format("HH:mm"),
869
+ metadata: {
870
+ venue_booking: true,
871
+ slot_count: group.slotCount
872
+ },
873
+ holder: null
874
+ }
875
+ })
876
+ );
877
+ const booking = (0, import_slotMerge.buildVenueBookingEntry)({
878
+ group,
879
+ resourceId,
880
+ mapping,
881
+ rawResource,
882
+ bookingUuid,
883
+ productUid: identityKey
884
+ });
885
+ tempOrder.bookings.push(booking);
886
+ }
887
+ this.store.order.applyDiscount();
888
+ await this.store.order.recalculateSummary({ createIfMissing: true });
889
+ this.store.order.persistTempOrder();
890
+ }
891
+ // ─── 配置 ───
892
+ setSlotConfig(config) {
893
+ this.store.slotConfig = {
894
+ ...this.store.slotConfig,
895
+ ...config
896
+ };
897
+ }
898
+ getSlotConfig() {
899
+ return { ...this.store.slotConfig };
900
+ }
901
+ // ─── 日程 ───
902
+ async loadSchedules() {
903
+ this.logMethodStart("loadSchedules");
904
+ try {
905
+ if (!this.store.schedule)
906
+ throw new Error("schedule 模块未初始化");
907
+ await this.store.schedule.loadAllSchedule();
908
+ this.injectScheduleResolverToQuotation();
909
+ this.logMethodSuccess("loadSchedules");
910
+ } catch (error) {
911
+ this.logMethodError("loadSchedules", error);
912
+ throw error;
913
+ }
914
+ }
915
+ injectScheduleResolverToQuotation() {
916
+ if (this.store.quotation && this.store.schedule) {
917
+ this.store.quotation.setScheduleResolver(
918
+ (id) => this.store.schedule.getScheduleListByIds([id])[0]
919
+ );
920
+ }
921
+ }
922
+ getScheduleListByIds(ids) {
923
+ if (!this.store.schedule)
924
+ return [];
925
+ return this.store.schedule.getScheduleListByIds(ids);
926
+ }
927
+ // ─── 临时订单操作(保留原有能力) ───
928
+ getTempOrder() {
929
+ var _a;
930
+ const result = ((_a = this.store.order) == null ? void 0 : _a.getTempOrder()) || null;
931
+ return result;
932
+ }
933
+ updateTempOrderNote(note) {
934
+ if (!this.store.order)
935
+ throw new Error("order 模块未初始化");
936
+ return this.store.order.updateTempOrderNote(note);
937
+ }
938
+ updateTempOrderContactsInfo(contactsInfo) {
939
+ if (!this.store.order)
940
+ throw new Error("order 模块未初始化");
941
+ return this.store.order.updateTempOrderContactsInfo(contactsInfo);
942
+ }
943
+ ensureTempOrder() {
944
+ if (!this.store.order)
945
+ throw new Error("order 模块未初始化");
946
+ return this.store.order.ensureTempOrder();
947
+ }
948
+ async onCustomerLogin(params) {
949
+ this.logMethodStart("onCustomerLogin", { customerId: params.customerId });
950
+ try {
951
+ await this.refreshOrderMarketingAfterLogin({
952
+ customerId: params.customerId
953
+ });
954
+ this.logMethodSuccess("onCustomerLogin", { customerId: params.customerId });
955
+ } catch (error) {
956
+ this.logMethodError("onCustomerLogin", error);
957
+ throw error;
958
+ }
959
+ }
960
+ recalculateOrderPricesFromQuotation() {
961
+ var _a, _b;
962
+ if (!this.store.order || !this.store.quotation)
963
+ return;
964
+ const tempOrder = this.store.order.getTempOrder();
965
+ if (!((_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.length))
966
+ return;
967
+ const now = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
968
+ for (const product of tempOrder.products) {
969
+ if ((_b = product.metadata) == null ? void 0 : _b.venue_booking) {
970
+ const mapping = this.resourceProductMap.get(product.metadata.resource_id);
971
+ if (!mapping)
972
+ continue;
973
+ const slots = (0, import_slotMerge.expandMergedSlotToIndividual)(
974
+ product,
975
+ this.store.slotConfig.slotDurationMinutes
976
+ );
977
+ const updatedSlots = slots.map((slot) => ({
978
+ ...slot,
979
+ price: this.store.quotation.getPriceForProduct({
980
+ productId: mapping.productId,
981
+ datetime: slot.startTime
982
+ }) ?? mapping.price
983
+ }));
984
+ const merged = (0, import_slotMerge.mergeConsecutiveSlots)(updatedSlots);
985
+ if (merged.length === 1) {
986
+ product.selling_price = merged[0].totalPrice;
987
+ product.payment_price = merged[0].totalPrice;
988
+ product.metadata.price_breakdown = (0, import_slotMerge.buildPriceBreakdown)({
989
+ group: merged[0],
990
+ productId: mapping.productId,
991
+ quotation: this.store.quotation
992
+ });
993
+ }
994
+ } else if (product.product_id != null) {
995
+ const quotationPrice = this.store.quotation.getPriceForProduct({
996
+ productId: product.product_id,
997
+ variantId: product.product_variant_id ?? void 0,
998
+ datetime: now
999
+ });
1000
+ if (quotationPrice !== null) {
1001
+ product.selling_price = quotationPrice;
1002
+ product.payment_price = quotationPrice;
1003
+ }
1004
+ }
1005
+ }
1006
+ }
1007
+ async scanCode(code, customerId) {
1008
+ this.logMethodStart("scanCode", { code });
1009
+ try {
1010
+ if (!this.store.order)
1011
+ throw new Error("order 模块未初始化");
1012
+ const result = await this.store.order.scanCode(code, customerId);
1013
+ if (result.isAvailable) {
1014
+ await this.store.order.recalculateSummary({ createIfMissing: true });
1015
+ this.store.order.persistTempOrder();
1016
+ }
1017
+ this.logMethodSuccess("scanCode", { isAvailable: result.isAvailable });
1018
+ return result;
1019
+ } catch (error) {
1020
+ this.logMethodError("scanCode", error);
1021
+ throw error;
1022
+ }
1023
+ }
1024
+ /** 获取当前折扣列表(包装 order.getDiscountList) */
1025
+ getDiscountList() {
1026
+ if (!this.store.order)
1027
+ return [];
1028
+ return this.store.order.getDiscountList();
1029
+ }
1030
+ /** 勾选/取消勾选某张折扣券,重新计算折扣并持久化 */
1031
+ async setDiscountSelected(params) {
1032
+ var _a, _b, _c, _d, _e, _f;
1033
+ this.logMethodStart("setDiscountSelected", params);
1034
+ try {
1035
+ if (!this.store.order)
1036
+ throw new Error("order 模块未初始化");
1037
+ const list = this.store.order.getDiscountList();
1038
+ const beforeTarget = list.find((d) => d.id === params.discountId) || null;
1039
+ const updated = list.map(
1040
+ (d) => d.id === params.discountId ? {
1041
+ ...d,
1042
+ isSelected: params.isSelected,
1043
+ isManualSelect: !params.isSelected
1044
+ } : d
1045
+ );
1046
+ const updatedTarget = updated.find((d) => d.id === params.discountId) || null;
1047
+ const tempOrder = this.store.order.ensureTempOrder();
1048
+ const orderStore = this.store.order.store || {};
1049
+ const discountModule = orderStore.discount;
1050
+ const rulesModule = orderStore.rules;
1051
+ const holders = ((_a = tempOrder.holder) == null ? void 0 : _a.form_record_id) ? [{ form_record_id: tempOrder.holder.form_record_id }] : [];
1052
+ let nextDiscountList = updated;
1053
+ await (discountModule == null ? void 0 : discountModule.setDiscountList(updated));
1054
+ if (rulesModule) {
1055
+ const result = rulesModule.calcDiscount(
1056
+ {
1057
+ productList: tempOrder.products,
1058
+ discountList: updated,
1059
+ holders,
1060
+ isFormSubject: !!((_b = tempOrder.holder) == null ? void 0 : _b.type) && tempOrder.holder.type === "form"
1061
+ },
1062
+ {
1063
+ discountId: params.discountId,
1064
+ isSelected: params.isSelected
1065
+ }
1066
+ ) || { productList: tempOrder.products, discountList: updated };
1067
+ if (result == null ? void 0 : result.productList) {
1068
+ tempOrder.products = result.productList;
1069
+ }
1070
+ if (result == null ? void 0 : result.discountList) {
1071
+ nextDiscountList = result.discountList;
1072
+ if (!params.isSelected) {
1073
+ const beforeSelectedIds = new Set(
1074
+ updated.filter((d) => d.isSelected).map((d) => d.id)
1075
+ );
1076
+ for (const d of nextDiscountList) {
1077
+ if (d.isSelected && !beforeSelectedIds.has(d.id)) {
1078
+ d.isSelected = false;
1079
+ }
1080
+ }
1081
+ }
1082
+ }
1083
+ }
1084
+ const selectedResourceIds = new Set(
1085
+ nextDiscountList.filter((d) => d.isSelected).map((d) => d.id)
1086
+ );
1087
+ for (const product of tempOrder.products) {
1088
+ if (!((_c = product.discount_list) == null ? void 0 : _c.length))
1089
+ continue;
1090
+ const before = product.discount_list.length;
1091
+ product.discount_list = product.discount_list.filter((pd) => {
1092
+ var _a2;
1093
+ const rid = ((_a2 = pd.discount) == null ? void 0 : _a2.resource_id) ?? pd.id;
1094
+ return rid != null && selectedResourceIds.has(rid);
1095
+ });
1096
+ if (product.discount_list.length < before) {
1097
+ const totalDiscountAmount = product.discount_list.reduce(
1098
+ (sum, pd) => sum + (pd.amount || 0),
1099
+ 0
1100
+ );
1101
+ const newPaymentPrice = new import_decimal.default(product.selling_price || 0).minus(totalDiscountAmount).toNumber();
1102
+ const paymentStr = (0, import_utils.toPriceString)(newPaymentPrice);
1103
+ product.payment_price = paymentStr;
1104
+ if (product.metadata) {
1105
+ product.metadata.main_product_selling_price = paymentStr;
1106
+ }
1107
+ }
1108
+ }
1109
+ import_Order.OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
1110
+ await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
1111
+ tempOrder.discount_list = (nextDiscountList || []).filter((d) => d.isSelected);
1112
+ const afterApplyTarget = this.store.order.getDiscountList().find((d) => d.id === params.discountId) || null;
1113
+ await this.store.order.recalculateSummary({ createIfMissing: true });
1114
+ this.store.order.persistTempOrder();
1115
+ const finalSummary = ((_d = this.store.order.getTempOrder()) == null ? void 0 : _d.summary) || null;
1116
+ const finalProduct = ((_f = (_e = this.store.order.getTempOrder()) == null ? void 0 : _e.products) == null ? void 0 : _f[0]) || null;
1117
+ this.logMethodSuccess("setDiscountSelected", params);
1118
+ const finalTarget = this.store.order.getDiscountList().find((d) => d.id === params.discountId) || null;
1119
+ return this.store.order.getDiscountList();
1120
+ } catch (error) {
1121
+ this.logMethodError("setDiscountSelected", error);
1122
+ throw error;
1123
+ }
1124
+ }
1125
+ async addNewOrder() {
1126
+ this.logMethodStart("addNewOrder");
1127
+ try {
1128
+ if (!this.store.order)
1129
+ throw new Error("order 模块未初始化");
1130
+ const tempOrder = await this.store.order.addNewOrder();
1131
+ this.logMethodSuccess("addNewOrder", {
1132
+ productCount: tempOrder.products.length
1133
+ });
1134
+ return tempOrder;
1135
+ } catch (error) {
1136
+ this.logMethodError("addNewOrder", error);
1137
+ throw error;
1138
+ }
1139
+ }
1140
+ getOrderProducts() {
1141
+ if (!this.store.order)
1142
+ throw new Error("order 模块未初始化");
1143
+ return this.store.order.getOrderProducts();
1144
+ }
1145
+ async getSummary() {
1146
+ this.logMethodStart("getSummary");
1147
+ try {
1148
+ if (!this.store.order)
1149
+ throw new Error("order 模块未初始化");
1150
+ const summary = await this.store.order.getScanOrderSummary();
1151
+ this.logMethodSuccess("getSummary", {
1152
+ totalAmount: summary.total_amount
1153
+ });
1154
+ return summary;
1155
+ } catch (error) {
1156
+ this.logMethodError("getSummary", error);
1157
+ throw error;
1158
+ }
1159
+ }
1160
+ async submitOrder() {
1161
+ var _a;
1162
+ this.logMethodStart("submitOrder");
1163
+ try {
1164
+ await this.validateBeforeSubmitByItemRule();
1165
+ if (!this.store.order) {
1166
+ throw new Error("venueBooking解决方案需要 order 模块支持");
1167
+ }
1168
+ const result = await this.store.order.submitTempOrder({
1169
+ cacheId: this.cacheId
1170
+ });
1171
+ const tempOrder = this.store.order.getTempOrder();
1172
+ this.logMethodSuccess("submitOrder", {
1173
+ productCount: ((_a = tempOrder == null ? void 0 : tempOrder.products) == null ? void 0 : _a.length) || 0
1174
+ });
1175
+ return result;
1176
+ } catch (error) {
1177
+ this.logMethodError("submitOrder", error);
1178
+ throw error;
1179
+ }
1180
+ }
1181
+ async addProductToOrder(product) {
1182
+ var _a;
1183
+ this.logMethodStart("addProductToOrder", {
1184
+ product_id: product.product_id,
1185
+ product_variant_id: product.product_variant_id
1186
+ });
1187
+ try {
1188
+ if (!this.store.order)
1189
+ throw new Error("order 模块未初始化");
1190
+ if (!((_a = product.metadata) == null ? void 0 : _a.venue_booking) && this.store.quotation && product.product_id != null) {
1191
+ const quotationPrice = this.store.quotation.getPriceForProduct({
1192
+ productId: product.product_id,
1193
+ variantId: product.product_variant_id ?? void 0,
1194
+ datetime: (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss")
1195
+ });
1196
+ if (quotationPrice !== null) {
1197
+ product.selling_price = quotationPrice;
1198
+ if (product.original_price == null) {
1199
+ product.original_price = quotationPrice;
1200
+ }
1201
+ product.payment_price = quotationPrice;
1202
+ }
1203
+ }
1204
+ const products = await this.store.order.addProductToOrder(product);
1205
+ await this.refreshItemRuleQuantityLimits();
1206
+ await this.refreshCartValidationPassed();
1207
+ this.logMethodSuccess("addProductToOrder", {
1208
+ productCount: products.length
1209
+ });
1210
+ return products;
1211
+ } catch (error) {
1212
+ this.logMethodError("addProductToOrder", error);
1213
+ throw error;
1214
+ }
1215
+ }
1216
+ async updateProductInOrder(params) {
1217
+ this.logMethodStart("updateProductInOrder", {
1218
+ product_id: params.product_id,
1219
+ product_variant_id: params.product_variant_id
1220
+ });
1221
+ try {
1222
+ if (!this.store.order)
1223
+ throw new Error("order 模块未初始化");
1224
+ const products = await this.store.order.updateProductInOrder(params);
1225
+ await this.refreshItemRuleQuantityLimits();
1226
+ await this.refreshCartValidationPassed();
1227
+ this.logMethodSuccess("updateProductInOrder", {
1228
+ productCount: products.length
1229
+ });
1230
+ return products;
1231
+ } catch (error) {
1232
+ this.logMethodError("updateProductInOrder", error);
1233
+ throw error;
1234
+ }
1235
+ }
1236
+ async removeProductFromOrder(identity) {
1237
+ this.logMethodStart("removeProductFromOrder", {
1238
+ product_id: identity.product_id,
1239
+ product_variant_id: identity.product_variant_id
1240
+ });
1241
+ try {
1242
+ if (!this.store.order)
1243
+ throw new Error("order 模块未初始化");
1244
+ const products = await this.store.order.removeProductFromOrder(identity);
1245
+ await this.refreshItemRuleQuantityLimits();
1246
+ await this.refreshCartValidationPassed();
1247
+ this.logMethodSuccess("removeProductFromOrder", {
1248
+ productCount: products.length
1249
+ });
1250
+ return products;
1251
+ } catch (error) {
1252
+ this.logMethodError("removeProductFromOrder", error);
1253
+ throw error;
1254
+ }
1255
+ }
1256
+ async getProductList() {
1257
+ if (this.productsLoaded) {
1258
+ return (0, import_utils.attachItemRuleLimitsToTopLevelProducts)(
1259
+ this.getAddonProductsList(),
1260
+ this.store.itemRuleQuantityLimits || []
1261
+ );
1262
+ }
1263
+ const result = await this.loadAllProducts();
1264
+ return (0, import_utils.attachItemRuleLimitsToTopLevelProducts)(
1265
+ result.addonProducts,
1266
+ this.store.itemRuleQuantityLimits || []
1267
+ );
1268
+ }
1269
+ // ─── ItemRule 引擎 ───
1270
+ async loadOpenDataConfig() {
1271
+ if (!this.store.openData)
1272
+ throw new Error("openData 模块未初始化");
1273
+ const lastFetchedAt = this.store.openData.getLastFetchedAt();
1274
+ const cachedData = this.store.openData.getOpenData();
1275
+ if (cachedData && lastFetchedAt && Date.now() - lastFetchedAt < _VenueBookingImpl.OPEN_DATA_CACHE_TTL) {
1276
+ this.otherParams.openData = cachedData;
1277
+ return cachedData;
1278
+ }
1279
+ if (this.loadOpenDataConfigInFlight)
1280
+ return this.loadOpenDataConfigInFlight;
1281
+ this.loadOpenDataConfigInFlight = this.store.openData.fetchOpenData({
1282
+ scope: "board",
1283
+ target: "venue_booking+online_store",
1284
+ section_code: [...OPEN_DATA_SECTION_CODES]
1285
+ }).then((openDataConfig) => {
1286
+ this.otherParams.openData = openDataConfig;
1287
+ return openDataConfig;
1288
+ }).finally(() => {
1289
+ this.loadOpenDataConfigInFlight = null;
1290
+ });
1291
+ return this.loadOpenDataConfigInFlight;
1292
+ }
1293
+ async loadRuntimeConfigs() {
1294
+ await this.loadOpenDataConfig();
1295
+ const itemRuleConfigs = await this.ensureItemRuleConfigsLoaded();
1296
+ this.logMethodSuccess("loadRuntimeConfigs", {
1297
+ itemRuleCount: itemRuleConfigs.length
1298
+ });
1299
+ return { itemRuleConfigs };
1300
+ }
1301
+ async fetchItemRuleConfigsByModelIds(strategyModelIds) {
1302
+ this.logMethodStart("fetchItemRuleConfigsByModelIds", { strategyModelIds });
1303
+ if (!strategyModelIds.length)
1304
+ return [];
1305
+ try {
1306
+ const result = await this.request.get("/promotion", {
1307
+ skip: 1,
1308
+ num: 99,
1309
+ status: "active",
1310
+ ids: strategyModelIds
1311
+ });
1312
+ let configs = [];
1313
+ if (result.code === 200) {
1314
+ configs = result.data.list.map((item) => item.metadata);
1315
+ }
1316
+ this.logMethodSuccess("fetchItemRuleConfigsByModelIds", {
1317
+ strategyModelIds,
1318
+ strategyCount: configs.length
1319
+ });
1320
+ return configs;
1321
+ } catch (error) {
1322
+ this.logMethodError("fetchItemRuleConfigsByModelIds", error, { strategyModelIds });
1323
+ return [];
1324
+ }
1325
+ }
1326
+ async buildPrefillProductSourceMap() {
1327
+ const sourceMap = /* @__PURE__ */ new Map();
1328
+ try {
1329
+ const productList = await this.getProductList();
1330
+ if (!Array.isArray(productList))
1331
+ return sourceMap;
1332
+ const visited = /* @__PURE__ */ new Set();
1333
+ const collectFromValue = (value) => {
1334
+ if (!value || typeof value !== "object")
1335
+ return;
1336
+ if (visited.has(value))
1337
+ return;
1338
+ visited.add(value);
1339
+ if (Array.isArray(value)) {
1340
+ for (const item of value)
1341
+ collectFromValue(item);
1342
+ return;
1343
+ }
1344
+ const node = value;
1345
+ const rawProductId = node.product_id ?? node.id;
1346
+ const productId = Number(rawProductId);
1347
+ if (Number.isFinite(productId) && productId > 0) {
1348
+ const productVariantId = Number(node.product_variant_id ?? node.variant_id ?? 0);
1349
+ const normalizedVariantId = Number.isNaN(productVariantId) ? 0 : productVariantId;
1350
+ const key = (0, import_utils.buildProductKey)(productId, normalizedVariantId);
1351
+ if (!sourceMap.has(key))
1352
+ sourceMap.set(key, node);
1353
+ }
1354
+ for (const childValue of Object.values(node)) {
1355
+ if (childValue && typeof childValue === "object")
1356
+ collectFromValue(childValue);
1357
+ }
1358
+ };
1359
+ collectFromValue(productList);
1360
+ } catch (error) {
1361
+ this.logMethodError("buildPrefillProductSourceMap", error);
1362
+ }
1363
+ return sourceMap;
1364
+ }
1365
+ getItemRuleRuntimeConfig() {
1366
+ return this.itemRuleRuntimeConfig || {};
1367
+ }
1368
+ async ensureItemRuleConfigsLoaded() {
1369
+ if (this.itemRuleConfigs.length > 0)
1370
+ return this.itemRuleConfigs;
1371
+ if (this.itemRuleConfigsPromise)
1372
+ return this.itemRuleConfigsPromise;
1373
+ this.itemRuleConfigsPromise = (async () => {
1374
+ const runtimeConfig = this.getItemRuleRuntimeConfig();
1375
+ const staticConfigs = (0, import_utils.normalizeItemRuleStrategies)(runtimeConfig.strategyConfigs);
1376
+ if (staticConfigs.length > 0) {
1377
+ this.itemRuleConfigs = staticConfigs;
1378
+ this.itemRuleEvaluator.setStrategyConfigs(staticConfigs);
1379
+ return this.itemRuleConfigs;
1380
+ }
1381
+ this.itemRuleConfigs = [];
1382
+ this.itemRuleEvaluator.setStrategyConfigs([]);
1383
+ return this.itemRuleConfigs;
1384
+ })();
1385
+ return await this.itemRuleConfigsPromise;
1386
+ }
1387
+ async refreshItemRuleQuantityLimits() {
1388
+ try {
1389
+ const strategyConfigs = await this.ensureItemRuleConfigsLoaded();
1390
+ if (!strategyConfigs.length) {
1391
+ this.store.itemRuleQuantityLimits = [];
1392
+ return [];
1393
+ }
1394
+ const businessData = (0, import_utils.buildItemRuleBusinessData)({
1395
+ tempOrder: this.ensureTempOrder(),
1396
+ runtimeConfig: this.getItemRuleRuntimeConfig(),
1397
+ itemRuleConfigs: this.itemRuleConfigs
1398
+ });
1399
+ const limits = this.itemRuleEvaluator.getQuantityLimits(businessData);
1400
+ this.store.itemRuleQuantityLimits = limits;
1401
+ this.logMethodSuccess("refreshItemRuleQuantityLimits", { limitCount: limits.length });
1402
+ return limits;
1403
+ } catch (error) {
1404
+ this.store.itemRuleQuantityLimits = [];
1405
+ this.logMethodError("refreshItemRuleQuantityLimits", error);
1406
+ return [];
1407
+ }
1408
+ }
1409
+ async applyPrefillByItemRule() {
1410
+ var _a;
1411
+ if (this.itemRulePrefillApplied)
1412
+ return;
1413
+ if (!this.store.order)
1414
+ return;
1415
+ const strategyConfigs = await this.ensureItemRuleConfigsLoaded();
1416
+ if (!strategyConfigs.length)
1417
+ return;
1418
+ const businessData = (0, import_utils.buildItemRuleBusinessData)({
1419
+ tempOrder: this.ensureTempOrder(),
1420
+ runtimeConfig: this.getItemRuleRuntimeConfig(),
1421
+ itemRuleConfigs: this.itemRuleConfigs
1422
+ });
1423
+ const prefillItems = this.itemRuleEvaluator.getPrefillItems(businessData);
1424
+ if (!prefillItems.length) {
1425
+ this.itemRulePrefillApplied = true;
1426
+ return;
1427
+ }
1428
+ const productSourceMap = await this.buildPrefillProductSourceMap();
1429
+ const tempOrder = this.ensureTempOrder();
1430
+ let hasChanges = false;
1431
+ for (const prefillItem of prefillItems) {
1432
+ const productId = Number(prefillItem.product_id);
1433
+ const productVariantId = Number(prefillItem.product_variant_id ?? 0);
1434
+ const targetQuantity = (0, import_utils.toNonNegativeInt)(prefillItem.quantity);
1435
+ if (!Number.isFinite(productId) || targetQuantity <= 0)
1436
+ continue;
1437
+ if (Number.isNaN(productVariantId))
1438
+ continue;
1439
+ const sourceItem = productSourceMap.get((0, import_utils.buildProductKey)(productId, productVariantId)) || productSourceMap.get((0, import_utils.buildProductKey)(productId, 0)) || null;
1440
+ const productIndex = (0, import_utils.getProductIdentityIndex)(tempOrder.products, {
1441
+ product_id: productId,
1442
+ product_variant_id: productVariantId
1443
+ });
1444
+ if (productIndex === -1) {
1445
+ const sellingPrice = (0, import_utils.toPriceString)((sourceItem == null ? void 0 : sourceItem.price) ?? (sourceItem == null ? void 0 : sourceItem.selling_price), "0.00");
1446
+ const originalPrice = (0, import_utils.toPriceString)((sourceItem == null ? void 0 : sourceItem.original_price) ?? (sourceItem == null ? void 0 : sourceItem.price) ?? sellingPrice, sellingPrice);
1447
+ const paymentPrice = (0, import_utils.toPriceString)((sourceItem == null ? void 0 : sourceItem.payment_price) ?? (sourceItem == null ? void 0 : sourceItem.price) ?? sellingPrice, sellingPrice);
1448
+ tempOrder.products.push(
1449
+ (0, import_utils.normalizeOrderProduct)({
1450
+ product_id: productId,
1451
+ product_variant_id: productVariantId,
1452
+ num: targetQuantity,
1453
+ selling_price: sellingPrice,
1454
+ original_price: originalPrice,
1455
+ payment_price: paymentPrice,
1456
+ metadata: { item_rule_prefill: true, item_rule_id: prefillItem.ruleId },
1457
+ _origin: { ...sourceItem || {}, item_rule_prefill: true, item_rule_id: prefillItem.ruleId }
1458
+ })
1459
+ );
1460
+ hasChanges = true;
1461
+ continue;
1462
+ }
1463
+ const targetProduct = tempOrder.products[productIndex];
1464
+ const existedQuantity = (0, import_utils.toNonNegativeInt)(targetProduct.num);
1465
+ const delta = targetQuantity - existedQuantity;
1466
+ const nextProduct = {
1467
+ ...targetProduct,
1468
+ ...delta > 0 ? { num: (0, import_utils.getSafeProductNum)(existedQuantity + delta) } : {},
1469
+ metadata: { ...targetProduct.metadata || {}, item_rule_prefill: true, item_rule_id: prefillItem.ruleId },
1470
+ _origin: sourceItem ? { ...targetProduct._origin || {}, ...sourceItem } : targetProduct._origin
1471
+ };
1472
+ if (delta > 0 || Boolean(sourceItem && (!targetProduct._origin || ((_a = targetProduct._origin) == null ? void 0 : _a.price) !== (sourceItem == null ? void 0 : sourceItem.price)))) {
1473
+ tempOrder.products[productIndex] = nextProduct;
1474
+ hasChanges = true;
1475
+ }
1476
+ }
1477
+ if (hasChanges) {
1478
+ await this.store.order.recalculateSummary({ createIfMissing: true });
1479
+ this.store.order.persistTempOrder();
1480
+ }
1481
+ await this.refreshItemRuleQuantityLimits();
1482
+ this.itemRulePrefillApplied = true;
1483
+ this.logMethodSuccess("applyPrefillByItemRule", {
1484
+ prefillCount: prefillItems.length,
1485
+ hasChanges
1486
+ });
1487
+ }
1488
+ async applyItemRulePrefill() {
1489
+ this.logMethodStart("applyItemRulePrefill");
1490
+ await this.applyPrefillByItemRule();
1491
+ await this.refreshItemRuleQuantityLimits();
1492
+ await this.refreshCartValidationPassed();
1493
+ }
1494
+ async evaluateCartValidationByItemRule() {
1495
+ const strategyConfigs = await this.ensureItemRuleConfigsLoaded();
1496
+ if (!strategyConfigs.length)
1497
+ return { passed: true, failures: [] };
1498
+ const businessData = (0, import_utils.buildItemRuleBusinessData)({
1499
+ tempOrder: this.ensureTempOrder(),
1500
+ runtimeConfig: this.getItemRuleRuntimeConfig(),
1501
+ itemRuleConfigs: this.itemRuleConfigs
1502
+ });
1503
+ return this.itemRuleEvaluator.validateCart(businessData);
1504
+ }
1505
+ async validateBeforeSubmitByItemRule() {
1506
+ const validationResult = await this.evaluateCartValidationByItemRule();
1507
+ if (validationResult.passed)
1508
+ return;
1509
+ const firstFailure = validationResult.failures[0];
1510
+ const errorMessage = (firstFailure == null ? void 0 : firstFailure.validationMessage) || "当前购物车未满足商品规则,请调整后再提交";
1511
+ const error = new Error(String(errorMessage));
1512
+ error.failures = validationResult.failures;
1513
+ throw error;
1514
+ }
1515
+ async refreshCartValidationPassed() {
1516
+ const previous = this.store.cartValidation || { passed: null, failures: [] };
1517
+ let nextState = {
1518
+ passed: null,
1519
+ failures: []
1520
+ };
1521
+ try {
1522
+ const validationResult = await this.evaluateCartValidationByItemRule();
1523
+ nextState = {
1524
+ passed: validationResult.passed,
1525
+ failures: validationResult.failures || []
1526
+ };
1527
+ } catch {
1528
+ nextState = { passed: false, failures: [] };
1529
+ }
1530
+ this.store.cartValidation = nextState;
1531
+ const changed = previous.passed !== nextState.passed || previous.failures !== nextState.failures;
1532
+ if (changed) {
1533
+ await this.core.effects.emit(import_types.VenueBookingHooks.onCartValidationChanged, {
1534
+ cartValidation: nextState,
1535
+ cartValidationPassed: nextState.passed
1536
+ });
1537
+ }
1538
+ return nextState.passed;
1539
+ }
1540
+ async setItemRuleRuntimeConfig(config = {}) {
1541
+ var _a, _b;
1542
+ this.logMethodStart("setItemRuleRuntimeConfig");
1543
+ this.itemRuleRuntimeConfig = {
1544
+ ...this.itemRuleRuntimeConfig,
1545
+ ...config,
1546
+ pax: { ...((_a = this.itemRuleRuntimeConfig) == null ? void 0 : _a.pax) || {}, ...(config == null ? void 0 : config.pax) || {} },
1547
+ custom: { ...((_b = this.itemRuleRuntimeConfig) == null ? void 0 : _b.custom) || {}, ...(config == null ? void 0 : config.custom) || {} }
1548
+ };
1549
+ if ("strategyConfigs" in config) {
1550
+ this.itemRuleConfigs = [];
1551
+ this.itemRuleConfigsPromise = null;
1552
+ this.itemRuleEvaluator.setStrategyConfigs([]);
1553
+ }
1554
+ this.itemRulePrefillApplied = false;
1555
+ await this.refreshItemRuleQuantityLimits();
1556
+ await this.refreshCartValidationPassed();
1557
+ this.logMethodSuccess("setItemRuleRuntimeConfig", {
1558
+ strategyCount: Array.isArray(this.itemRuleRuntimeConfig.strategyConfigs) ? this.itemRuleRuntimeConfig.strategyConfigs.length : 0
1559
+ });
1560
+ }
1561
+ getOtherParams() {
1562
+ return this.otherParams;
1563
+ }
1564
+ // ─── OpenData 可用性 ───
1565
+ async checkOpenDataAvailability() {
1566
+ if (!this.store.openData)
1567
+ throw new Error("openData 模块未初始化");
1568
+ await this.loadOpenDataConfig();
1569
+ return this.store.openData.checkAvailability(this.store.schedule);
1570
+ }
1571
+ };
1572
+ var VenueBookingImpl = _VenueBookingImpl;
1573
+ VenueBookingImpl.OPEN_DATA_CACHE_TTL = 5 * 60 * 1e3;
1574
+ // Annotate the CommonJS export names for ESM import in node:
1575
+ 0 && (module.exports = {
1576
+ VenueBookingImpl,
1577
+ ...require("./types")
1578
+ });