@pisell/pisellos 2.2.301 → 2.2.303

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 (152) hide show
  1. package/dist/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  2. package/dist/model/strategy/adapter/dataVariant/evaluator.js +287 -101
  3. package/dist/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  4. package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  5. package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
  6. package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  7. package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
  8. package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
  9. package/dist/model/strategy/adapter/itemRule/type.js +19 -1
  10. package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +10 -7
  11. package/dist/modules/Discount/index.d.ts +2 -0
  12. package/dist/modules/Discount/index.js +41 -5
  13. package/dist/modules/Discount/types.d.ts +21 -0
  14. package/dist/modules/OpenData/index.d.ts +15 -2
  15. package/dist/modules/OpenData/index.js +307 -19
  16. package/dist/modules/OpenData/types.d.ts +55 -0
  17. package/dist/modules/OpenData/types.js +7 -1
  18. package/dist/modules/OpenData/utils.d.ts +21 -1
  19. package/dist/modules/OpenData/utils.js +138 -0
  20. package/dist/modules/Order/index.d.ts +50 -7
  21. package/dist/modules/Order/index.js +1690 -815
  22. package/dist/modules/Order/salesNotes.d.ts +31 -0
  23. package/dist/modules/Order/salesNotes.js +492 -0
  24. package/dist/modules/Order/types.d.ts +117 -10
  25. package/dist/modules/Order/types.js +6 -1
  26. package/dist/modules/Order/utils/virtualSettlement.d.ts +63 -0
  27. package/dist/modules/Order/utils/virtualSettlement.js +284 -0
  28. package/dist/modules/Order/utils.d.ts +5 -1
  29. package/dist/modules/Order/utils.js +138 -33
  30. package/dist/modules/Payment/walletpass.js +20 -21
  31. package/dist/modules/Product/types.d.ts +23 -0
  32. package/dist/modules/ProductList/index.d.ts +2 -1
  33. package/dist/modules/ProductList/index.js +100 -20
  34. package/dist/modules/ProductList/types.d.ts +10 -0
  35. package/dist/modules/Rules/index.d.ts +5 -0
  36. package/dist/modules/Rules/index.js +30 -14
  37. package/dist/modules/SalesSummary/index.d.ts +1 -0
  38. package/dist/modules/SalesSummary/index.js +4 -3
  39. package/dist/modules/SalesSummary/types.d.ts +1 -0
  40. package/dist/modules/SalesSummary/utils.d.ts +1 -0
  41. package/dist/modules/SalesSummary/utils.js +21 -1
  42. package/dist/plugins/request.d.ts +2 -1
  43. package/dist/plugins/request.js +4 -2
  44. package/dist/server/index.d.ts +21 -0
  45. package/dist/server/index.js +1774 -1285
  46. package/dist/server/modules/order/types.d.ts +50 -0
  47. package/dist/server/modules/order/types.js +2 -0
  48. package/dist/server/utils/small-ticket.d.ts +4 -1
  49. package/dist/server/utils/small-ticket.js +461 -96
  50. package/dist/solution/BaseSales/index.d.ts +26 -3
  51. package/dist/solution/BaseSales/index.js +1492 -873
  52. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
  53. package/dist/solution/BaseSales/utils/parseSalesResponse.js +1 -1
  54. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  55. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +72 -9
  56. package/dist/solution/BookingByStep/index.d.ts +1 -1
  57. package/dist/solution/BookingTicket/index.d.ts +8 -3
  58. package/dist/solution/BookingTicket/index.js +558 -443
  59. package/dist/solution/BookingTicket/utils/addProductDecision.js +2 -1
  60. package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
  61. package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
  62. package/dist/solution/RegisterAndLogin/config.js +95 -40
  63. package/dist/solution/RegisterAndLogin/index.js +4 -1
  64. package/dist/solution/Sales/index.d.ts +16 -1
  65. package/dist/solution/Sales/index.js +338 -63
  66. package/dist/solution/Sales/types.d.ts +10 -0
  67. package/dist/solution/ScanOrder/index.d.ts +1 -0
  68. package/dist/solution/ScanOrder/index.js +31 -27
  69. package/dist/solution/ScanOrder/utils.d.ts +1 -0
  70. package/dist/solution/ScanOrder/utils.js +2 -0
  71. package/dist/solution/UnifiedBookingSales/index.d.ts +20 -6
  72. package/dist/solution/UnifiedBookingSales/index.js +874 -527
  73. package/dist/solution/UnifiedBookingSales/types.d.ts +21 -2
  74. package/dist/solution/VenueBooking/index.d.ts +1 -0
  75. package/dist/solution/VenueBooking/index.js +8 -4
  76. package/lib/model/strategy/adapter/dataVariant/evaluator.d.ts +18 -2
  77. package/lib/model/strategy/adapter/dataVariant/evaluator.js +137 -6
  78. package/lib/model/strategy/adapter/dataVariant/type.d.ts +25 -0
  79. package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
  80. package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
  81. package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
  82. package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
  83. package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
  84. package/lib/model/strategy/adapter/itemRule/type.js +19 -1
  85. package/lib/model/strategy/adapter/promotion/index.js +1 -46
  86. package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +4 -0
  87. package/lib/modules/Discount/index.d.ts +2 -0
  88. package/lib/modules/Discount/index.js +34 -2
  89. package/lib/modules/Discount/types.d.ts +21 -0
  90. package/lib/modules/OpenData/index.d.ts +15 -2
  91. package/lib/modules/OpenData/index.js +230 -3
  92. package/lib/modules/OpenData/types.d.ts +55 -0
  93. package/lib/modules/OpenData/types.js +9 -1
  94. package/lib/modules/OpenData/utils.d.ts +21 -1
  95. package/lib/modules/OpenData/utils.js +126 -0
  96. package/lib/modules/Order/index.d.ts +50 -7
  97. package/lib/modules/Order/index.js +704 -64
  98. package/lib/modules/Order/salesNotes.d.ts +31 -0
  99. package/lib/modules/Order/salesNotes.js +382 -0
  100. package/lib/modules/Order/types.d.ts +117 -10
  101. package/lib/modules/Order/types.js +5 -1
  102. package/lib/modules/Order/utils/virtualSettlement.d.ts +63 -0
  103. package/lib/modules/Order/utils/virtualSettlement.js +262 -0
  104. package/lib/modules/Order/utils.d.ts +5 -1
  105. package/lib/modules/Order/utils.js +127 -21
  106. package/lib/modules/Payment/walletpass.js +14 -11
  107. package/lib/modules/Product/types.d.ts +23 -0
  108. package/lib/modules/ProductList/index.d.ts +2 -1
  109. package/lib/modules/ProductList/index.js +47 -2
  110. package/lib/modules/ProductList/types.d.ts +10 -0
  111. package/lib/modules/Rules/index.d.ts +5 -0
  112. package/lib/modules/Rules/index.js +22 -12
  113. package/lib/modules/SalesSummary/index.d.ts +1 -0
  114. package/lib/modules/SalesSummary/index.js +4 -2
  115. package/lib/modules/SalesSummary/types.d.ts +1 -0
  116. package/lib/modules/SalesSummary/utils.d.ts +1 -0
  117. package/lib/modules/SalesSummary/utils.js +17 -1
  118. package/lib/plugins/request.d.ts +2 -1
  119. package/lib/plugins/request.js +3 -2
  120. package/lib/server/index.d.ts +21 -0
  121. package/lib/server/index.js +492 -108
  122. package/lib/server/modules/order/types.d.ts +50 -0
  123. package/lib/server/modules/order/types.js +1 -0
  124. package/lib/server/utils/small-ticket.d.ts +4 -1
  125. package/lib/server/utils/small-ticket.js +427 -72
  126. package/lib/solution/BaseSales/index.d.ts +26 -3
  127. package/lib/solution/BaseSales/index.js +439 -30
  128. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +2 -0
  129. package/lib/solution/BaseSales/utils/parseSalesResponse.js +1 -1
  130. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.d.ts +1 -0
  131. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +38 -0
  132. package/lib/solution/BookingByStep/index.d.ts +1 -1
  133. package/lib/solution/BookingTicket/index.d.ts +8 -3
  134. package/lib/solution/BookingTicket/index.js +60 -15
  135. package/lib/solution/BookingTicket/utils/addProductDecision.js +1 -0
  136. package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
  137. package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
  138. package/lib/solution/RegisterAndLogin/config.js +49 -8
  139. package/lib/solution/RegisterAndLogin/index.js +4 -1
  140. package/lib/solution/Sales/index.d.ts +16 -1
  141. package/lib/solution/Sales/index.js +168 -1
  142. package/lib/solution/Sales/types.d.ts +10 -0
  143. package/lib/solution/ScanOrder/index.d.ts +1 -0
  144. package/lib/solution/ScanOrder/index.js +5 -1
  145. package/lib/solution/ScanOrder/utils.d.ts +1 -0
  146. package/lib/solution/ScanOrder/utils.js +1 -0
  147. package/lib/solution/UnifiedBookingSales/index.d.ts +20 -6
  148. package/lib/solution/UnifiedBookingSales/index.js +169 -16
  149. package/lib/solution/UnifiedBookingSales/types.d.ts +21 -2
  150. package/lib/solution/VenueBooking/index.d.ts +1 -0
  151. package/lib/solution/VenueBooking/index.js +5 -1
  152. package/package.json +1 -1
@@ -4,6 +4,8 @@ export declare const ITEM_RULE_ACTION_TYPES: {
4
4
  readonly QUANTITY_CHECK: "QUANTITY_CHECK";
5
5
  /** 预填购物车 */
6
6
  readonly PREFILL_CART: "PREFILL_CART";
7
+ /** 加购前过敏信息确认 */
8
+ readonly ALLERGY_CHECK: "ALLERGY_CHECK";
7
9
  };
8
10
  export type ItemRuleActionType = (typeof ITEM_RULE_ACTION_TYPES)[keyof typeof ITEM_RULE_ACTION_TYPES];
9
11
  export declare const ITEM_RULE_TEMPLATES: {
@@ -63,6 +65,42 @@ export interface TargetItem {
63
65
  /** 变体 ID */
64
66
  product_variant_id?: number;
65
67
  }
68
+ /** 策略展示文案,可由调用方按当前 locale 解析。 */
69
+ export type ItemRuleLocalizedText = string | Record<string, string>;
70
+ /** 内联过敏源选项。稳定 id 用于保存选择,label 只负责展示。 */
71
+ export interface AllergyDataSourceItem {
72
+ id: string;
73
+ label: ItemRuleLocalizedText;
74
+ }
75
+ /** 当前仅支持随策略下发的内联过敏源。 */
76
+ export interface AllergyDataSource {
77
+ type: 'inline';
78
+ items: AllergyDataSourceItem[];
79
+ }
80
+ /** 每个目标商品独立持有自己的过敏源,禁止跨商品合并。 */
81
+ export interface AllergyTargetItem extends TargetItem {
82
+ dataSource: AllergyDataSource;
83
+ }
84
+ export type AllergyPromptScope = 'once_per_order_product';
85
+ /** ALLERGY_CHECK Action 的商品级配置。 */
86
+ export interface AllergyCheckConfig {
87
+ targetType: 'product';
88
+ targets: AllergyTargetItem[];
89
+ promptScope: AllergyPromptScope;
90
+ allowNote?: boolean;
91
+ }
92
+ /** 当前商品命中的单条过敏门禁要求。 */
93
+ export interface AllergyRequirement {
94
+ strategyId: string;
95
+ ruleId: string;
96
+ priority: number;
97
+ targetType: 'product';
98
+ product_id: number;
99
+ product_variant_id?: number;
100
+ dataSource: AllergyDataSource;
101
+ promptScope: AllergyPromptScope;
102
+ allowNote: boolean;
103
+ }
66
104
  /**
67
105
  * 预填商品项
68
106
  */
@@ -119,6 +157,10 @@ export interface ItemRuleBusinessData {
119
157
  historicalItems?: CartItemSummary[];
120
158
  /** 服务类型(如 'dine-in', 'takeaway') */
121
159
  serviceType?: string;
160
+ /** 当前业务渠道(如 'kiosk', 'pos', 'online_store') */
161
+ channel?: string;
162
+ /** 当前正在加入购物车的商品;ALLERGY_CHECK 只读取该商品的 Target。 */
163
+ currentProduct?: Pick<TargetItem, 'product_id' | 'product_variant_id'>;
122
164
  /** 当前提交次数(0=首次提交, >0=追加提交) */
123
165
  submissionIndex?: number;
124
166
  /** 策略配置列表(可选,如果不传则使用 setStrategyConfigs 设置的) */
@@ -216,6 +258,8 @@ export interface ItemRuleEvaluationResult {
216
258
  quantityChecks: QuantityCheckResult[];
217
259
  /** 需要预填的商品列表 */
218
260
  prefillItems: PrefillItemResult[];
261
+ /** 当前商品命中的过敏门禁要求;不同 Action/商品不会合并。 */
262
+ allergyRequirements: AllergyRequirement[];
219
263
  /** 所有校验是否全部通过 */
220
264
  allPassed: boolean;
221
265
  /** 未通过的校验列表 */
@@ -12,7 +12,9 @@ const ITEM_RULE_ACTION_TYPES = exports.ITEM_RULE_ACTION_TYPES = {
12
12
  /** 数量校验 */
13
13
  QUANTITY_CHECK: 'QUANTITY_CHECK',
14
14
  /** 预填购物车 */
15
- PREFILL_CART: 'PREFILL_CART'
15
+ PREFILL_CART: 'PREFILL_CART',
16
+ /** 加购前过敏信息确认 */
17
+ ALLERGY_CHECK: 'ALLERGY_CHECK'
16
18
  };
17
19
  // ============================================
18
20
  // Rule Template 类型(创建规则时的起始模板)
@@ -56,6 +58,22 @@ const ITEM_RULE_TEMPLATES = exports.ITEM_RULE_TEMPLATES = {
56
58
 
57
59
  /** 目标项 */
58
60
 
61
+ // ============================================
62
+ // Allergy Check 相关类型
63
+ // ============================================
64
+
65
+ /** 策略展示文案,可由调用方按当前 locale 解析。 */
66
+
67
+ /** 内联过敏源选项。稳定 id 用于保存选择,label 只负责展示。 */
68
+
69
+ /** 当前仅支持随策略下发的内联过敏源。 */
70
+
71
+ /** 每个目标商品独立持有自己的过敏源,禁止跨商品合并。 */
72
+
73
+ /** ALLERGY_CHECK Action 的商品级配置。 */
74
+
75
+ /** 当前商品命中的单条过敏门禁要求。 */
76
+
59
77
  // ============================================
60
78
  // Prefill Cart 相关类型
61
79
  // ============================================
@@ -1,46 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "BUY_X_GET_Y_FREE_STRATEGY", {
7
- enumerable: true,
8
- get: function () {
9
- return _examples.BUY_X_GET_Y_FREE_STRATEGY;
10
- }
11
- });
12
- Object.defineProperty(exports, "ITEM_REWARD_STRATEGY", {
13
- enumerable: true,
14
- get: function () {
15
- return _examples.ITEM_REWARD_STRATEGY;
16
- }
17
- });
18
- Object.defineProperty(exports, "PromotionAdapter", {
19
- enumerable: true,
20
- get: function () {
21
- return _adapter.PromotionAdapter;
22
- }
23
- });
24
- Object.defineProperty(exports, "PromotionEvaluator", {
25
- enumerable: true,
26
- get: function () {
27
- return _evaluator.PromotionEvaluator;
28
- }
29
- });
30
- Object.defineProperty(exports, "X_ITEMS_FOR_Y_PRICE_STRATEGY", {
31
- enumerable: true,
32
- get: function () {
33
- return _examples.X_ITEMS_FOR_Y_PRICE_STRATEGY;
34
- }
35
- });
36
- Object.defineProperty(exports, "default", {
37
- enumerable: true,
38
- get: function () {
39
- return _adapter.default;
40
- }
41
- });
42
- var _evaluator = require("./evaluator");
43
- var _adapter = _interopRequireWildcard(require("./adapter"));
44
- var _examples = require("./examples");
45
- function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
46
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
1
+ "use strict";
@@ -181,6 +181,7 @@ function buildCacheItemFromOrderLine(input) {
181
181
  booking,
182
182
  sourceProduct
183
183
  } = input;
184
+ const holderConfig = sourceProduct?.holder_config ?? sourceProduct?.origin?.holder_config ?? product.metadata?.holder_config;
184
185
  const resolvedId = product.product_id ?? sourceProduct?.id;
185
186
  const selling = Number(product.selling_price ?? 0);
186
187
  const original = Number(product.original_price ?? selling);
@@ -249,6 +250,9 @@ function buildCacheItemFromOrderLine(input) {
249
250
  }
250
251
  const base = {
251
252
  ...(sourceProduct || {}),
253
+ ...(holderConfig !== undefined && holderConfig !== null ? {
254
+ holder_config: holderConfig
255
+ } : {}),
252
256
  id: resolvedId,
253
257
  product_id: resolvedId,
254
258
  extension_type: sourceProduct?.extension_type ?? booking?.product?.extension_type ?? sourceProduct?.extension_type,
@@ -25,9 +25,11 @@ export declare class DiscountModule extends BaseModule implements Module, Discou
25
25
  with_wallet_pass_holder: 0 | 1;
26
26
  with_available_wallet_flag?: 0 | 1;
27
27
  with_available_wallet_pass_flag?: 0 | 1;
28
+ with_virtual_currency?: 0 | 1;
28
29
  request_timezone: string;
29
30
  order_id?: number | string;
30
31
  }): Promise<DiscountPrepareConfigResult>;
32
+ private normalizeVirtualCurrencyList;
31
33
  batchSearch(code: string, options?: {
32
34
  customerId?: number;
33
35
  orderId?: number;
@@ -80,21 +80,53 @@ class DiscountModule extends _BaseModule.BaseModule {
80
80
  const prepareConfig = await this.request.post(`/order/prepare/config`, {
81
81
  ...params,
82
82
  with_available_wallet_flag: params.with_available_wallet_flag ?? 1,
83
- with_available_wallet_pass_flag: params.with_available_wallet_pass_flag ?? 1
83
+ with_available_wallet_pass_flag: params.with_available_wallet_pass_flag ?? 1,
84
+ with_virtual_currency: params.with_virtual_currency ?? 1
84
85
  });
85
86
  const rawDiscountList = [...(prepareConfig?.data?.good_pass_list || []), ...(prepareConfig?.data?.discount_card_list || [])];
86
87
  const availableWalletList = [...(prepareConfig?.data?.avaiable_wallet_list || []), ...(prepareConfig?.data?.available_wallet_list || [])];
87
88
  const availableWalletPassList = prepareConfig?.data?.available_wallet_pass_list || [];
88
89
  const availableWalletIds = this.normalizePositiveNumberIds([...availableWalletList.map(item => item?.wallet_id), ...availableWalletPassList.map(item => item?.product_id)]);
90
+ const virtualCurrencyList = this.normalizeVirtualCurrencyList(prepareConfig?.data?.virtual_currency_list);
89
91
  const goodPassList = this.filterEnabledDiscountList(rawDiscountList) || [];
90
92
 
91
93
  // this.setDiscountList(goodPassList);
92
94
 
93
95
  return {
94
96
  discountList: goodPassList,
95
- availableWalletIds
97
+ availableWalletIds,
98
+ virtualCurrencyList,
99
+ availableWalletPassList: availableWalletPassList.map(item => ({
100
+ ...(item || {})
101
+ }))
96
102
  };
97
103
  }
104
+ normalizeVirtualCurrencyList(value) {
105
+ if (!Array.isArray(value)) return [];
106
+ return value.flatMap(item => {
107
+ const id = Number(item?.id);
108
+ const productId = Number(item?.product_id);
109
+ if (!Number.isFinite(id) || id <= 0 || !Number.isFinite(productId) || productId <= 0) {
110
+ return [];
111
+ }
112
+ const displayExtension = Array.isArray(item?.extension_data) ? item.extension_data.find(extension => extension?.field_key === 'virtual_currency_display') : undefined;
113
+ let display = displayExtension?.value;
114
+ if (typeof display === 'string') {
115
+ try {
116
+ display = JSON.parse(display);
117
+ } catch {
118
+ display = {};
119
+ }
120
+ }
121
+ return [{
122
+ ...item,
123
+ id,
124
+ product_id: productId,
125
+ balance: String(item?.balance ?? '0'),
126
+ virtual_currency_display: display && typeof display === 'object' && !Array.isArray(display) ? display : {}
127
+ }];
128
+ });
129
+ }
98
130
  async batchSearch(code, options) {
99
131
  const {
100
132
  customerId,
@@ -68,9 +68,30 @@ export interface DiscountWithReason {
68
68
  discountList: Discount[];
69
69
  unavailableReasonKey: DiscountFilterRejectKey | null;
70
70
  }
71
+ export interface WalletPassPrepareConfigItem {
72
+ id?: number | string | null;
73
+ tag?: string | null;
74
+ product_id?: number | string | null;
75
+ product_name?: string | null;
76
+ par_value?: string | number | null;
77
+ used_par_value?: string | number | null;
78
+ [key: string]: any;
79
+ }
71
80
  export interface DiscountPrepareConfigResult {
72
81
  discountList: Discount[];
73
82
  availableWalletIds: number[];
83
+ virtualCurrencyList?: VirtualCurrencyAsset[];
84
+ availableWalletPassList?: WalletPassPrepareConfigItem[];
85
+ }
86
+ export interface VirtualCurrencyAsset extends Record<string, any> {
87
+ id: number;
88
+ product_id: number;
89
+ balance: string;
90
+ product_name?: string;
91
+ format_title?: Record<string, any>;
92
+ code?: string;
93
+ encoded?: string;
94
+ virtual_currency_display?: Record<string, any>;
74
95
  }
75
96
  interface ExtensionData {
76
97
  id: number;
@@ -1,9 +1,9 @@
1
1
  import { Module, PisellCore, ModuleOptions } from '../../types';
2
2
  import { BaseModule } from '../BaseModule';
3
3
  import type { ScheduleModule } from '../Schedule';
4
- import type { OpenDataConfig, OpenDataFetchParams, OpenDataAvailabilityResult } from './types';
4
+ import type { OpenDataConfig, OpenDataFetchParams, OpenDataAvailabilityResult, InvoiceLayoutConfig, InvoiceTemplateSettings } from './types';
5
5
  export * from './types';
6
- export { computeAvailability } from './utils';
6
+ export { computeAvailability, getDefaultInvoiceLayoutConfig, getDefaultInvoiceTemplateSettings, normalizeInvoiceLayoutConfig, normalizeInvoiceLayoutFromTemplateSettings, normalizeInvoiceTemplateSettings, normalizeRawInvoiceTemplateSettings, resolveInvoiceReceiptLocales, } from './utils';
7
7
  export declare class OpenDataModule extends BaseModule implements Module {
8
8
  protected defaultName: string;
9
9
  protected defaultVersion: string;
@@ -15,6 +15,10 @@ export declare class OpenDataModule extends BaseModule implements Module {
15
15
  private openCache;
16
16
  private fatherModule;
17
17
  private otherParams;
18
+ private fetchRevision;
19
+ private invoiceTemplateCacheRevision;
20
+ private invoiceTemplateDocumentCache;
21
+ private invoiceTemplateDocumentInFlight;
18
22
  constructor(name?: string, version?: string);
19
23
  initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
20
24
  /**
@@ -24,8 +28,17 @@ export declare class OpenDataModule extends BaseModule implements Module {
24
28
  * openDataModule.updateOtherParams({ openCache: true, cacheId: 'cache-2' })
25
29
  */
26
30
  updateOtherParams(params: Record<string, any>): void;
31
+ private shouldSkipInvoiceTemplateDocument;
27
32
  fetchOpenData(params: OpenDataFetchParams): Promise<OpenDataConfig>;
28
33
  getOpenData(): OpenDataConfig | null;
34
+ getInvoiceLayoutConfig(): InvoiceLayoutConfig;
35
+ getInvoiceTemplateSettings(): InvoiceTemplateSettings;
36
+ ensureInvoiceTemplateSettings(target: string): Promise<InvoiceTemplateSettings>;
37
+ private commitInvoiceTemplateSettings;
38
+ private resolveInvoiceTemplateSettings;
39
+ private buildInvoiceTemplateCacheKey;
40
+ private fetchInvoiceTemplateDocument;
41
+ private logInvoiceTemplateDocumentFallback;
29
42
  getLastFetchedAt(): number | null;
30
43
  /** 清除内存与 sessionStorage 镜像中的 OpenData,供宿主切店时调用。 */
31
44
  clearCache(): void;
@@ -5,7 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  var _exportNames = {
7
7
  OpenDataModule: true,
8
- computeAvailability: true
8
+ computeAvailability: true,
9
+ getDefaultInvoiceLayoutConfig: true,
10
+ getDefaultInvoiceTemplateSettings: true,
11
+ normalizeInvoiceLayoutConfig: true,
12
+ normalizeInvoiceLayoutFromTemplateSettings: true,
13
+ normalizeInvoiceTemplateSettings: true,
14
+ normalizeRawInvoiceTemplateSettings: true,
15
+ resolveInvoiceReceiptLocales: true
9
16
  };
10
17
  exports.OpenDataModule = void 0;
11
18
  Object.defineProperty(exports, "computeAvailability", {
@@ -14,6 +21,48 @@ Object.defineProperty(exports, "computeAvailability", {
14
21
  return _utils.computeAvailability;
15
22
  }
16
23
  });
24
+ Object.defineProperty(exports, "getDefaultInvoiceLayoutConfig", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _utils.getDefaultInvoiceLayoutConfig;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "getDefaultInvoiceTemplateSettings", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _utils.getDefaultInvoiceTemplateSettings;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "normalizeInvoiceLayoutConfig", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _utils.normalizeInvoiceLayoutConfig;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "normalizeInvoiceLayoutFromTemplateSettings", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _utils.normalizeInvoiceLayoutFromTemplateSettings;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "normalizeInvoiceTemplateSettings", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _utils.normalizeInvoiceTemplateSettings;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "normalizeRawInvoiceTemplateSettings", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _utils.normalizeRawInvoiceTemplateSettings;
58
+ }
59
+ });
60
+ Object.defineProperty(exports, "resolveInvoiceReceiptLocales", {
61
+ enumerable: true,
62
+ get: function () {
63
+ return _utils.resolveInvoiceReceiptLocales;
64
+ }
65
+ });
17
66
  var _BaseModule = require("../BaseModule");
18
67
  var _utils = require("./utils");
19
68
  var _types = require("./types");
@@ -28,6 +77,25 @@ Object.keys(_types).forEach(function (key) {
28
77
  }
29
78
  });
30
79
  });
80
+ function isRecord(value) {
81
+ return !!value && typeof value === 'object' && !Array.isArray(value);
82
+ }
83
+ function resolveInvoiceDocumentId(value) {
84
+ if (typeof value === 'number') {
85
+ return Number.isSafeInteger(value) && value > 0 ? String(value) : null;
86
+ }
87
+ if (typeof value !== 'string') return null;
88
+ const normalized = value.trim();
89
+ if (!/^\d+$/.test(normalized)) return null;
90
+ const numericId = Number(normalized);
91
+ return Number.isSafeInteger(numericId) && numericId > 0 ? String(numericId) : null;
92
+ }
93
+ function isLegacyInvoiceTemplate(value) {
94
+ if (typeof value !== 'string' || value.trim().length === 0) return false;
95
+ const normalized = value.trim();
96
+ const numericLike = /^[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?$/i;
97
+ return !numericLike.test(normalized);
98
+ }
31
99
  class OpenDataModule extends _BaseModule.BaseModule {
32
100
  defaultName = 'openData';
33
101
  defaultVersion = '1.0.0';
@@ -39,6 +107,10 @@ class OpenDataModule extends _BaseModule.BaseModule {
39
107
  openCache = false;
40
108
  fatherModule;
41
109
  otherParams = {};
110
+ fetchRevision = 0;
111
+ invoiceTemplateCacheRevision = 0;
112
+ invoiceTemplateDocumentCache = new Map();
113
+ invoiceTemplateDocumentInFlight = new Map();
42
114
  constructor(name, version) {
43
115
  super(name, version);
44
116
  }
@@ -47,6 +119,12 @@ class OpenDataModule extends _BaseModule.BaseModule {
47
119
  this.store = options.store;
48
120
  this.store.data = options.initialState?.data ?? null;
49
121
  this.store.lastFetchedAt = options.initialState?.lastFetchedAt ?? null;
122
+ // Document 解析结果只在当前模块实例内复用。页面刷新后即使恢复了原始
123
+ // OpenData,也必须重新查询一次 NocoBase,以取得当前模板内容。
124
+ this.store.invoiceTemplateSettings = null;
125
+ this.store.invoiceTemplateTarget = null;
126
+ this.store.invoiceTemplateDocumentId = null;
127
+ this.store.invoiceTemplateCacheKey = null;
50
128
  this.otherParams = options.otherParams || {};
51
129
  if (this.otherParams.cacheId) {
52
130
  this.openCache = this.otherParams.openCache ?? false;
@@ -74,7 +152,11 @@ class OpenDataModule extends _BaseModule.BaseModule {
74
152
  this.cacheId = this.otherParams.cacheId;
75
153
  this.fatherModule = this.otherParams.fatherModule;
76
154
  }
155
+ shouldSkipInvoiceTemplateDocument() {
156
+ return String(this.otherParams?.platform || '').trim().toLowerCase() === 'h5';
157
+ }
77
158
  async fetchOpenData(params) {
159
+ const fetchRevision = ++this.fetchRevision;
78
160
  const getData = this.appPlugin?.getData?.();
79
161
  const shopId = getData?.('shop_id');
80
162
  if (!shopId) throw new Error('[OpenDataModule] 无法获取 shop_id');
@@ -95,21 +177,166 @@ class OpenDataModule extends _BaseModule.BaseModule {
95
177
  throw new Error(response?.message || '获取 OpenData 配置失败');
96
178
  }
97
179
  const data = response?.data || {};
98
- this.store.data = data;
99
- this.store.lastFetchedAt = Date.now();
180
+ const resolvedInvoiceTemplate = await this.resolveInvoiceTemplateSettings(data, params.target);
181
+ // clearCache() 或后续请求发生后,旧响应不得复活已失效的 target 配置。
182
+ if (fetchRevision === this.fetchRevision) {
183
+ this.store.data = data;
184
+ this.store.lastFetchedAt = Date.now();
185
+ this.commitInvoiceTemplateSettings(params.target, resolvedInvoiceTemplate);
186
+ }
100
187
  return data;
101
188
  }
102
189
  getOpenData() {
103
190
  return this.store.data;
104
191
  }
192
+ getInvoiceLayoutConfig() {
193
+ return (0, _utils.normalizeInvoiceLayoutFromTemplateSettings)(this.getInvoiceTemplateSettings());
194
+ }
195
+ getInvoiceTemplateSettings() {
196
+ if (this.shouldSkipInvoiceTemplateDocument()) {
197
+ return (0, _utils.getDefaultInvoiceTemplateSettings)();
198
+ }
199
+ if (isRecord(this.store.invoiceTemplateSettings)) {
200
+ const documentId = resolveInvoiceDocumentId(this.store.data?.['documents.invoice_template']);
201
+ if (documentId) {
202
+ const target = this.store.invoiceTemplateTarget;
203
+ if (!target || this.store.invoiceTemplateCacheKey !== this.buildInvoiceTemplateCacheKey(target, documentId)) {
204
+ return (0, _utils.getDefaultInvoiceTemplateSettings)();
205
+ }
206
+ }
207
+ return (0, _utils.normalizeRawInvoiceTemplateSettings)(this.store.invoiceTemplateSettings);
208
+ }
209
+ if (isLegacyInvoiceTemplate(this.store.data?.['documents.invoice_template'])) {
210
+ return (0, _utils.normalizeInvoiceTemplateSettings)(this.store.data);
211
+ }
212
+ return (0, _utils.getDefaultInvoiceTemplateSettings)();
213
+ }
214
+ async ensureInvoiceTemplateSettings(target) {
215
+ const normalizedTarget = String(target || '').trim();
216
+ const config = this.store.data;
217
+ if (!normalizedTarget || !config) {
218
+ return (0, _utils.getDefaultInvoiceTemplateSettings)();
219
+ }
220
+ const fetchRevision = this.fetchRevision;
221
+ const resolved = await this.resolveInvoiceTemplateSettings(config, normalizedTarget);
222
+ if (fetchRevision !== this.fetchRevision || this.store.data !== config) {
223
+ return (0, _utils.getDefaultInvoiceTemplateSettings)();
224
+ }
225
+ this.commitInvoiceTemplateSettings(normalizedTarget, resolved);
226
+ return (0, _utils.normalizeRawInvoiceTemplateSettings)(resolved.settings);
227
+ }
228
+ commitInvoiceTemplateSettings(target, resolved) {
229
+ this.store.invoiceTemplateSettings = (0, _utils.normalizeRawInvoiceTemplateSettings)(resolved.settings);
230
+ this.store.invoiceTemplateTarget = target;
231
+ this.store.invoiceTemplateDocumentId = resolved.documentId;
232
+ this.store.invoiceTemplateCacheKey = resolved.cacheKey;
233
+ }
234
+ async resolveInvoiceTemplateSettings(config, target) {
235
+ if (this.shouldSkipInvoiceTemplateDocument()) {
236
+ return {
237
+ settings: (0, _utils.getDefaultInvoiceTemplateSettings)(),
238
+ documentId: null,
239
+ cacheKey: null
240
+ };
241
+ }
242
+ const rawTemplate = config['documents.invoice_template'];
243
+ const documentId = resolveInvoiceDocumentId(rawTemplate);
244
+ if (!documentId) {
245
+ return {
246
+ settings: isLegacyInvoiceTemplate(rawTemplate) ? (0, _utils.normalizeInvoiceTemplateSettings)(config) : (0, _utils.getDefaultInvoiceTemplateSettings)(),
247
+ documentId: null,
248
+ cacheKey: null
249
+ };
250
+ }
251
+ const cacheKey = this.buildInvoiceTemplateCacheKey(target, documentId);
252
+ if (this.store.invoiceTemplateTarget === target && this.store.invoiceTemplateDocumentId === documentId && this.store.invoiceTemplateCacheKey === cacheKey && isRecord(this.store.invoiceTemplateSettings)) {
253
+ return {
254
+ settings: (0, _utils.normalizeRawInvoiceTemplateSettings)(this.store.invoiceTemplateSettings),
255
+ documentId,
256
+ cacheKey
257
+ };
258
+ }
259
+ const cachedSettings = this.invoiceTemplateDocumentCache.get(cacheKey);
260
+ if (cachedSettings) {
261
+ return {
262
+ settings: (0, _utils.normalizeRawInvoiceTemplateSettings)(cachedSettings),
263
+ documentId,
264
+ cacheKey
265
+ };
266
+ }
267
+ let request = this.invoiceTemplateDocumentInFlight.get(cacheKey);
268
+ if (!request) {
269
+ const cacheRevision = this.invoiceTemplateCacheRevision;
270
+ request = this.fetchInvoiceTemplateDocument(documentId).catch(error => {
271
+ this.logInvoiceTemplateDocumentFallback(error, target, documentId);
272
+ return (0, _utils.getDefaultInvoiceTemplateSettings)();
273
+ }).then(settings => {
274
+ const normalized = (0, _utils.normalizeRawInvoiceTemplateSettings)(settings);
275
+ if (cacheRevision === this.invoiceTemplateCacheRevision) {
276
+ this.invoiceTemplateDocumentCache.set(cacheKey, normalized);
277
+ }
278
+ return normalized;
279
+ }).finally(() => {
280
+ if (this.invoiceTemplateDocumentInFlight.get(cacheKey) === request) {
281
+ this.invoiceTemplateDocumentInFlight.delete(cacheKey);
282
+ }
283
+ });
284
+ this.invoiceTemplateDocumentInFlight.set(cacheKey, request);
285
+ }
286
+ return {
287
+ settings: await request,
288
+ documentId,
289
+ cacheKey
290
+ };
291
+ }
292
+ buildInvoiceTemplateCacheKey(target, documentId) {
293
+ const getData = this.appPlugin?.getData?.();
294
+ return JSON.stringify([getData?.('tenant_id') ?? null, getData?.('shop_id') ?? null, target, documentId]);
295
+ }
296
+ async fetchInvoiceTemplateDocument(documentId) {
297
+ const response = await this.request.get(`/document:get?filterByTk=${encodeURIComponent(documentId)}`, {}, {
298
+ isNocobase: true,
299
+ prefix: false,
300
+ headers: {
301
+ 'x-data-source': 'pisell2'
302
+ },
303
+ customToast: () => {}
304
+ });
305
+ const document = response?.data;
306
+ if (!document || resolveInvoiceDocumentId(document.id) !== documentId) {
307
+ throw new Error(`Invoice Document ${documentId} 返回的 ID 不匹配`);
308
+ }
309
+ if (document.deleted_at !== null && document.deleted_at !== undefined) {
310
+ throw new Error(`Invoice Document ${documentId} 已被删除`);
311
+ }
312
+ if (!isRecord(document.data) || !isRecord(document.data.template_settings)) {
313
+ throw new Error(`Invoice Document ${documentId} 缺少 template_settings`);
314
+ }
315
+ return (0, _utils.normalizeRawInvoiceTemplateSettings)(document.data.template_settings);
316
+ }
317
+ logInvoiceTemplateDocumentFallback(error, target, documentId) {
318
+ console.warn('[OpenDataModule] Invoice Document 加载失败,使用 DEFAULT', {
319
+ target,
320
+ documentId,
321
+ message: error instanceof Error ? error.message : String(error)
322
+ });
323
+ }
105
324
  getLastFetchedAt() {
106
325
  return this.store.lastFetchedAt ?? null;
107
326
  }
108
327
 
109
328
  /** 清除内存与 sessionStorage 镜像中的 OpenData,供宿主切店时调用。 */
110
329
  clearCache() {
330
+ this.fetchRevision += 1;
331
+ this.invoiceTemplateCacheRevision += 1;
332
+ this.invoiceTemplateDocumentCache.clear();
333
+ this.invoiceTemplateDocumentInFlight.clear();
111
334
  this.store.data = null;
112
335
  this.store.lastFetchedAt = null;
336
+ this.store.invoiceTemplateSettings = null;
337
+ this.store.invoiceTemplateTarget = null;
338
+ this.store.invoiceTemplateDocumentId = null;
339
+ this.store.invoiceTemplateCacheKey = null;
113
340
  }
114
341
  checkAvailability(scheduleModule) {
115
342
  const scheduleList = scheduleModule ? scheduleModule?.getScheduleListByIds(this.store.data?.['availability.operating_hours'] || []) : undefined;
@@ -8,6 +8,49 @@ export interface MultiLangObject {
8
8
  original?: string;
9
9
  [key: string]: string | undefined;
10
10
  }
11
+ export declare const INVOICE_MODULE_KEYS: readonly ["reference", "brand", "custom_1", "order", "handover", "customer", "line_groups", "settlement", "custom_2", "payment", "card", "total_savings", "custom_3", "barcode"];
12
+ export type InvoiceModuleKey = (typeof INVOICE_MODULE_KEYS)[number];
13
+ /**
14
+ * Documents Registry 中的 Invoice 模块配置。
15
+ *
16
+ * 模块 key、显隐值及模块私有字段均由 Registry/Native 约定,OS 不做枚举收窄或改写。
17
+ */
18
+ export interface InvoiceTemplateModuleConfig {
19
+ key: string;
20
+ is_show?: unknown;
21
+ [key: string]: unknown;
22
+ }
23
+ export interface InvoiceModuleConfig extends InvoiceTemplateModuleConfig {
24
+ }
25
+ export interface InvoiceLayoutConfig {
26
+ locale?: string;
27
+ module: InvoiceModuleConfig[];
28
+ }
29
+ export interface InvoiceTemplateSettings {
30
+ template: string;
31
+ language: Record<string, number>;
32
+ modules: InvoiceTemplateModuleConfig[];
33
+ [key: string]: unknown;
34
+ }
35
+ export interface InvoiceDocumentResponse {
36
+ data?: {
37
+ id?: number | string;
38
+ deleted_at?: string | null;
39
+ data?: {
40
+ template_settings?: unknown;
41
+ };
42
+ };
43
+ }
44
+ export type RawInvoiceEditConfig = string | {
45
+ language?: unknown;
46
+ modules?: unknown;
47
+ [key: string]: unknown;
48
+ };
49
+ export type RawInvoiceLayoutConfig = string | {
50
+ locale?: unknown;
51
+ module?: unknown[];
52
+ [key: string]: unknown;
53
+ };
11
54
  export interface OpenDataConfig {
12
55
  'basic.enable'?: boolean;
13
56
  'basic.code'?: string | null;
@@ -45,11 +88,23 @@ export interface OpenDataConfig {
45
88
  label: string;
46
89
  value: number;
47
90
  }>;
91
+ 'documents.invoice_template'?: string | number;
92
+ 'documents.invoice_edit'?: RawInvoiceEditConfig;
93
+ /** @deprecated 仅保留旧调用方的类型兼容,Invoice 读取逻辑不再消费该字段。 */
94
+ 'documents.invoice'?: RawInvoiceLayoutConfig;
95
+ /** @deprecated Invoice 读取逻辑只消费扁平的 documents.invoice_* 字段。 */
96
+ documents?: {
97
+ invoice?: RawInvoiceLayoutConfig;
98
+ };
48
99
  [key: string]: any;
49
100
  }
50
101
  export interface OpenDataState {
51
102
  data: OpenDataConfig | null;
52
103
  lastFetchedAt: number | null;
104
+ invoiceTemplateSettings?: InvoiceTemplateSettings | null;
105
+ invoiceTemplateTarget?: string | null;
106
+ invoiceTemplateDocumentId?: string | null;
107
+ invoiceTemplateCacheKey?: string | null;
53
108
  }
54
109
  export interface OpenDataFetchParams {
55
110
  scope: string;