ipaynow-nodejs-sdk 1.0.0

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/src/params.js ADDED
@@ -0,0 +1,366 @@
1
+ /**
2
+ * 将 Params 实例(不含 extraParams)与 extraParams 合并为字符串字段表。
3
+ * null/undefined 跳过;其余值转字符串;extraParams 与命名字段同名时以 extraParams 为准
4
+ * (即后写覆盖前写,与 Java BeanMap 行为一致)。
5
+ * @param {object} instance
6
+ * @returns {Record<string, string>}
7
+ */
8
+ function toFieldsOf(instance) {
9
+ const out = {};
10
+ for (const key of Object.keys(instance)) {
11
+ if (key === "extraParams") continue;
12
+ const value = instance[key];
13
+ if (value === undefined || value === null) continue;
14
+ out[key] = String(value);
15
+ }
16
+ if (instance.extraParams) {
17
+ for (const [key, value] of Object.entries(instance.extraParams)) {
18
+ if (value === undefined || value === null) continue;
19
+ out[key] = String(value);
20
+ }
21
+ }
22
+ return out;
23
+ }
24
+
25
+ /** JSAPI 统一下单入参(规范 §5.1) */
26
+ export class JsapiUnifiedOrderParams {
27
+ /** @param {object} [fields] */
28
+ constructor(fields = {}) {
29
+ const {
30
+ consumerCreateIp,
31
+ consumerId,
32
+ deviceType = "0600",
33
+ frontNotifyUrl,
34
+ mhtCurrencyType = "156",
35
+ mhtGoodsTag,
36
+ mhtGoodsDetails,
37
+ mhtLimitPay,
38
+ mhtOrderAmt,
39
+ mhtOrderDetail,
40
+ mhtOrderName,
41
+ mhtOrderNo,
42
+ mhtOrderStartTime,
43
+ mhtOrderTimeOut = 120,
44
+ mhtOrderType = "05",
45
+ mhtReserved,
46
+ mhtSubAppId,
47
+ notifyUrl,
48
+ outputType,
49
+ payChannelType,
50
+ extraParams,
51
+ } = fields;
52
+ Object.assign(this, {
53
+ consumerCreateIp,
54
+ consumerId,
55
+ deviceType,
56
+ frontNotifyUrl,
57
+ mhtCurrencyType,
58
+ mhtGoodsTag,
59
+ mhtGoodsDetails,
60
+ mhtLimitPay,
61
+ mhtOrderAmt,
62
+ mhtOrderDetail,
63
+ mhtOrderName,
64
+ mhtOrderNo,
65
+ mhtOrderStartTime,
66
+ mhtOrderTimeOut,
67
+ mhtOrderType,
68
+ mhtReserved,
69
+ mhtSubAppId,
70
+ notifyUrl,
71
+ outputType,
72
+ payChannelType,
73
+ });
74
+ this.extraParams = extraParams;
75
+ }
76
+
77
+ toFields() {
78
+ return toFieldsOf(this);
79
+ }
80
+ }
81
+
82
+ /** 聚合码统一下单入参(规范 §5.2) */
83
+ export class AggregateCodeUnifiedOrderParams {
84
+ /** @param {object} [fields] */
85
+ constructor(fields = {}) {
86
+ const {
87
+ deviceType = "20",
88
+ mhtCurrencyType = "156",
89
+ mhtLimitPay,
90
+ mhtOrderAmt,
91
+ mhtOrderDetail,
92
+ mhtOrderName,
93
+ mhtOrderNo,
94
+ mhtOrderStartTime,
95
+ mhtOrderTimeOut = 120,
96
+ mhtOrderType = "05",
97
+ mhtReserved,
98
+ notifyUrl,
99
+ outputType,
100
+ extraParams,
101
+ } = fields;
102
+ Object.assign(this, {
103
+ deviceType,
104
+ mhtCurrencyType,
105
+ mhtLimitPay,
106
+ mhtOrderAmt,
107
+ mhtOrderDetail,
108
+ mhtOrderName,
109
+ mhtOrderNo,
110
+ mhtOrderStartTime,
111
+ mhtOrderTimeOut,
112
+ mhtOrderType,
113
+ mhtReserved,
114
+ notifyUrl,
115
+ outputType,
116
+ });
117
+ this.extraParams = extraParams;
118
+ }
119
+
120
+ toFields() {
121
+ return toFieldsOf(this);
122
+ }
123
+ }
124
+
125
+ /** 小程序统一下单入参(规范 §5.3) */
126
+ export class MiniProgramUnifiedOrderParams {
127
+ /** @param {object} [fields] */
128
+ constructor(fields = {}) {
129
+ const {
130
+ consumerId,
131
+ deviceType = "14",
132
+ discountAmt,
133
+ mhtCurrencyType = "156",
134
+ mhtGoodsTag,
135
+ mhtGoodsDetails,
136
+ mhtLimitPay,
137
+ mhtOrderAmt,
138
+ mhtOrderDetail,
139
+ mhtOrderName,
140
+ mhtOrderNo,
141
+ mhtOrderStartTime,
142
+ mhtOrderTimeOut = 120,
143
+ mhtOrderType = "05",
144
+ mhtReserved,
145
+ mhtSubAppId,
146
+ notifyUrl,
147
+ oriMhtOrderAmt,
148
+ outputType = "1",
149
+ payChannelType,
150
+ mhtStoreId,
151
+ extraParams,
152
+ } = fields;
153
+ Object.assign(this, {
154
+ consumerId,
155
+ deviceType,
156
+ discountAmt,
157
+ mhtCurrencyType,
158
+ mhtGoodsTag,
159
+ mhtGoodsDetails,
160
+ mhtLimitPay,
161
+ mhtOrderAmt,
162
+ mhtOrderDetail,
163
+ mhtOrderName,
164
+ mhtOrderNo,
165
+ mhtOrderStartTime,
166
+ mhtOrderTimeOut,
167
+ mhtOrderType,
168
+ mhtReserved,
169
+ mhtSubAppId,
170
+ notifyUrl,
171
+ oriMhtOrderAmt,
172
+ outputType,
173
+ payChannelType,
174
+ mhtStoreId,
175
+ });
176
+ this.extraParams = extraParams;
177
+ }
178
+
179
+ toFields() {
180
+ return toFieldsOf(this);
181
+ }
182
+ }
183
+
184
+ /** H5 统一下单入参(规范 §5.4) */
185
+ export class H5UnifiedOrderParams {
186
+ /** @param {object} [fields] */
187
+ constructor(fields = {}) {
188
+ const {
189
+ consumerCreateIp,
190
+ consumerId,
191
+ deviceType = "0601",
192
+ frontNotifyUrl,
193
+ mhtCurrencyType = "156",
194
+ mhtLimitPay,
195
+ mhtOrderAmt,
196
+ mhtOrderDetail,
197
+ mhtOrderName,
198
+ mhtOrderNo,
199
+ mhtOrderStartTime,
200
+ mhtOrderTimeOut = 120,
201
+ mhtOrderType = "05",
202
+ mhtReserved,
203
+ notifyUrl,
204
+ outputType,
205
+ payChannelType,
206
+ specifiedChannel,
207
+ payAccNo,
208
+ guideId,
209
+ extraParams,
210
+ } = fields;
211
+ Object.assign(this, {
212
+ consumerCreateIp,
213
+ consumerId,
214
+ deviceType,
215
+ frontNotifyUrl,
216
+ mhtCurrencyType,
217
+ mhtLimitPay,
218
+ mhtOrderAmt,
219
+ mhtOrderDetail,
220
+ mhtOrderName,
221
+ mhtOrderNo,
222
+ mhtOrderStartTime,
223
+ mhtOrderTimeOut,
224
+ mhtOrderType,
225
+ mhtReserved,
226
+ notifyUrl,
227
+ outputType,
228
+ payChannelType,
229
+ specifiedChannel,
230
+ payAccNo,
231
+ guideId,
232
+ });
233
+ this.extraParams = extraParams;
234
+ }
235
+
236
+ toFields() {
237
+ return toFieldsOf(this);
238
+ }
239
+ }
240
+
241
+ /** APP 统一下单入参(规范 §5.5) */
242
+ export class AppUnifiedOrderParams {
243
+ /** @param {object} [fields] */
244
+ constructor(fields = {}) {
245
+ const {
246
+ consumerCreateIp,
247
+ consumerId,
248
+ consumerName,
249
+ deviceType = "01",
250
+ mhtCurrencyType = "156",
251
+ mhtLimitPay,
252
+ mhtOrderAmt,
253
+ mhtOrderDetail,
254
+ mhtOrderName,
255
+ mhtOrderNo,
256
+ mhtOrderStartTime,
257
+ mhtOrderTimeOut = 120,
258
+ mhtOrderType = "05",
259
+ mhtReserved,
260
+ mhtSubAppId,
261
+ notifyUrl,
262
+ payChannelType,
263
+ outputType = "0",
264
+ frontNotifyUrl,
265
+ mhtStoreId,
266
+ extraParams,
267
+ } = fields;
268
+ Object.assign(this, {
269
+ consumerCreateIp,
270
+ consumerId,
271
+ consumerName,
272
+ deviceType,
273
+ mhtCurrencyType,
274
+ mhtLimitPay,
275
+ mhtOrderAmt,
276
+ mhtOrderDetail,
277
+ mhtOrderName,
278
+ mhtOrderNo,
279
+ mhtOrderStartTime,
280
+ mhtOrderTimeOut,
281
+ mhtOrderType,
282
+ mhtReserved,
283
+ mhtSubAppId,
284
+ notifyUrl,
285
+ payChannelType,
286
+ outputType,
287
+ frontNotifyUrl,
288
+ mhtStoreId,
289
+ });
290
+ this.extraParams = extraParams;
291
+ }
292
+
293
+ toFields() {
294
+ return toFieldsOf(this);
295
+ }
296
+ }
297
+
298
+ /** 订单查询入参(规范 §5.6) */
299
+ export class OrderQueryParams {
300
+ /** @param {object} [fields] */
301
+ constructor(fields = {}) {
302
+ const { deviceType, mhtOrderNo, version, extraParams } = fields;
303
+ Object.assign(this, { deviceType, mhtOrderNo, version });
304
+ this.extraParams = extraParams;
305
+ }
306
+
307
+ toFields() {
308
+ return toFieldsOf(this);
309
+ }
310
+ }
311
+
312
+ /** 退款入参(规范 §5.7) */
313
+ export class RefundParams {
314
+ /** @param {object} [fields] */
315
+ constructor(fields = {}) {
316
+ const { amount, mhtOrderNo, mhtRefundNo, notifyUrl, oriTransId, reason, extraParams } = fields;
317
+ Object.assign(this, { amount, mhtOrderNo, mhtRefundNo, notifyUrl, oriTransId, reason });
318
+ this.extraParams = extraParams;
319
+ }
320
+
321
+ toFields() {
322
+ return toFieldsOf(this);
323
+ }
324
+ }
325
+
326
+ /** 退款查询入参(规范 §5.8) */
327
+ export class RefundQueryParams {
328
+ /** @param {object} [fields] */
329
+ constructor(fields = {}) {
330
+ const { mhtRefundNo, extraParams } = fields;
331
+ Object.assign(this, { mhtRefundNo });
332
+ this.extraParams = extraParams;
333
+ }
334
+
335
+ toFields() {
336
+ return toFieldsOf(this);
337
+ }
338
+ }
339
+
340
+ /** 撤销入参(规范 §5.9) */
341
+ export class ReverseParams {
342
+ /** @param {object} [fields] */
343
+ constructor(fields = {}) {
344
+ const { mhtRefundNo, mhtOrderNo, oriTransId, reason, extraParams } = fields;
345
+ Object.assign(this, { mhtRefundNo, mhtOrderNo, oriTransId, reason });
346
+ this.extraParams = extraParams;
347
+ }
348
+
349
+ toFields() {
350
+ return toFieldsOf(this);
351
+ }
352
+ }
353
+
354
+ /** 撤销查询入参(规范 §5.10) */
355
+ export class ReverseQueryParams {
356
+ /** @param {object} [fields] */
357
+ constructor(fields = {}) {
358
+ const { mhtRefundNo, extraParams } = fields;
359
+ Object.assign(this, { mhtRefundNo });
360
+ this.extraParams = extraParams;
361
+ }
362
+
363
+ toFields() {
364
+ return toFieldsOf(this);
365
+ }
366
+ }
@@ -0,0 +1,269 @@
1
+ import {
2
+ JsapiUnifiedOrderParams,
3
+ AggregateCodeUnifiedOrderParams,
4
+ MiniProgramUnifiedOrderParams,
5
+ H5UnifiedOrderParams,
6
+ AppUnifiedOrderParams,
7
+ OrderQueryParams,
8
+ RefundParams,
9
+ RefundQueryParams,
10
+ ReverseParams,
11
+ ReverseQueryParams,
12
+ } from "./params.js";
13
+ import {
14
+ JsapiUnifiedOrderResponse,
15
+ AggregateCodeUnifiedOrderResponse,
16
+ MiniProgramUnifiedOrderResponse,
17
+ H5UnifiedOrderResponse,
18
+ AppUnifiedOrderResponse,
19
+ OrderQueryResponse,
20
+ RefundResponse,
21
+ RefundQueryResponse,
22
+ ReverseResponse,
23
+ ReverseQueryResponse,
24
+ } from "./responses.js";
25
+
26
+ /**
27
+ * 每操作一个 Request 类,携带 funcode/version/path/签名字段名/excludeSignType 元数据。
28
+ * 不使用集中式 Requests 工厂(已在设计评审中否决)。
29
+ */
30
+ export class IpaynowRequest {
31
+ /**
32
+ * @param {{funcode: string, version: string, path?: string, signTypeField: string,
33
+ * excludeSignType?: boolean, responseClass: Function, params: {toFields: () => Record<string, string>}}} options
34
+ */
35
+ constructor({ funcode, version, path = "/", signTypeField, excludeSignType = false, responseClass, params }) {
36
+ this.funcode = funcode;
37
+ this.version = version;
38
+ this.path = path;
39
+ this.signTypeField = signTypeField;
40
+ this.excludeSignType = excludeSignType;
41
+ this.responseClass = responseClass;
42
+ this.params = params;
43
+ }
44
+
45
+ get mhtCharset() {
46
+ return "UTF-8";
47
+ }
48
+
49
+ get signatureField() {
50
+ return "mhtSignature";
51
+ }
52
+
53
+ get responseSignatureField() {
54
+ return "signature";
55
+ }
56
+
57
+ /** @returns {Record<string, string>} */
58
+ toFields() {
59
+ return this.params.toFields();
60
+ }
61
+ }
62
+
63
+ /** @param {string|{version?: string}} [override] */
64
+ function resolveVersion(defaultVersion, override) {
65
+ if (typeof override === "string") return override;
66
+ if (override && typeof override === "object" && override.version) return override.version;
67
+ return defaultVersion;
68
+ }
69
+
70
+ /** JSAPI 统一下单请求(funcode=WP001, version=1.0.0, path=/) */
71
+ export class JsapiUnifiedOrderRequest extends IpaynowRequest {
72
+ /**
73
+ * @param {JsapiUnifiedOrderParams|object} params
74
+ * @param {string|{version?: string}} [versionOrOptions]
75
+ */
76
+ constructor(params, versionOrOptions) {
77
+ const p = params instanceof JsapiUnifiedOrderParams ? params : new JsapiUnifiedOrderParams(params);
78
+ super({
79
+ funcode: "WP001",
80
+ version: resolveVersion("1.0.0", versionOrOptions),
81
+ path: "/",
82
+ signTypeField: "mhtSignType",
83
+ excludeSignType: false,
84
+ responseClass: JsapiUnifiedOrderResponse,
85
+ params: p,
86
+ });
87
+ }
88
+ }
89
+
90
+ /** 聚合码统一下单请求(funcode=WP001, version=1.0.3, path=/) */
91
+ export class AggregateCodeUnifiedOrderRequest extends IpaynowRequest {
92
+ /**
93
+ * @param {AggregateCodeUnifiedOrderParams|object} params
94
+ * @param {string|{version?: string}} [versionOrOptions]
95
+ */
96
+ constructor(params, versionOrOptions) {
97
+ const p = params instanceof AggregateCodeUnifiedOrderParams ? params : new AggregateCodeUnifiedOrderParams(params);
98
+ super({
99
+ funcode: "WP001",
100
+ version: resolveVersion("1.0.3", versionOrOptions),
101
+ path: "/",
102
+ signTypeField: "mhtSignType",
103
+ excludeSignType: false,
104
+ responseClass: AggregateCodeUnifiedOrderResponse,
105
+ params: p,
106
+ });
107
+ }
108
+ }
109
+
110
+ /** 小程序统一下单请求(funcode=WP001, version=1.0.0, path=/) */
111
+ export class MiniProgramUnifiedOrderRequest extends IpaynowRequest {
112
+ /**
113
+ * @param {MiniProgramUnifiedOrderParams|object} params
114
+ * @param {string|{version?: string}} [versionOrOptions]
115
+ */
116
+ constructor(params, versionOrOptions) {
117
+ const p = params instanceof MiniProgramUnifiedOrderParams ? params : new MiniProgramUnifiedOrderParams(params);
118
+ super({
119
+ funcode: "WP001",
120
+ version: resolveVersion("1.0.0", versionOrOptions),
121
+ path: "/",
122
+ signTypeField: "mhtSignType",
123
+ excludeSignType: false,
124
+ responseClass: MiniProgramUnifiedOrderResponse,
125
+ params: p,
126
+ });
127
+ }
128
+ }
129
+
130
+ /** H5 统一下单请求(funcode=WP001, version=1.0.0, path=/) */
131
+ export class H5UnifiedOrderRequest extends IpaynowRequest {
132
+ /**
133
+ * @param {H5UnifiedOrderParams|object} params
134
+ * @param {string|{version?: string}} [versionOrOptions]
135
+ */
136
+ constructor(params, versionOrOptions) {
137
+ const p = params instanceof H5UnifiedOrderParams ? params : new H5UnifiedOrderParams(params);
138
+ super({
139
+ funcode: "WP001",
140
+ version: resolveVersion("1.0.0", versionOrOptions),
141
+ path: "/",
142
+ signTypeField: "mhtSignType",
143
+ excludeSignType: false,
144
+ responseClass: H5UnifiedOrderResponse,
145
+ params: p,
146
+ });
147
+ }
148
+ }
149
+
150
+ /** APP 统一下单请求(funcode=WP001, version=1.0.3, path=/) */
151
+ export class AppUnifiedOrderRequest extends IpaynowRequest {
152
+ /**
153
+ * @param {AppUnifiedOrderParams|object} params
154
+ * @param {string|{version?: string}} [versionOrOptions]
155
+ */
156
+ constructor(params, versionOrOptions) {
157
+ const p = params instanceof AppUnifiedOrderParams ? params : new AppUnifiedOrderParams(params);
158
+ super({
159
+ funcode: "WP001",
160
+ version: resolveVersion("1.0.3", versionOrOptions),
161
+ path: "/",
162
+ signTypeField: "mhtSignType",
163
+ excludeSignType: false,
164
+ responseClass: AppUnifiedOrderResponse,
165
+ params: p,
166
+ });
167
+ }
168
+ }
169
+
170
+ /** 订单查询请求(funcode=MQ002, version=1.0.0,可被 params.version 或构造覆盖,path=/) */
171
+ export class OrderQueryRequest extends IpaynowRequest {
172
+ /**
173
+ * @param {OrderQueryParams|object} params
174
+ * @param {string|{version?: string}} [versionOrOptions]
175
+ */
176
+ constructor(params, versionOrOptions) {
177
+ const p = params instanceof OrderQueryParams ? params : new OrderQueryParams(params);
178
+ const version = resolveVersion(p.version || "1.0.0", versionOrOptions);
179
+ super({
180
+ funcode: "MQ002",
181
+ version,
182
+ path: "/",
183
+ signTypeField: "mhtSignType",
184
+ excludeSignType: false,
185
+ responseClass: OrderQueryResponse,
186
+ params: p,
187
+ });
188
+ }
189
+ }
190
+
191
+ /** 退款请求(funcode=R001, version=1.0.0, path=/refund/refundOrder, signType 不参与签名) */
192
+ export class RefundRequest extends IpaynowRequest {
193
+ /**
194
+ * @param {RefundParams|object} params
195
+ * @param {string|{version?: string}} [versionOrOptions]
196
+ */
197
+ constructor(params, versionOrOptions) {
198
+ const p = params instanceof RefundParams ? params : new RefundParams(params);
199
+ super({
200
+ funcode: "R001",
201
+ version: resolveVersion("1.0.0", versionOrOptions),
202
+ path: "/refund/refundOrder",
203
+ signTypeField: "signType",
204
+ excludeSignType: true,
205
+ responseClass: RefundResponse,
206
+ params: p,
207
+ });
208
+ }
209
+ }
210
+
211
+ /** 退款查询请求(funcode=Q001, version=1.0.0, path=/refund/refundQuery, signType 不参与签名) */
212
+ export class RefundQueryRequest extends IpaynowRequest {
213
+ /**
214
+ * @param {RefundQueryParams|object} params
215
+ * @param {string|{version?: string}} [versionOrOptions]
216
+ */
217
+ constructor(params, versionOrOptions) {
218
+ const p = params instanceof RefundQueryParams ? params : new RefundQueryParams(params);
219
+ super({
220
+ funcode: "Q001",
221
+ version: resolveVersion("1.0.0", versionOrOptions),
222
+ path: "/refund/refundQuery",
223
+ signTypeField: "signType",
224
+ excludeSignType: true,
225
+ responseClass: RefundQueryResponse,
226
+ params: p,
227
+ });
228
+ }
229
+ }
230
+
231
+ /** 撤销请求(funcode=R002, version=1.0.0, path=/refund/cancelOrder, signType 不参与签名) */
232
+ export class ReverseRequest extends IpaynowRequest {
233
+ /**
234
+ * @param {ReverseParams|object} params
235
+ * @param {string|{version?: string}} [versionOrOptions]
236
+ */
237
+ constructor(params, versionOrOptions) {
238
+ const p = params instanceof ReverseParams ? params : new ReverseParams(params);
239
+ super({
240
+ funcode: "R002",
241
+ version: resolveVersion("1.0.0", versionOrOptions),
242
+ path: "/refund/cancelOrder",
243
+ signTypeField: "signType",
244
+ excludeSignType: true,
245
+ responseClass: ReverseResponse,
246
+ params: p,
247
+ });
248
+ }
249
+ }
250
+
251
+ /** 撤销查询请求(funcode=Q002, version=1.0.0, path=/refund/refundQuery, signType 不参与签名) */
252
+ export class ReverseQueryRequest extends IpaynowRequest {
253
+ /**
254
+ * @param {ReverseQueryParams|object} params
255
+ * @param {string|{version?: string}} [versionOrOptions]
256
+ */
257
+ constructor(params, versionOrOptions) {
258
+ const p = params instanceof ReverseQueryParams ? params : new ReverseQueryParams(params);
259
+ super({
260
+ funcode: "Q002",
261
+ version: resolveVersion("1.0.0", versionOrOptions),
262
+ path: "/refund/refundQuery",
263
+ signTypeField: "signType",
264
+ excludeSignType: true,
265
+ responseClass: ReverseQueryResponse,
266
+ params: p,
267
+ });
268
+ }
269
+ }