支付
cool-admin 自带封装了微信和支付宝支付
微信支付
适用微信支付接口 v3
1、安装插件
shell
npm install @cool-midway/pay
2、引入插件
src/configuration.ts
ts
import { App, Configuration } from "@midwayjs/decorator";
import { ILifeCycle, IMidwayContainer } from "@midwayjs/core";
import { Application } from "egg";
import * as orm from "@midwayjs/orm";
import * as cool from "@cool-midway/core";
import * as pay from "@cool-midway/pay";
@Configuration({
// 注意组件顺序 cool 有依赖orm组件, 所以必须放在,orm组件之后 cool的其他组件必须放在cool 核心组件之后
imports: [pay],
})
export class ContainerLifeCycle {
@App()
app: Application;
// 应用启动完成
async onReady(container?: IMidwayContainer) {}
// 应用停止
async onStop() {}
}
3、配置
也可以在src/config/xxx.ts
配置(两种配置都存在,此种方式优先)
ts
config.cool = {
pay: {
wx: {
appid: "公众号ID",
mchid: "微信商户号",
publicKey: require("fs").readFileSync("公钥证书文件路径"),
privateKey: require("fs").readFileSync("私钥证书文件路径"),
notify_url: "支付回调地址",
key: "可选参数 APIv3密钥",
},
},
};
4、API
其他支付方式可以参考wechatpay-node-v3
支付宝支付
1、安装插件
shell
@cool-midway/pay
2、引入插件
src/configuration.ts
ts
import { App, Configuration } from "@midwayjs/decorator";
import { ILifeCycle, IMidwayContainer } from "@midwayjs/core";
import { Application } from "egg";
import * as orm from "@midwayjs/orm";
import * as cool from "@cool-midway/core";
import * as pay from "@cool-midway/pay";
@Configuration({
// 注意组件顺序 cool 有依赖orm组件, 所以必须放在,orm组件之后 cool的其他组件必须放在cool 核心组件之后
imports: [pay],
})
export class ContainerLifeCycle {
@App()
app: Application;
// 应用启动完成
async onReady(container?: IMidwayContainer) {}
// 应用停止
async onStop() {}
}
3、配置
也可以在src/config/xxx.ts
配置(两种配置都存在,此种方式优先)
ts
config.cool = {
pay: {
ali: {
notifyUrl: "https://xxx/app/order/pay/aliNotify",
appId: "xxxxxx",
privateKey: fs.readFileSync(
path.resolve("./src/modules/order/pem/ali/privateKey.pem"),
"ascii"
),
keyType: "PKCS1",
appCertPath: path.resolve(
"./src/modules/order/pem/ali/appCertPublicKey.crt"
),
alipayRootCertPath: path.resolve(
"./src/modules/order/pem/ali/alipayRootCert.crt"
),
alipayPublicCertPath: path.resolve(
"./src/modules/order/pem/ali/alipayCertPublicKey_RSA2.crt"
),
},
},
};
WARNING
注意私钥需要用支付宝密钥工具转成 PKCS1 格式
4、API
其他支付方式可以参考alipay-sdk
DEMO 示例
Controller
,需要注意开放回调接口,不要对其进行 token 校验
ts
import {
CoolController,
BaseController,
CoolUrlTag,
TagTypes,
} from "@cool-midway/core";
import { Body, Inject, Post } from "@midwayjs/core";
import { OrderPayService } from "../../service/pay";
/**
* 支付
*/
@CoolUrlTag({
key: TagTypes.IGNORE_TOKEN,
value: ["wxNotify", "aliNotify"],
})
@CoolController()
export class AppOrderPayController extends BaseController {
@Inject()
orderPayService: OrderPayService;
@Post("/aliNotify", { summary: "支付宝支付回调通知" })
async aliNotify(@Body() body) {
this.orderPayService.aliNotify(body);
return "success";
}
@Post("/aliQrcode", { summary: "支付宝扫码支付" })
async aliQrcode(
@Body("orderId") orderId: number,
@Body("width") width: number
) {
return this.ok(await this.orderPayService.aliQrcode(orderId, width));
}
@Post("/aliApp", { summary: "支付宝APP支付" })
async aliApp(@Body("orderId") orderId: number) {
return this.ok(await this.orderPayService.aliApp(orderId));
}
@Post("/wxApp", { summary: "微信APP支付" })
async wxApp(@Body("orderId") orderId: number) {
return this.ok(await this.orderPayService.wxApp(orderId));
}
@Post("/wxNotify", { summary: "微信支付回调" })
async wxNotify(@Body() body) {
await this.orderPayService.wxNotify(body);
return "success";
}
@Post("/wxQrcode", { summary: "微信扫码支付" })
async wxQrcode(@Body() body) {
await this.orderPayService.wxQrcode(body);
return "success";
}
}
Service
ts
import { Config, Inject, Provide } from "@midwayjs/decorator";
import { BaseService, CoolCommException } from "@cool-midway/core";
import { InjectEntityModel } from "@midwayjs/typeorm";
import { Repository } from "typeorm";
import { OrderInfoEntity } from "../entity/info";
// @ts-ignore
import { sign } from "alipay-sdk/lib/util";
import { CoolWxPay, CoolAliPay } from "@cool-midway/pay";
// @ts-ignore
import AlipayFormData from "alipay-sdk/lib/form";
// @ts-ignore
import { Decimal } from "decimal.js";
import { UserVipService } from "../../user/service/vip";
import { SeesionSocketService } from "../../session/service/socket";
/**
* 支付
*/
@Provide()
export class OrderPayService extends BaseService {
@InjectEntityModel(OrderInfoEntity)
orderInfoEntity: Repository<OrderInfoEntity>;
@Config("appName")
appName: string;
// 微信支付
@Inject()
wxPay: CoolWxPay;
// 支付宝支付
@Inject()
aliPay: CoolAliPay;
@Inject()
userVipService: UserVipService;
@Inject()
seesionSocketService: SeesionSocketService;
@Inject()
ctx;
/**
* 微信APP支付
* @param orderId
* @returns
*/
async wxApp(orderId: number) {
const info = await this.orderInfo(orderId);
const params = {
description: `${this.appName}-订单`,
out_trade_no: info?.orderNum,
notify_url: this.wxPay.coolWxPay.notify_url,
amount: {
total: new Decimal(info.price).times(100).toNumber(),
},
};
const result = await this.wxPay.getInstance().transactions_app(params);
return result;
}
/**
* 微信二维码支付
* @param orderId
*/
async wxQrcode(orderId: number) {
const info = await this.orderInfo(orderId);
const params = {
description: `${this.appName}-订单`,
out_trade_no: info?.orderNum,
notify_url: this.wxPay.coolWxPay.notify_url,
amount: {
total: new Decimal(info.price).times(100).toNumber(),
},
};
const result = await this.wxPay.getInstance().transactions_native(params);
return result;
}
/**
* 微信退款
* @param order
*/
async wxRefund(order: OrderInfoEntity) {
const params = {
description: `${this.appName}-订单`,
out_trade_no: order.orderNum,
notify_url: this.wxPay.coolWxPay.notify_url,
amount: {
refund: new Decimal(order.refundAmount).times(100).toNumber(),
total: new Decimal(order.price).times(100).toNumber(),
},
};
const result = await this.wxPay.getInstance().transactions_app(params);
return result.status == "SUCCESS";
}
/**
* 订单信息
* @param orderId
*/
async orderInfo(orderId: number) {
const info = await this.orderInfoEntity.findOneBy({ id: orderId });
if (!info && info?.payStatus != 0) {
throw new CoolCommException("订单不存在或不是可支付的状态");
}
return info;
}
/**
* 支付宝App支付
* @param orderId
*/
async aliApp(orderId: number) {
const info = await this.orderInfo(orderId);
// 返回支付链接
const data = sign(
"alipay.trade.app.pay",
{
notifyUrl: this.aliPay.coolAlipay.notifyUrl,
bizContent: {
subject: `${this.appName}-订单`,
totalAmount: info.price,
outTradeNo: info.orderNum,
productCode: "QUICK_MSECURITY_PAY",
body: {},
},
},
this.aliPay.getInstance().config
);
const payInfo = new URLSearchParams(data).toString();
return payInfo;
}
/**
* 支付宝扫码支付
* @param orderId
*/
async aliQrcode(orderId: number, width = 400): Promise<any> {
const info = await this.orderInfo(orderId);
const formData = new AlipayFormData();
// 调用 setMethod 并传入 get,会返回可以跳转到支付页面的 url
formData.setMethod("get");
formData.addField("notifyUrl", this.aliPay.coolAlipay.notifyUrl);
formData.addField("bizContent", {
outTradeNo: info.orderNum,
productCode: "FAST_INSTANT_TRADE_PAY",
totalAmount: info.price,
subject: `${this.appName}-订单`,
qrPayMode: 4,
qrcodeWidth: width,
body: JSON.stringify({
orderId,
}),
});
// 返回支付链接
const result = await this.aliPay
.getInstance()
.exec("alipay.trade.page.pay", {}, { formData });
return result;
}
/**
* 支付宝支付回调通知
* @param data
*/
async aliNotify(data: any) {
// 检查签名
const check = await this.aliPay.signVerify(data);
if (check && data.trade_status == "TRADE_SUCCESS") {
await this.paySuccess(data.out_trade_no, 1);
}
}
/**
* 微信支付回调通知
*/
async wxNotify(body: any) {
const { ciphertext, associated_data, nonce } = body.resource;
const data: any = this.wxPay
.getInstance()
.decipher_gcm(ciphertext, associated_data, nonce);
const check = await this.wxPay.signVerify(this.ctx);
// 验签通过,处理业务逻辑
if (check && data.trade_state == "SUCCESS") {
await this.paySuccess(data.out_trade_no, 0);
}
}
/**
* 支付成功
* @param orderNum
* @param payWay
*/
async paySuccess(orderNum: string, payWay: number) {
await this.orderInfoEntity.update(
{ orderNum },
{ payStatus: 1, payWay, payTime: new Date() }
);
await this.userVipService.paySuccess(orderNum);
const order = await this.orderInfoEntity.findOneBy({ orderNum });
this.seesionSocketService.sendByUserId(order.userId, "paySuccess", order);
}
/**
* 订单号
* @param order
*/
async aliRefund(order: OrderInfoEntity) {
const result = await this.aliPay.getInstance().exec("alipay.trade.refund", {
bizContent: {
out_trade_no: order.orderNum,
refund_amount: order.price,
refund_reason: order.refundReason,
},
});
return result.code == "10000";
}
}