@jayfong/x-server 2.5.0 → 2.7.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/lib/_cjs/services/pay.js +75 -8
- package/lib/services/pay.d.ts +43 -2
- package/lib/services/pay.js +75 -8
- package/package.json +1 -1
package/lib/_cjs/services/pay.js
CHANGED
|
@@ -94,20 +94,80 @@ class PayService {
|
|
|
94
94
|
|
|
95
95
|
verifyNotifyData(data) {
|
|
96
96
|
try {
|
|
97
|
-
|
|
97
|
+
if (!data || typeof data !== 'object') {
|
|
98
|
+
return false;
|
|
99
|
+
} // 支付宝
|
|
100
|
+
// https://opendocs.alipay.com/open/270/105902
|
|
98
101
|
|
|
99
|
-
|
|
100
|
-
data.passback_params === 'alipay'
|
|
101
|
-
|
|
102
|
+
|
|
103
|
+
if (data.passback_params === 'alipay') {
|
|
104
|
+
var _this$alipaySdk;
|
|
105
|
+
|
|
106
|
+
if (!((_this$alipaySdk = this.alipaySdk) != null && _this$alipaySdk.checkNotifySign(data))) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
channelOrderNo: data.trade_no
|
|
112
|
+
};
|
|
113
|
+
} // 微信支付
|
|
114
|
+
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if (data.resource) {
|
|
118
|
+
const params = JSON.parse(this.wepayDecrypt(data.resource));
|
|
119
|
+
|
|
120
|
+
if (params.attach === 'wepay') {
|
|
121
|
+
return {
|
|
122
|
+
channelOrderNo: params.transaction_id
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return false;
|
|
102
130
|
} catch {
|
|
103
131
|
return false;
|
|
104
132
|
}
|
|
105
133
|
}
|
|
106
134
|
|
|
107
135
|
verifyNotifyDataOrFail(data, message) {
|
|
108
|
-
|
|
136
|
+
const res = this.verifyNotifyData(data);
|
|
137
|
+
|
|
138
|
+
if (!res) {
|
|
109
139
|
throw new _http_error.HttpError.BadRequest(message);
|
|
110
140
|
}
|
|
141
|
+
|
|
142
|
+
return res;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async getOrderInfo(payload) {
|
|
146
|
+
// 微信支付
|
|
147
|
+
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
|
|
148
|
+
if (payload.channel === 'wepay') {
|
|
149
|
+
const res = await this.wepayRequest(payload.orderNo ? `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${payload.orderNo}?mchid=${this.options.wepay.merchantId}` : `https://api.mch.weixin.qq.com/v3/pay/transactions/id/${payload.channelOrderNo}?mchid=${this.options.wepay.merchantId}`);
|
|
150
|
+
return {
|
|
151
|
+
channelOrderNo: res.transaction_id,
|
|
152
|
+
orderNo: res.out_trade_no,
|
|
153
|
+
status: res.trade_state === 'SUCCESS' ? 'success' : 'fail'
|
|
154
|
+
};
|
|
155
|
+
} // 支付宝
|
|
156
|
+
// https://opendocs.alipay.com/open/028woa?scene=common&pathHash=dbf247eb
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
const res = await this.alipaySdk.exec('alipay.trade.query', {
|
|
160
|
+
biz_content: payload.orderNo ? {
|
|
161
|
+
out_trade_no: payload.orderNo
|
|
162
|
+
} : {
|
|
163
|
+
trade_no: payload.channelOrderNo
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
return {
|
|
167
|
+
channelOrderNo: res.trade_no,
|
|
168
|
+
orderNo: res.out_trade_no,
|
|
169
|
+
status: res.trade_status === 'TRADE_SUCCESS' || res.trade_status === 'TRADE_FINISHED' ? 'success' : 'fail'
|
|
170
|
+
};
|
|
111
171
|
}
|
|
112
172
|
|
|
113
173
|
wepaySign(data) {
|
|
@@ -130,9 +190,10 @@ class PayService {
|
|
|
130
190
|
|
|
131
191
|
async wepayRequest(url, data) {
|
|
132
192
|
const path = url.replace(/^https?:\/\/[^/]+/, '');
|
|
133
|
-
const
|
|
193
|
+
const method = data == null ? 'GET' : 'POST';
|
|
194
|
+
const body = method === 'POST' ? JSON.stringify(data) : '';
|
|
134
195
|
const params = {
|
|
135
|
-
method:
|
|
196
|
+
method: method,
|
|
136
197
|
url: path,
|
|
137
198
|
time: String(Math.round(Date.now() / 1000)),
|
|
138
199
|
rand: Math.random().toString().substr(2, 12),
|
|
@@ -141,13 +202,19 @@ class PayService {
|
|
|
141
202
|
};
|
|
142
203
|
params.signature = this.wepaySign([params.method, params.url, params.time, params.rand, params.body]);
|
|
143
204
|
const Authorization = [`WECHATPAY2-SHA256-RSA2048 `, `mchid="${this.options.wepay.merchantId}",`, `nonce_str="${params.rand}",`, `signature="${params.signature}",`, `timestamp="${params.time}",`, `serial_no="${this.options.wepay.certificateSerialNumber}"`].join('');
|
|
144
|
-
const res = await _got.default.post(url, {
|
|
205
|
+
const res = method === 'POST' ? await _got.default.post(url, {
|
|
145
206
|
json: data,
|
|
146
207
|
headers: {
|
|
147
208
|
Authorization
|
|
148
209
|
},
|
|
149
210
|
responseType: 'json',
|
|
150
211
|
resolveBodyOnly: true
|
|
212
|
+
}) : await _got.default.get(url, {
|
|
213
|
+
headers: {
|
|
214
|
+
Authorization
|
|
215
|
+
},
|
|
216
|
+
responseType: 'json',
|
|
217
|
+
resolveBodyOnly: true
|
|
151
218
|
});
|
|
152
219
|
return res;
|
|
153
220
|
}
|
package/lib/services/pay.d.ts
CHANGED
|
@@ -64,6 +64,46 @@ export interface PayServicePrepareWepayResult {
|
|
|
64
64
|
paySign: string;
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
+
export interface PayServiceVerifyNotifyDataResult {
|
|
68
|
+
/**
|
|
69
|
+
* 渠道订单号。
|
|
70
|
+
*
|
|
71
|
+
* - 支付宝最长 `64` 位;
|
|
72
|
+
* - 微信支付最长 `32` 位。
|
|
73
|
+
*/
|
|
74
|
+
channelOrderNo: string;
|
|
75
|
+
}
|
|
76
|
+
export interface PayServiceGetOrderInfoPayload {
|
|
77
|
+
/**
|
|
78
|
+
* 渠道。
|
|
79
|
+
*/
|
|
80
|
+
channel: 'alipay' | 'wepay';
|
|
81
|
+
/**
|
|
82
|
+
* 商家订单号。
|
|
83
|
+
*/
|
|
84
|
+
orderNo?: string;
|
|
85
|
+
/**
|
|
86
|
+
* 渠道订单号。
|
|
87
|
+
*/
|
|
88
|
+
channelOrderNo?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface PayServiceGetOrderInfoResult {
|
|
91
|
+
/**
|
|
92
|
+
* 商家订单号。
|
|
93
|
+
*/
|
|
94
|
+
orderNo: string;
|
|
95
|
+
/**
|
|
96
|
+
* 渠道订单号。
|
|
97
|
+
*
|
|
98
|
+
* - 支付宝最长 `64` 位;
|
|
99
|
+
* - 微信支付最长 `32` 位。
|
|
100
|
+
*/
|
|
101
|
+
channelOrderNo: string;
|
|
102
|
+
/**
|
|
103
|
+
* 订单状态。
|
|
104
|
+
*/
|
|
105
|
+
status: 'success' | 'fail';
|
|
106
|
+
}
|
|
67
107
|
export declare class PayService implements BaseService {
|
|
68
108
|
private options;
|
|
69
109
|
serviceName: string;
|
|
@@ -71,8 +111,9 @@ export declare class PayService implements BaseService {
|
|
|
71
111
|
constructor(options: PayServiceOptions);
|
|
72
112
|
prepareAlipay(options: PayServicePrepareAlipayOptions): Promise<PayServicePrepareAlipayResult>;
|
|
73
113
|
prepareWepay(options: PayServicePrepareWepayOptions): Promise<PayServicePrepareWepayResult>;
|
|
74
|
-
verifyNotifyData(data: any):
|
|
75
|
-
verifyNotifyDataOrFail(data: any, message?: string):
|
|
114
|
+
verifyNotifyData(data: any): false | PayServiceVerifyNotifyDataResult;
|
|
115
|
+
verifyNotifyDataOrFail(data: any, message?: string): PayServiceVerifyNotifyDataResult;
|
|
116
|
+
getOrderInfo(payload: PayServiceGetOrderInfoPayload): Promise<PayServiceGetOrderInfoResult>;
|
|
76
117
|
private wepaySign;
|
|
77
118
|
private wepayDecrypt;
|
|
78
119
|
private wepayRequest;
|
package/lib/services/pay.js
CHANGED
|
@@ -82,20 +82,80 @@ export class PayService {
|
|
|
82
82
|
|
|
83
83
|
verifyNotifyData(data) {
|
|
84
84
|
try {
|
|
85
|
-
|
|
85
|
+
if (!data || typeof data !== 'object') {
|
|
86
|
+
return false;
|
|
87
|
+
} // 支付宝
|
|
88
|
+
// https://opendocs.alipay.com/open/270/105902
|
|
86
89
|
|
|
87
|
-
|
|
88
|
-
data.passback_params === 'alipay'
|
|
89
|
-
|
|
90
|
+
|
|
91
|
+
if (data.passback_params === 'alipay') {
|
|
92
|
+
var _this$alipaySdk;
|
|
93
|
+
|
|
94
|
+
if (!((_this$alipaySdk = this.alipaySdk) != null && _this$alipaySdk.checkNotifySign(data))) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
channelOrderNo: data.trade_no
|
|
100
|
+
};
|
|
101
|
+
} // 微信支付
|
|
102
|
+
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_5.shtml
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if (data.resource) {
|
|
106
|
+
const params = JSON.parse(this.wepayDecrypt(data.resource));
|
|
107
|
+
|
|
108
|
+
if (params.attach === 'wepay') {
|
|
109
|
+
return {
|
|
110
|
+
channelOrderNo: params.transaction_id
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false;
|
|
90
118
|
} catch {
|
|
91
119
|
return false;
|
|
92
120
|
}
|
|
93
121
|
}
|
|
94
122
|
|
|
95
123
|
verifyNotifyDataOrFail(data, message) {
|
|
96
|
-
|
|
124
|
+
const res = this.verifyNotifyData(data);
|
|
125
|
+
|
|
126
|
+
if (!res) {
|
|
97
127
|
throw new HttpError.BadRequest(message);
|
|
98
128
|
}
|
|
129
|
+
|
|
130
|
+
return res;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async getOrderInfo(payload) {
|
|
134
|
+
// 微信支付
|
|
135
|
+
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_2.shtml
|
|
136
|
+
if (payload.channel === 'wepay') {
|
|
137
|
+
const res = await this.wepayRequest(payload.orderNo ? `https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/${payload.orderNo}?mchid=${this.options.wepay.merchantId}` : `https://api.mch.weixin.qq.com/v3/pay/transactions/id/${payload.channelOrderNo}?mchid=${this.options.wepay.merchantId}`);
|
|
138
|
+
return {
|
|
139
|
+
channelOrderNo: res.transaction_id,
|
|
140
|
+
orderNo: res.out_trade_no,
|
|
141
|
+
status: res.trade_state === 'SUCCESS' ? 'success' : 'fail'
|
|
142
|
+
};
|
|
143
|
+
} // 支付宝
|
|
144
|
+
// https://opendocs.alipay.com/open/028woa?scene=common&pathHash=dbf247eb
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
const res = await this.alipaySdk.exec('alipay.trade.query', {
|
|
148
|
+
biz_content: payload.orderNo ? {
|
|
149
|
+
out_trade_no: payload.orderNo
|
|
150
|
+
} : {
|
|
151
|
+
trade_no: payload.channelOrderNo
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
channelOrderNo: res.trade_no,
|
|
156
|
+
orderNo: res.out_trade_no,
|
|
157
|
+
status: res.trade_status === 'TRADE_SUCCESS' || res.trade_status === 'TRADE_FINISHED' ? 'success' : 'fail'
|
|
158
|
+
};
|
|
99
159
|
}
|
|
100
160
|
|
|
101
161
|
wepaySign(data) {
|
|
@@ -116,9 +176,10 @@ export class PayService {
|
|
|
116
176
|
|
|
117
177
|
async wepayRequest(url, data) {
|
|
118
178
|
const path = url.replace(/^https?:\/\/[^/]+/, '');
|
|
119
|
-
const
|
|
179
|
+
const method = data == null ? 'GET' : 'POST';
|
|
180
|
+
const body = method === 'POST' ? JSON.stringify(data) : '';
|
|
120
181
|
const params = {
|
|
121
|
-
method:
|
|
182
|
+
method: method,
|
|
122
183
|
url: path,
|
|
123
184
|
time: String(Math.round(Date.now() / 1000)),
|
|
124
185
|
rand: Math.random().toString().substr(2, 12),
|
|
@@ -127,13 +188,19 @@ export class PayService {
|
|
|
127
188
|
};
|
|
128
189
|
params.signature = this.wepaySign([params.method, params.url, params.time, params.rand, params.body]);
|
|
129
190
|
const Authorization = [`WECHATPAY2-SHA256-RSA2048 `, `mchid="${this.options.wepay.merchantId}",`, `nonce_str="${params.rand}",`, `signature="${params.signature}",`, `timestamp="${params.time}",`, `serial_no="${this.options.wepay.certificateSerialNumber}"`].join('');
|
|
130
|
-
const res = await got.post(url, {
|
|
191
|
+
const res = method === 'POST' ? await got.post(url, {
|
|
131
192
|
json: data,
|
|
132
193
|
headers: {
|
|
133
194
|
Authorization
|
|
134
195
|
},
|
|
135
196
|
responseType: 'json',
|
|
136
197
|
resolveBodyOnly: true
|
|
198
|
+
}) : await got.get(url, {
|
|
199
|
+
headers: {
|
|
200
|
+
Authorization
|
|
201
|
+
},
|
|
202
|
+
responseType: 'json',
|
|
203
|
+
resolveBodyOnly: true
|
|
137
204
|
});
|
|
138
205
|
return res;
|
|
139
206
|
}
|