@pisell/pisellos 2.2.309 → 2.2.311
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.
- package/dist/model/strategy/adapter/promotion/index.js +0 -9
- package/dist/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -2
- package/dist/modules/BookingContext/index.js +4 -4
- package/dist/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +58 -19
- package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +24 -12
- package/dist/modules/Customer/index.js +6 -3
- package/dist/modules/Customer/types.d.ts +2 -0
- package/dist/modules/Discount/availability.d.ts +7 -0
- package/dist/modules/Discount/availability.js +49 -0
- package/dist/modules/Discount/entitlementPass.d.ts +34 -0
- package/dist/modules/Discount/entitlementPass.js +147 -0
- package/dist/modules/Discount/index.d.ts +2 -2
- package/dist/modules/Discount/index.js +37 -151
- package/dist/modules/Discount/types.d.ts +36 -5
- package/dist/modules/OpenData/index.d.ts +1 -1
- package/dist/modules/OpenData/index.js +21 -12
- package/dist/modules/Order/index.d.ts +32 -4
- package/dist/modules/Order/index.js +733 -373
- package/dist/modules/Order/types.d.ts +17 -0
- package/dist/modules/Order/utils/orderCollectionIdentity.js +16 -12
- package/dist/modules/Order/utils.d.ts +19 -5
- package/dist/modules/Order/utils.js +306 -86
- package/dist/modules/Payment/index.d.ts +0 -5
- package/dist/modules/Payment/index.js +35 -85
- package/dist/modules/Payment/types.d.ts +21 -1
- package/dist/modules/Payment/types.js +2 -0
- package/dist/modules/Payment/walletpass.d.ts +1 -1
- package/dist/modules/Payment/walletpass.js +80 -47
- package/dist/modules/ProductList/index.js +18 -5
- package/dist/modules/Rules/index.d.ts +2 -2
- package/dist/modules/Rules/index.js +480 -186
- package/dist/modules/Rules/types.d.ts +4 -0
- package/dist/server/index.js +8 -5
- package/dist/server/modules/floor-plan/index.js +34 -3
- package/dist/server/modules/order/index.js +6 -0
- package/dist/server/modules/order/types.d.ts +12 -0
- package/dist/server/modules/payment/index.d.ts +25 -6
- package/dist/server/modules/payment/index.js +660 -133
- package/dist/server/utils/small-ticket.d.ts +8 -5
- package/dist/server/utils/small-ticket.js +1269 -199
- package/dist/solution/BaseSales/index.d.ts +11 -2
- package/dist/solution/BaseSales/index.js +1463 -1173
- package/dist/solution/BaseSales/types.d.ts +7 -3
- package/dist/solution/BaseSales/utils/cartPromotion.js +141 -126
- package/dist/solution/BookingTicket/index.d.ts +11 -2
- package/dist/solution/BookingTicket/index.js +663 -542
- package/dist/solution/BookingTicket/types.d.ts +5 -1
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +2 -0
- package/dist/solution/BookingTicket/utils/scan/applyGlobalScan.js +338 -147
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +8 -4
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +6 -0
- package/dist/solution/BookingTicket/utils/scan/formatGlobalScan.js +19 -6
- package/dist/solution/ShopDiscount/index.d.ts +2 -0
- package/dist/solution/ShopDiscount/index.js +99 -42
- package/dist/solution/ShopDiscount/utils.d.ts +4 -2
- package/dist/solution/ShopDiscount/utils.js +43 -23
- package/dist/solution/UnifiedBookingSales/index.d.ts +2 -2
- package/dist/solution/UnifiedBookingSales/index.js +5 -5
- package/dist/utils/os-private-payload.d.ts +5 -0
- package/dist/utils/os-private-payload.js +17 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.d.ts +2 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -0
- package/lib/modules/BookingContext/index.js +3 -3
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +35 -6
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +13 -6
- package/lib/modules/Customer/index.js +5 -1
- package/lib/modules/Customer/types.d.ts +2 -0
- package/lib/modules/Discount/availability.d.ts +7 -0
- package/lib/modules/Discount/availability.js +43 -0
- package/lib/modules/Discount/entitlementPass.d.ts +34 -0
- package/lib/modules/Discount/entitlementPass.js +141 -0
- package/lib/modules/Discount/index.d.ts +2 -2
- package/lib/modules/Discount/index.js +23 -129
- package/lib/modules/Discount/types.d.ts +36 -5
- package/lib/modules/OpenData/index.d.ts +1 -1
- package/lib/modules/OpenData/index.js +11 -2
- package/lib/modules/Order/index.d.ts +32 -4
- package/lib/modules/Order/index.js +341 -71
- package/lib/modules/Order/types.d.ts +17 -0
- package/lib/modules/Order/utils/orderCollectionIdentity.js +14 -11
- package/lib/modules/Order/utils.d.ts +19 -5
- package/lib/modules/Order/utils.js +215 -13
- package/lib/modules/Payment/index.d.ts +0 -5
- package/lib/modules/Payment/index.js +3 -28
- package/lib/modules/Payment/types.d.ts +21 -1
- package/lib/modules/Payment/types.js +1 -0
- package/lib/modules/Payment/walletpass.d.ts +1 -1
- package/lib/modules/Payment/walletpass.js +29 -9
- package/lib/modules/ProductList/index.js +14 -1
- package/lib/modules/Rules/index.d.ts +2 -2
- package/lib/modules/Rules/index.js +357 -110
- package/lib/modules/Rules/types.d.ts +4 -0
- package/lib/server/index.js +8 -5
- package/lib/server/modules/floor-plan/index.js +29 -1
- package/lib/server/modules/order/index.js +6 -0
- package/lib/server/modules/order/types.d.ts +12 -0
- package/lib/server/modules/payment/index.d.ts +25 -6
- package/lib/server/modules/payment/index.js +350 -78
- package/lib/server/utils/small-ticket.d.ts +8 -5
- package/lib/server/utils/small-ticket.js +1009 -121
- package/lib/solution/BaseSales/index.d.ts +11 -2
- package/lib/solution/BaseSales/index.js +164 -30
- package/lib/solution/BaseSales/types.d.ts +7 -3
- package/lib/solution/BaseSales/utils/cartPromotion.js +12 -4
- package/lib/solution/BookingTicket/index.d.ts +11 -2
- package/lib/solution/BookingTicket/index.js +103 -41
- package/lib/solution/BookingTicket/types.d.ts +5 -1
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.d.ts +2 -0
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +174 -42
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +8 -4
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.d.ts +6 -0
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +11 -3
- package/lib/solution/ShopDiscount/index.d.ts +2 -0
- package/lib/solution/ShopDiscount/index.js +55 -9
- package/lib/solution/ShopDiscount/utils.d.ts +4 -2
- package/lib/solution/ShopDiscount/utils.js +42 -25
- package/lib/solution/UnifiedBookingSales/index.d.ts +2 -2
- package/lib/solution/UnifiedBookingSales/index.js +5 -5
- package/lib/utils/os-private-payload.d.ts +5 -0
- package/lib/utils/os-private-payload.js +22 -0
- package/package.json +1 -1
|
@@ -5,18 +5,33 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.PaymentServerModule = void 0;
|
|
7
7
|
var _BaseModule = require("../../../modules/BaseModule");
|
|
8
|
+
var _lodashEs = require("lodash-es");
|
|
8
9
|
const WALLET_PASS_CODE = 'WALLET_PASS';
|
|
9
10
|
const WALLET_DEPENDENT_CODES = new Set(['PRODUCTVOUCHER', 'GIFTCARD', 'POINTCARD']);
|
|
10
11
|
const PAYMENT_METHODS_LOADED_EVENT = 'payment:onPaymentMethodsLoaded';
|
|
12
|
+
const PAYMENT_METHODS_CHANGED_EVENT = 'payment:onPaymentMethodsChanged';
|
|
13
|
+
const PAYMENT_METHOD_STORE_NAME = 'pay_method';
|
|
14
|
+
const CUSTOM_PAYMENT_MODULE = 'custom_payment';
|
|
15
|
+
const PAYMENT_METHOD_SYNC_DEBOUNCE_MS = 500;
|
|
16
|
+
const SNAPSHOT_ORDER_FIELD = '__payment_snapshot_order';
|
|
17
|
+
const SNAPSHOT_SHOP_ID_FIELD = '__payment_snapshot_shop_id';
|
|
11
18
|
class PaymentServerModule extends _BaseModule.BaseModule {
|
|
12
19
|
defaultName = 'payment';
|
|
13
20
|
defaultVersion = '1.0.0';
|
|
14
21
|
request;
|
|
15
22
|
app;
|
|
16
23
|
logger;
|
|
24
|
+
dbManager;
|
|
17
25
|
store;
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
paymentDataSource;
|
|
27
|
+
initialLoadInFlight = null;
|
|
28
|
+
refreshInFlight = null;
|
|
29
|
+
hasLoadedPayMethods = false;
|
|
30
|
+
hasEmittedLoaded = false;
|
|
31
|
+
syncTimer;
|
|
32
|
+
pendingMessageUuids = new Set();
|
|
33
|
+
queuedTrailingRefresh = false;
|
|
34
|
+
trailingMessageUuids = new Set();
|
|
20
35
|
constructor(name, version) {
|
|
21
36
|
super(name || 'payment', version);
|
|
22
37
|
}
|
|
@@ -31,78 +46,327 @@ class PaymentServerModule extends _BaseModule.BaseModule {
|
|
|
31
46
|
const appPlugin = core.getPlugin('app');
|
|
32
47
|
this.app = appPlugin?.getApp();
|
|
33
48
|
this.logger = this.app?.logger;
|
|
49
|
+
this.dbManager = this.app?.sqlite;
|
|
34
50
|
if (!this.request && !this.app?.request) {
|
|
35
51
|
throw new Error('PaymentServerModule 需要 request 插件或 app.request 支持');
|
|
36
52
|
}
|
|
53
|
+
this.initPaymentDataSource();
|
|
54
|
+
this.setupPaymentMethodSync();
|
|
37
55
|
this.logInfo('PaymentServerModule initialized successfully', {
|
|
38
|
-
hasAppRequest: !!this.app?.request
|
|
56
|
+
hasAppRequest: !!this.app?.request,
|
|
57
|
+
hasSQLite: !!this.dbManager,
|
|
58
|
+
hasPaymentDataSource: !!this.paymentDataSource
|
|
39
59
|
});
|
|
40
60
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// });
|
|
51
|
-
// return {
|
|
52
|
-
// code: 200,
|
|
53
|
-
// status: true,
|
|
54
|
-
// data: payMethods,
|
|
55
|
-
// };
|
|
56
|
-
// },
|
|
57
|
-
// },
|
|
58
|
-
// ];
|
|
59
|
-
// }
|
|
60
|
-
|
|
61
|
+
async preload() {
|
|
62
|
+
try {
|
|
63
|
+
await this.ensureInitialPayMethods('preload');
|
|
64
|
+
} catch (error) {
|
|
65
|
+
this.logError('preload 支付方式失败,保持空列表并允许后续读取重试', {
|
|
66
|
+
error: this.getErrorMessage(error)
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
61
70
|
async getPayMethodListAsync(options = {}) {
|
|
62
|
-
this.logInfo('Starting getPayMethodListAsync'
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
this.logInfo('Starting getPayMethodListAsync', {
|
|
72
|
+
hasLoadedPayMethods: this.hasLoadedPayMethods,
|
|
73
|
+
cachedCount: this.store.payMethods.length
|
|
74
|
+
});
|
|
75
|
+
if (!this.hasLoadedPayMethods) {
|
|
76
|
+
try {
|
|
77
|
+
await this.ensureInitialPayMethods('route');
|
|
78
|
+
} catch (error) {
|
|
79
|
+
this.logError('getPayMethodListAsync 初始化失败', {
|
|
80
|
+
error: this.getErrorMessage(error)
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} else if (!this.paymentDataSource) {
|
|
84
|
+
try {
|
|
85
|
+
await this.refreshPayMethodsSingleFlight({
|
|
86
|
+
trigger: 'compat.route',
|
|
87
|
+
emitChanged: false
|
|
88
|
+
});
|
|
89
|
+
} catch (error) {
|
|
90
|
+
this.logWarning('兼容模式远端刷新失败,保留当前运行态快照', {
|
|
91
|
+
error: this.getErrorMessage(error)
|
|
92
|
+
});
|
|
93
|
+
}
|
|
65
94
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
95
|
+
return this.resolvePayMethods(this.store.payMethods, options);
|
|
96
|
+
}
|
|
97
|
+
async ensureInitialPayMethods(trigger) {
|
|
98
|
+
if (this.hasLoadedPayMethods) return this.store.payMethods;
|
|
99
|
+
if (this.initialLoadInFlight) return this.initialLoadInFlight;
|
|
100
|
+
this.initialLoadInFlight = (async () => {
|
|
101
|
+
const localSnapshot = await this.loadPayMethodsFromSQLite();
|
|
102
|
+
if (localSnapshot.available) {
|
|
103
|
+
this.setPayMethodMirror(localSnapshot.methods);
|
|
104
|
+
this.logInfo('从 SQLite 加载支付方式兜底快照', {
|
|
105
|
+
trigger,
|
|
106
|
+
count: localSnapshot.methods.length,
|
|
107
|
+
shopScope: this.resolveCurrentShopScope(localSnapshot.methods)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
await this.refreshPayMethodsSingleFlight({
|
|
112
|
+
trigger,
|
|
113
|
+
emitChanged: false
|
|
114
|
+
});
|
|
115
|
+
this.hasLoadedPayMethods = true;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (!localSnapshot.available) throw error;
|
|
118
|
+
this.hasLoadedPayMethods = true;
|
|
119
|
+
this.logWarning('远端刷新失败,继续使用 SQLite 支付方式快照', {
|
|
120
|
+
trigger,
|
|
121
|
+
count: localSnapshot.methods.length,
|
|
122
|
+
error: this.getErrorMessage(error)
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (!this.hasEmittedLoaded) {
|
|
126
|
+
this.hasEmittedLoaded = true;
|
|
127
|
+
await this.core.effects.emit(PAYMENT_METHODS_LOADED_EVENT, this.store.payMethods);
|
|
128
|
+
}
|
|
129
|
+
return this.store.payMethods;
|
|
130
|
+
})().finally(() => {
|
|
131
|
+
this.initialLoadInFlight = null;
|
|
132
|
+
});
|
|
133
|
+
return this.initialLoadInFlight;
|
|
134
|
+
}
|
|
135
|
+
initPaymentDataSource() {
|
|
136
|
+
const PaymentDataSourceClass = this.core.serverOptions?.All_DATA_SOURCES?.PaymentDataSource;
|
|
137
|
+
if (!PaymentDataSourceClass) {
|
|
138
|
+
this.logWarning('PaymentDataSource 不可用,使用无本地持久化的兼容模式');
|
|
139
|
+
return;
|
|
69
140
|
}
|
|
70
|
-
this.
|
|
71
|
-
|
|
141
|
+
this.paymentDataSource = new PaymentDataSourceClass();
|
|
142
|
+
}
|
|
143
|
+
setupPaymentMethodSync() {
|
|
144
|
+
if (!this.paymentDataSource) return;
|
|
145
|
+
this.paymentDataSource.run({
|
|
146
|
+
pubsub: {
|
|
147
|
+
callback: res => {
|
|
148
|
+
const message = res?.data || res;
|
|
149
|
+
if (!message || message.module !== CUSTOM_PAYMENT_MODULE) return;
|
|
150
|
+
const messageUuid = String(message.message_uuid || '').trim();
|
|
151
|
+
if (messageUuid) this.pendingMessageUuids.add(messageUuid);
|
|
152
|
+
this.logInfo('收到 custom_payment Ably 消息,等待全量刷新', {
|
|
153
|
+
message_uuid: messageUuid || undefined,
|
|
154
|
+
action: message.action,
|
|
155
|
+
operation: message.operation
|
|
156
|
+
});
|
|
157
|
+
this.schedulePaymentMethodRefresh();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}).catch(error => {
|
|
161
|
+
this.logError('建立 custom_payment pubsub 订阅失败', {
|
|
162
|
+
error: this.getErrorMessage(error)
|
|
163
|
+
});
|
|
72
164
|
});
|
|
73
|
-
const payMethods = await this.payMethodListInFlight;
|
|
74
|
-
return this.resolvePayMethods(payMethods, options);
|
|
75
165
|
}
|
|
76
|
-
|
|
77
|
-
this.
|
|
78
|
-
this.
|
|
166
|
+
schedulePaymentMethodRefresh() {
|
|
167
|
+
if (this.syncTimer) clearTimeout(this.syncTimer);
|
|
168
|
+
this.syncTimer = setTimeout(() => {
|
|
169
|
+
this.syncTimer = undefined;
|
|
170
|
+
const messageUuids = [...this.pendingMessageUuids];
|
|
171
|
+
this.pendingMessageUuids.clear();
|
|
172
|
+
void this.refreshPayMethodsSingleFlight({
|
|
173
|
+
trigger: 'ably',
|
|
174
|
+
emitChanged: true,
|
|
175
|
+
messageUuids
|
|
176
|
+
}).catch(error => {
|
|
177
|
+
this.logError('custom_payment Ably 全量刷新失败,保留旧快照', {
|
|
178
|
+
message_uuids: messageUuids,
|
|
179
|
+
error: this.getErrorMessage(error)
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}, PAYMENT_METHOD_SYNC_DEBOUNCE_MS);
|
|
79
183
|
}
|
|
80
|
-
async
|
|
184
|
+
async refreshPayMethodsSingleFlight(context) {
|
|
185
|
+
if (this.refreshInFlight) {
|
|
186
|
+
if (context.trigger.startsWith('ably')) {
|
|
187
|
+
this.queuedTrailingRefresh = true;
|
|
188
|
+
context.messageUuids?.forEach(uuid => this.trailingMessageUuids.add(uuid));
|
|
189
|
+
this.logInfo('支付方式刷新进行中,已排队一次尾随刷新', {
|
|
190
|
+
trigger: context.trigger,
|
|
191
|
+
message_uuids: context.messageUuids || []
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return this.refreshInFlight;
|
|
195
|
+
}
|
|
196
|
+
const refreshTask = this.performRemoteRefresh(context);
|
|
197
|
+
this.refreshInFlight = refreshTask;
|
|
81
198
|
try {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.
|
|
86
|
-
|
|
199
|
+
return await refreshTask;
|
|
200
|
+
} finally {
|
|
201
|
+
if (this.refreshInFlight === refreshTask) this.refreshInFlight = null;
|
|
202
|
+
if (this.queuedTrailingRefresh) {
|
|
203
|
+
this.queuedTrailingRefresh = false;
|
|
204
|
+
const messageUuids = [...this.trailingMessageUuids];
|
|
205
|
+
this.trailingMessageUuids.clear();
|
|
206
|
+
void this.refreshPayMethodsSingleFlight({
|
|
207
|
+
trigger: 'ably.trailing',
|
|
208
|
+
emitChanged: true,
|
|
209
|
+
messageUuids
|
|
210
|
+
}).catch(error => {
|
|
211
|
+
this.logError('custom_payment 尾随刷新失败,保留当前快照', {
|
|
212
|
+
message_uuids: messageUuids,
|
|
213
|
+
error: this.getErrorMessage(error)
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async performRemoteRefresh(context) {
|
|
220
|
+
const oldMethods = this.store.payMethods;
|
|
221
|
+
const payMethods = await this.fetchRemotePayMethods();
|
|
222
|
+
const persisted = await this.replacePayMethodsInSQLite(payMethods);
|
|
223
|
+
if (!persisted) {
|
|
224
|
+
this.logWarning('SQLite 不可用,支付方式仅用于当前运行时', {
|
|
225
|
+
trigger: context.trigger,
|
|
226
|
+
count: payMethods.length
|
|
87
227
|
});
|
|
88
|
-
return payMethods;
|
|
89
|
-
} catch (error) {
|
|
90
|
-
console.error('[PaymentServerModule] 获取支付方式列表失败', error);
|
|
91
|
-
this.logError('getPayMethodListAsync failed', error);
|
|
92
|
-
return [];
|
|
93
228
|
}
|
|
229
|
+
this.setPayMethodMirror(payMethods);
|
|
230
|
+
this.hasLoadedPayMethods = true;
|
|
231
|
+
const changed = !this.arePayMethodsEqual(oldMethods, payMethods);
|
|
232
|
+
if (context.emitChanged && changed) {
|
|
233
|
+
await this.core.effects.emit(PAYMENT_METHODS_CHANGED_EVENT, {
|
|
234
|
+
oldMethods,
|
|
235
|
+
newMethods: this.store.payMethods
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
this.logInfo('远端支付方式全量刷新成功', {
|
|
239
|
+
trigger: context.trigger,
|
|
240
|
+
message_uuids: context.messageUuids || [],
|
|
241
|
+
count: payMethods.length,
|
|
242
|
+
persisted,
|
|
243
|
+
changed
|
|
244
|
+
});
|
|
245
|
+
return this.store.payMethods;
|
|
94
246
|
}
|
|
95
247
|
async fetchRemotePayMethods() {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
248
|
+
const response = this.paymentDataSource ? await this.paymentDataSource.run({
|
|
249
|
+
http: {
|
|
250
|
+
url: '/shop/pay/custom-payment/all'
|
|
251
|
+
}
|
|
252
|
+
}) : await (this.app?.request || this.request).get('/shop/pay/custom-payment/all', undefined);
|
|
253
|
+
const payMethods = response?.data !== undefined ? response.data : response;
|
|
254
|
+
if (!Array.isArray(payMethods)) {
|
|
255
|
+
throw new Error('支付方式全量接口返回值不是数组');
|
|
256
|
+
}
|
|
257
|
+
if (payMethods.some(method => !method || method.id === undefined || method.id === null)) {
|
|
258
|
+
throw new Error('支付方式全量接口存在缺少 id 的记录');
|
|
259
|
+
}
|
|
260
|
+
return payMethods;
|
|
261
|
+
}
|
|
262
|
+
async loadPayMethodsFromSQLite() {
|
|
263
|
+
if (!this.dbManager) return {
|
|
264
|
+
available: false,
|
|
265
|
+
methods: []
|
|
266
|
+
};
|
|
267
|
+
try {
|
|
268
|
+
const rows = await this.dbManager.getAll(PAYMENT_METHOD_STORE_NAME);
|
|
269
|
+
if (!Array.isArray(rows) || rows.length === 0) {
|
|
270
|
+
return {
|
|
271
|
+
available: false,
|
|
272
|
+
methods: []
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
const currentShopScope = this.resolveCurrentShopScope();
|
|
276
|
+
if (!currentShopScope) {
|
|
277
|
+
this.logWarning('无法确认当前店铺,忽略 SQLite 支付方式快照');
|
|
278
|
+
return {
|
|
279
|
+
available: false,
|
|
280
|
+
methods: []
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const scopedRows = rows.filter(row => String(row?.[SNAPSHOT_SHOP_ID_FIELD] || '') === currentShopScope);
|
|
284
|
+
if (scopedRows.length === 0) {
|
|
285
|
+
this.logWarning('忽略其他店铺的 SQLite 支付方式快照', {
|
|
286
|
+
currentShopScope,
|
|
287
|
+
storedShopScopes: [...new Set(rows.map(row => String(row?.[SNAPSHOT_SHOP_ID_FIELD] || '')).filter(Boolean))]
|
|
288
|
+
});
|
|
289
|
+
return {
|
|
290
|
+
available: false,
|
|
291
|
+
methods: []
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
const methods = scopedRows.slice().sort((left, right) => Number(left?.[SNAPSHOT_ORDER_FIELD] || 0) - Number(right?.[SNAPSHOT_ORDER_FIELD] || 0)).map(row => this.stripSnapshotFields(row));
|
|
295
|
+
return {
|
|
296
|
+
available: true,
|
|
297
|
+
methods
|
|
298
|
+
};
|
|
299
|
+
} catch (error) {
|
|
300
|
+
this.logWarning('从 SQLite 读取支付方式失败', {
|
|
301
|
+
error: this.getErrorMessage(error)
|
|
302
|
+
});
|
|
303
|
+
return {
|
|
304
|
+
available: false,
|
|
305
|
+
methods: []
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
async replacePayMethodsInSQLite(payMethods) {
|
|
310
|
+
if (!this.dbManager) return false;
|
|
311
|
+
const previousRows = await this.dbManager.getAll(PAYMENT_METHOD_STORE_NAME);
|
|
312
|
+
const shopScope = this.resolveCurrentShopScope(payMethods);
|
|
313
|
+
const snapshotRows = payMethods.map((method, index) => ({
|
|
314
|
+
...method,
|
|
315
|
+
[SNAPSHOT_ORDER_FIELD]: index,
|
|
316
|
+
[SNAPSHOT_SHOP_ID_FIELD]: shopScope
|
|
317
|
+
}));
|
|
318
|
+
try {
|
|
319
|
+
await this.dbManager.clear(PAYMENT_METHOD_STORE_NAME);
|
|
320
|
+
if (snapshotRows.length > 0) {
|
|
321
|
+
await this.dbManager.bulkAdd(PAYMENT_METHOD_STORE_NAME, snapshotRows);
|
|
322
|
+
}
|
|
323
|
+
return true;
|
|
324
|
+
} catch (error) {
|
|
325
|
+
const writeError = this.getErrorMessage(error);
|
|
326
|
+
try {
|
|
327
|
+
await this.dbManager.clear(PAYMENT_METHOD_STORE_NAME);
|
|
328
|
+
if (Array.isArray(previousRows) && previousRows.length > 0) {
|
|
329
|
+
await this.dbManager.bulkAdd(PAYMENT_METHOD_STORE_NAME, previousRows);
|
|
330
|
+
}
|
|
331
|
+
} catch (rollbackError) {
|
|
332
|
+
this.logError('支付方式 SQLite 快照回滚失败', {
|
|
333
|
+
writeError,
|
|
334
|
+
rollbackError: this.getErrorMessage(rollbackError)
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
throw new Error(`支付方式 SQLite 全量替换失败: ${writeError}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
resolveCurrentShopScope(payMethods = []) {
|
|
341
|
+
const readStorageObject = key => {
|
|
342
|
+
try {
|
|
343
|
+
const raw = this.app?.storage?.getStorage?.(key);
|
|
344
|
+
if (!raw) return {};
|
|
345
|
+
if (typeof raw === 'object') return raw;
|
|
346
|
+
const parsed = JSON.parse(raw);
|
|
347
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
348
|
+
} catch {
|
|
349
|
+
return {};
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
const selectedStore = readStorageObject('selectedStore');
|
|
353
|
+
const core = readStorageObject('core');
|
|
354
|
+
const scope = selectedStore.id ?? selectedStore.shop_id ?? core.id ?? core.shop_id ?? payMethods.find(method => method?.shop_id != null)?.shop_id;
|
|
355
|
+
return scope === undefined || scope === null ? '' : String(scope);
|
|
356
|
+
}
|
|
357
|
+
stripSnapshotFields(row) {
|
|
358
|
+
const {
|
|
359
|
+
[SNAPSHOT_ORDER_FIELD]: _snapshotOrder,
|
|
360
|
+
[SNAPSHOT_SHOP_ID_FIELD]: _snapshotShopId,
|
|
361
|
+
...method
|
|
362
|
+
} = row;
|
|
363
|
+
return method;
|
|
100
364
|
}
|
|
101
|
-
|
|
102
|
-
return
|
|
365
|
+
arePayMethodsEqual(left, right) {
|
|
366
|
+
return (0, _lodashEs.isEqual)(left, right);
|
|
103
367
|
}
|
|
104
368
|
resolvePayMethods(payMethods, options) {
|
|
105
|
-
if (!options.shouldFilter) return payMethods;
|
|
369
|
+
if (!options.shouldFilter) return [...payMethods];
|
|
106
370
|
return this.filterPayMethods(payMethods);
|
|
107
371
|
}
|
|
108
372
|
filterPayMethods(payMethods) {
|
|
@@ -121,48 +385,56 @@ class PaymentServerModule extends _BaseModule.BaseModule {
|
|
|
121
385
|
});
|
|
122
386
|
return availableMethods;
|
|
123
387
|
}
|
|
124
|
-
|
|
125
|
-
this.
|
|
126
|
-
|
|
388
|
+
setPayMethodMirror(payMethods) {
|
|
389
|
+
this.store.payMethods = payMethods.map(method => ({
|
|
390
|
+
...method
|
|
391
|
+
}));
|
|
392
|
+
}
|
|
393
|
+
getErrorMessage(error) {
|
|
394
|
+
return error instanceof Error ? error.message : String(error);
|
|
127
395
|
}
|
|
128
396
|
logInfo(title, metadata) {
|
|
129
397
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
});
|
|
136
|
-
}
|
|
398
|
+
this.logger?.addLog({
|
|
399
|
+
type: 'info',
|
|
400
|
+
title: `[PaymentServerModule] ${title}`,
|
|
401
|
+
metadata: metadata || {}
|
|
402
|
+
});
|
|
137
403
|
} catch {
|
|
138
404
|
// 日志记录失败不影响主流程
|
|
139
405
|
}
|
|
140
406
|
}
|
|
141
407
|
logWarning(title, metadata) {
|
|
142
408
|
try {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
});
|
|
149
|
-
}
|
|
409
|
+
this.logger?.addLog({
|
|
410
|
+
type: 'warning',
|
|
411
|
+
title: `[PaymentServerModule] ${title}`,
|
|
412
|
+
metadata: metadata || {}
|
|
413
|
+
});
|
|
150
414
|
} catch {
|
|
151
415
|
// 日志记录失败不影响主流程
|
|
152
416
|
}
|
|
153
417
|
}
|
|
154
418
|
logError(title, metadata) {
|
|
155
419
|
try {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
162
|
-
}
|
|
420
|
+
this.logger?.addLog({
|
|
421
|
+
type: 'error',
|
|
422
|
+
title: `[PaymentServerModule] ${title}`,
|
|
423
|
+
metadata: metadata || {}
|
|
424
|
+
});
|
|
163
425
|
} catch {
|
|
164
426
|
// 日志记录失败不影响主流程
|
|
165
427
|
}
|
|
166
428
|
}
|
|
429
|
+
destroy() {
|
|
430
|
+
if (this.syncTimer) clearTimeout(this.syncTimer);
|
|
431
|
+
this.syncTimer = undefined;
|
|
432
|
+
this.pendingMessageUuids.clear();
|
|
433
|
+
this.trailingMessageUuids.clear();
|
|
434
|
+
this.queuedTrailingRefresh = false;
|
|
435
|
+
this.paymentDataSource?.destroy?.();
|
|
436
|
+
this.paymentDataSource = undefined;
|
|
437
|
+
super.destroy();
|
|
438
|
+
}
|
|
167
439
|
}
|
|
168
440
|
exports.PaymentServerModule = PaymentServerModule;
|
|
@@ -28,32 +28,35 @@ export interface SmallTicketItem {
|
|
|
28
28
|
value: string;
|
|
29
29
|
size?: number;
|
|
30
30
|
align?: string;
|
|
31
|
+
product_uid?: string | number;
|
|
32
|
+
booking_uid?: string | number;
|
|
31
33
|
}
|
|
32
34
|
export interface SmallTicketProduct {
|
|
33
35
|
product_title: string;
|
|
34
36
|
product_quantity: number;
|
|
35
37
|
selling_price: string;
|
|
38
|
+
total_selling_price: string;
|
|
36
39
|
original_price: string;
|
|
37
40
|
base_price?: string;
|
|
38
41
|
total_original_price: string;
|
|
42
|
+
options_total_price?: string;
|
|
43
|
+
package_items_total_price?: string;
|
|
39
44
|
extension_list: any[];
|
|
40
45
|
product_uid?: string | number;
|
|
41
46
|
booking_uid?: string | number;
|
|
42
47
|
product_note?: string;
|
|
48
|
+
allergy?: string;
|
|
43
49
|
options?: Array<{
|
|
44
50
|
name: string;
|
|
45
51
|
num?: number;
|
|
46
52
|
price?: string;
|
|
53
|
+
total_price: string;
|
|
47
54
|
value?: string;
|
|
48
55
|
}>;
|
|
49
56
|
variant?: string;
|
|
50
57
|
combinations?: any[];
|
|
51
58
|
}
|
|
52
|
-
export
|
|
53
|
-
product_uid?: string | number;
|
|
54
|
-
booking_uid?: string | number;
|
|
55
|
-
}
|
|
56
|
-
export type SmallTicketAppointment = SmallTicketItem[] | SmallTicketBookingSnapshot[];
|
|
59
|
+
export type SmallTicketAppointment = SmallTicketItem[];
|
|
57
60
|
export interface SmallTicketLocaleData {
|
|
58
61
|
base_data: Record<string, any>;
|
|
59
62
|
products: SmallTicketProduct[];
|