Skip to content

Commit

Permalink
Merge pull request #13 from notadd/develop
Browse files Browse the repository at this point in the history
chore(release): publish v0.4.0
  • Loading branch information
dzzzzzy authored Dec 10, 2018
2 parents 1ffa36f + 09807e4 commit 28bc3c4
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 24 deletions.
25 changes: 22 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import { PayAddon } from '@notadd/addon-pay';
appid: 'appid', // 公众号appi/应用appid/小程序appid
mch_id: 'mch_id', // 商户号
secretKey: 'secretKey', // 商户交易秘钥
sign_type: 'MD5', // 微信支付签名类型('MD5' | 'HMAC-SHA256'),默认MD5,配置后,所有接口参数均会使用这个签名类型
pfx: fs.readFileSync('path_to_p12_file'), // p12文件
sandbox: true // 是否启用沙箱环境,默认不启用
sandbox: true // 是否启用沙箱环境,默认不启用,用于商户支付验收测试
}
})
]
Expand All @@ -32,9 +33,27 @@ export class ApplicationModule {}

### 微信支付

接口使用前的必要声明:

1. 所有的接口请求参数和接口返回结果中的属性名全部使用的是 **`snake_case`**,其中属性名结尾带 **`?`** 的代表这个属性是可选的(非必填)。
2. 所有与金额相关的数据全部是 **`number`** 类型且单位为 **``**,需自行转换。
3. 所有接口参数中的 `mch_id``appid/wxappid``nonce_str``sign_type``sign` 数据均由插件自动填入,无需手动传入。
4. 所有请求的返回结果若有 `sign`,插件会自动验签。
5. 支付通知结果插件会自动验签,退款通知结果插件会自动解密 `req_info` 数据。

#### 使用 WeChat`XXX`PayService 调用 API

WeChat`XXX`PayService 类包含当前支付方式的支付、订单、退款相关 API,调用方式如下(扫码支付):
WeChat`XXX`PayService 类包含当前支付方式的支付、订单、退款相关 API,各支付类说明:

- WeChatAppPayService —— APP支付
- WeChatAppletPayService —— 小程序支付
- WeChatJSAPIPayService —— JSAPI支付(用户通过微信扫码、关注公众号等方式进入商家H5页面,并在微信内调用JSSDK完成支付)
- WeChatMicroPayService —— 付款码支付(用户打开微信钱包-付款码的界面,商户扫码后提交完成支付)
- WeChatNativePayService —— Native支付(扫码支付)
- WeChatWapPayService —— H5支付(用户在微信以外的手机浏览器请求微信支付的场景唤起微信支付)
- WeChatRedpackService —— 现金红包

例子:Native支付(扫码支付)调用方式如下

```typescript
import { Injectable, Inject } from '@nestjs/common';
Expand Down Expand Up @@ -139,7 +158,7 @@ export class PaymentNotifyController {
- [x] **0.1.0** 微信-普通商户版-APP支付
- [x] **0.2.0** 微信-普通商户版-JSAPI支付、微信-普通商户版-Native支付、微信-普通商户版-H5支付、微信-普通商户版-小程序支付
- [x] **0.3.0** 微信-普通商户版-付款码支付
- [ ] **0.4.0** 微信-普通商户版-现金红包
- [x] **0.4.0** 微信-普通商户版-现金红包
- [ ] **0.5.0** 微信-普通商户版-企业付款
- [ ] **0.6.0** 支付宝-APP支付
- [ ] **0.7.0** 支付宝-当面付
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nt-addon-pay",
"version": "0.3.2",
"version": "0.4.0",
"description": "The pay addon for notadd application",
"scripts": {
"start": "ts-node -r tsconfig-paths/register starter/main.ts",
Expand Down
1 change: 1 addition & 0 deletions src/modules/wechat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export * from './services/jsapi.pay.service';
export * from './services/micro.pay.service';
export * from './services/native.pay.service';
export * from './services/wap.pay.service';
export * from './services/redpack.service';
export * from './enums/trade-type.enum';
export * from './utils/notify-parser.util';
163 changes: 163 additions & 0 deletions src/modules/wechat/interfaces/redpack.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/** 微信支付发放红包接口请求参数 */
export interface WeChatRedpackReqParam {
/** 商户订单号 */
mch_billno: string;
/** 商户名称 */
send_name: string;
/** 用户openid */
re_openid: string;
/** 总金额 */
total_amount: number;
/** 红包发放总人数 */
total_num: number;
/** 红包祝福语 */
wishing: string;
/** ip地址 */
client_ip: string;
/** 活动名称 */
act_name: string;
/** 备注 */
remark: string;
/**
* 场景id
*
* 发放红包使用场景,红包金额大于200或者小于1元时必传
*
* PRODUCT_1:商品促销
*
* PRODUCT_2:抽奖
*
* PRODUCT_3:虚拟物品兑奖
*
* PRODUCT_4:企业内部福利
*
* PRODUCT_5:渠道分润
*
* PRODUCT_6:保险回馈
*
* PRODUCT_7:彩票派奖
*
* PRODUCT_8:税务刮奖
*/
scene_id?: string;
/** 活动信息 */
rish_info?: string;
/** 资金授权商户号 */
consume_mch_id?: string;
}

/** 微信支付发放普通红包接口返回结果 */
export interface WeChatRedpackRes {
/** 返回状态码 */
return_code: string;
/** 返回信息 */
return_msg: string;
/** 业务结果 */
result_code: string;
/** 错误代码 */
err_code?: string;
/** 错误代码描述 */
err_code_des?: string;
/** 商户订单号 */
mch_billno: string;
/** 商户号 */
mch_id: string;
/** 公众账号APPID */
wxappid: string;
/** 用户openid */
re_openid: string;
/** 总金额 */
total_amount: number;
/** 微信单号 */
send_listid: string;
}

/** 微信支付查询红包记录接口请求参数 */
export interface WeChatQueryRedpackRecordReqParam {
/** 商户订单号 */
mch_billno: string;
}

/** 微信支付查询红包记录接口返回结果 */
export interface WeChatQueryRedpackRecordRes {
/** 返回状态码 */
return_code: string;
/** 返回信息 */
return_msg: string;
/** 业务结果 */
result_code: string;
/** 错误代码 */
err_code?: string;
/** 错误代码描述 */
err_code_des?: string;
/** 商户订单号 */
mch_billno: string;
/** 商户号 */
mch_id: string;
/** 红包单号 */
detail_id: string;
/**
* 红包状态
*
* SENDING:发放中
*
* SENT:已发放待领取
*
* FAILED:发放失败
*
* RECEIVED:已领取
*
* RFUND_ING:退款中
*
* REFUND:已退款
*/
status: string;
/**
* 发放类型
*
* API:通过API接口发放
*
* UPLOAD:通过上传文件方式发放
*
* ACTIVITY:通过活动方式发放
*/
send_type: string;
/**
* 红包类型
*
* GROUP:裂变红包
*
* NORMAL:普通红包
*/
hb_type: string;
/** 红包个数 */
total_num: number;
/** 红包总金额 */
total_amount: number;
/** 失败原因 */
reason?: string;
/** 红包发送时间 */
send_time: string;
/** 红包退款时间 */
refund_time?: string;
/** 红包退款金额 */
refund_amount?: number;
/** 祝福语 */
wishing?: string;
/** 活动描述 */
remark?: string;
/** 活动名称 */
act_name?: string;
/** 裂变红包领取列表 */
hblist?: { hbinfo: WeChatGroupRedpackReceiveInfo[] };
}

/** 微信支付裂变红包接收记录信息 */
interface WeChatGroupRedpackReceiveInfo {
/** 领取红包的openid */
openid: string;
/** 领取金额 */
amount: number;
/** 接收时间 */
rcv_time: string;
}
15 changes: 1 addition & 14 deletions src/modules/wechat/services/base.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class WeChatPayBaseService {
protected readonly downloadFundFlowUrl = `${this.apiBase}/pay/downloadfundflow`;

constructor(
@Inject(WeChatPayConfigProvider) private readonly config: WeChatPayConfig,
@Inject(WeChatPayConfigProvider) protected readonly config: WeChatPayConfig,
@Inject(WeChatPayCertificateAgentProvider) protected readonly certificateAgent: https.Agent,
@Inject(WeChatRequestUtil) protected readonly requestUtil: WeChatRequestUtil
) { }
Expand All @@ -52,7 +52,6 @@ export class WeChatPayBaseService {
*/
public async queryOrder(params: WeChatBaseQueryOrderReqParam): Promise<WeChatBaseQueryOrderRes> {
if (!params.out_trade_no && !params.transaction_id) throw new Error('参数有误,out_trade_no 和 transaction_id 二选一');
this.checkOverrideDefaultSignType(params);
return await this.requestUtil.post<WeChatBaseQueryOrderRes>(this.queryOrderUrl, params);
}

Expand All @@ -62,7 +61,6 @@ export class WeChatPayBaseService {
* @param params 关闭订单请求参数
*/
public async closeOrder(params: WeChatBaseCloseOrderReqParam): Promise<WeChatBaseCloseOrderRes> {
this.checkOverrideDefaultSignType(params);
return await this.requestUtil.post<WeChatBaseCloseOrderRes>(this.closeOrderUrl, params);
}

Expand All @@ -73,7 +71,6 @@ export class WeChatPayBaseService {
*/
public async refund(params: WeChatBaseRefundReqParam): Promise<WeChatBaseRefundRes> {
if (!params.out_trade_no && !params.transaction_id) throw new Error('参数有误,out_trade_no 和 transaction_id 二选一');
this.checkOverrideDefaultSignType(params);
return await this.requestUtil.post<WeChatBaseRefundRes>(this.refundUrl, params, { httpsAgent: this.certificateAgent });
}

Expand All @@ -88,14 +85,4 @@ export class WeChatPayBaseService {
}
return await this.requestUtil.post<WeChatBaseQueryRefundRes>(this.refundQueryUrl, params);
}

/**
* 检查是否覆盖默认的签名类型
*/
protected checkOverrideDefaultSignType(params: any) {
const signType = this.config.sign_type;
if (signType) {
(params as any).sign_type = signType;
}
}
}
1 change: 0 additions & 1 deletion src/modules/wechat/services/micro.pay.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export class WeChatMicroPayService extends WeChatPayBaseService {
*/
async closeOrder(params: WeChatMicroPayReverseOrderReqParam): Promise<WeChatMicroPayReverseOrderRes> {
const url = `${this.apiBase}/pay/reverse`;
this.checkOverrideDefaultSignType(params);
return await this.requestUtil.post<WeChatMicroPayReverseOrderRes>(url, params, { httpsAgent: this.certificateAgent });
}
}
51 changes: 51 additions & 0 deletions src/modules/wechat/services/redpack.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Injectable } from '@nestjs/common';

import {
WeChatQueryRedpackRecordReqParam,
WeChatQueryRedpackRecordRes,
WeChatRedpackReqParam,
WeChatRedpackRes
} from '../interfaces/redpack.interface';
import { WeChatPayBaseService } from './base.service';

/**
* 微信支付-现金红包支付类
*/
@Injectable()
export class WeChatRedpackService extends WeChatPayBaseService {
private readonly redpackApiBase = 'https://api.mch.weixin.qq.com' + (this.config.sandbox ? '/sandboxnew' : '') + '/mmpaymkttransfers';
private readonly sendredpackUrl = `${this.redpackApiBase}/sendredpack`;
private readonly sendgroupredpackUrl = `${this.redpackApiBase}/sendgroupredpack`;
private readonly gethbinfoUrl = `${this.redpackApiBase}/gethbinfo`;

/**
* 发放普通红包
*
* @param params 发放普通红包请求参数
*/
async sendRedpack(params: WeChatRedpackReqParam): Promise<WeChatRedpackRes> {
(params as any).wxappid = '';
return await this.requestUtil.post<WeChatRedpackRes>(this.sendredpackUrl, params, { httpsAgent: this.certificateAgent });
}

/**
* 发放裂变红包
*
* @param params 发放裂变红包请求参数
*/
async sendGroupRedpack(params: WeChatRedpackReqParam): Promise<WeChatRedpackRes> {
(params as any).wxappid = '';
(params as any).amt_type = 'ALL_RAND';
return await this.requestUtil.post<WeChatRedpackRes>(this.sendgroupredpackUrl, params, { httpsAgent: this.certificateAgent });
}

/**
* 查询红包记录
*
* @param params 查询红包记录请求参数
*/
async queryRedpackRecord(params: WeChatQueryRedpackRecordReqParam): Promise<WeChatQueryRedpackRecordRes> {
(params as any).bill_type = 'MCHT';
return await this.requestUtil.post<WeChatQueryRedpackRecordRes>(this.gethbinfoUrl, params, { httpsAgent: this.certificateAgent });
}
}
15 changes: 10 additions & 5 deletions src/modules/wechat/utils/request.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,20 @@ export class WeChatRequestUtil {
* @param config AxiosRequestConfig
*/
async post<T>(url: string, params: any, config?: axios.AxiosRequestConfig): Promise<T> {
const wechatConfig = this.config;
params.appid = wechatConfig.appid;
params.mch_id = wechatConfig.mch_id;
// 现金红包特例 wxappid
if (Object.keys(params).includes('wxappid')) {
params.wxappid = this.config.appid;
} else {
params.appid = this.config.appid;
}
params.mch_id = this.config.mch_id;
params.nonce_str = this.randomUtil.genRandomStr();
params.sign = this.signUtil.sign(params, wechatConfig.secretKey, wechatConfig.sign_type);
params.sign_type = this.config.sign_type ? this.config.sign_type : 'MD5';
params.sign = this.signUtil.sign(params, this.config.secretKey, this.config.sign_type);
try {
const { data } = await this.httpService.post<T>(url, this.xmlUtil.convertObjToXml(params), config).toPromise();
if ((data as any).return_code === 'SUCCESS') {
if (params.sign !== (data as any).sign) throw new Error('微信支付接口返回签名有误');
if (params.sign && params.sign !== (data as any).sign) throw new Error('微信支付接口返回签名有误');
}
return this.xmlUtil.parseObjFromXml<T>(data);
} catch (error) {
Expand Down
3 changes: 3 additions & 0 deletions src/modules/wechat/wechat.pay.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { WeChatPayBaseService } from './services/base.service';
import { WeChatJSAPIPayService } from './services/jsapi.pay.service';
import { WeChatMicroPayService } from './services/micro.pay.service';
import { WeChatNativePayService } from './services/native.pay.service';
import { WeChatRedpackService } from './services/redpack.service';
import { WeChatWapPayService } from './services/wap.pay.service';
import { WeChatNotifyParserUtil } from './utils/notify-parser.util';
import { WeChatRequestUtil } from './utils/request.util';
Expand Down Expand Up @@ -42,6 +43,7 @@ export class WeChatPayModule implements OnModuleInit {
WeChatMicroPayService,
WeChatNativePayService,
WeChatWapPayService,
WeChatRedpackService,
WeChatSignUtil,
WeChatRequestUtil,
WeChatNotifyParserUtil,
Expand All @@ -55,6 +57,7 @@ export class WeChatPayModule implements OnModuleInit {
WeChatMicroPayService,
WeChatNativePayService,
WeChatWapPayService,
WeChatRedpackService,
WeChatNotifyParserUtil
]
};
Expand Down

0 comments on commit 28bc3c4

Please sign in to comment.