微信小程序-NestJS之微信支付

943 阅读3分钟

48645468.jpg

1. 准备环节

// 这些都需要在微信后台自行申请,[微信开发者平台](https://mp.weixin.qq.com)
appid:string         // 小程序ID
mchid:string         // 商户号
apiclient_cert.pem   // 公钥
apiclient_key.pem    // 秘钥
v3                   // 微信支付结果的解密密钥, 需要在开发者平台自行设置

需要这两个与支付相关的依赖库 wechatpay-node-v3 , nest-wechatpay-node-v3

yarn add wechatpay-node-v3 nest-wechatpay-node-v3

2.支付流程

2.1 登录

这里我们就不细说了,不会可以自行百度.登录完成之后,小程序会拿到当前微信用户的uuid, openid

2.2 小程序发起一个预支付请求,请求nestjs后台接口

// 小程序端请求参数
const options = {
        appid: 'xxx',           // 小程序appid
        payer: uuid,            // 微信账号的uuid
        openid: openid,         // 微信账号的uuid
        amount: '',             // 支付金额
        orderNo:'3123123123'    // 关于这个订单编号, 保证唯一即可,这里选择前端生成, 也可后端生成,商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一。 特殊规则:最小字符长度为6,
        description: '这是一段支付描述',
}

// 请求nestjs后台接口拿到相关参数调起微信支付
const res = wx.request(url, method, options)

wx.requestPayment({
    provider: 'wxpay', //支付类型-固定值
    timeStamp: res.data.timeStamp, // 时间戳(单位:秒)
    nonceStr: res.data.nonceStr, // 随机字符串
    package: res.data.package, // 固定值
    signType: res.data.signType, //固定值
    paySign: res.data.paySign, //签名
    success: function (res) {
        // 支付成功
    },
    fail: function (err) {
        // 支付失败
    },
})


// NestJs后台
payment.module.ts
import { WeChatPayModule } from 'nest-wechatpay-node-v3'
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
    imports: [
        // 这里配置一下
        WeChatPayModule.registerAsync({
            imports: [ConfigModule],
            inject: [ConfigService],
            useFactory: async (config: ConfigService) => {
                return {
                    appid: '直连商户申请的公众号或移动应用appid',
                    mchid: '商户号',
                    publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥
                    privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥
                }
            }
        }),
    ]
})

payment.service.ts
import WxPay from 'wechatpay-node-v3'
import { WECHAT_PAY_MANAGER } from 'nest-wechatpay-node-v3'

@Injectable()
export class PaymentService {
    constructor(
        @Inject(WECHAT_PAY_MANAGER)
        private readonly wxPay: WxPay,
    ) { }

    async prePayment(params:ParmentDto){
        //这里的params就是小程序传递的相关参数
        const { appid, payer, openid, description, amount, orderNo } = params
        const Fen = this.convertYuanToFen(Number(amount)) // 这里通过一个函数把钱转化为以分为单位的数字
        const options = {
            appid,
            mchid: '商户号',
            description,
            out_trade_no: orderNo,
            notify_url: '支付完成后微信将通过这个接口返回给你支付结果,必须保证是一个公网的域名,如:http://baidu.com/notify',
            amount: {
                total: Fen, // 转化后的数据
            },
            payer: {
                openid
            }
        }
        // TODO: 这里省略了将这条支付订单保存到数据库的步骤,请读者自行编写
        const res = await this.wxPay.transactions_jsapi(options) // 请求微信官方服务器
        return res // 这个res中就包含了小程序调起微信支付的相关参数
    }
    
    // 当微信官方收到上面的数据,将多次调用notify_url,将支付信息传递过来
    @Post()
    async notify_url(@Body() body: WxNotifyDto){
        // 这个body中是更私密的支付信息,我们通过解密之后才能拿到
        const v3 = '........' // 解密密钥
        const { resource } = body
        const { ciphertext, associated_data, nonce } = resource
        // out_trade_no 这个数据就是我们自行生成的支付的订单编号,可以根据这个查到此次支付信息
        const { out_trade_no } = await this.wxPay.decipher_gcm<TransactionResource>(ciphertext, associated_data, nonce, v3)
        
        // TODO: 需要根据返回的不同支付状态调整订单的支付状态
        
        // 到这里支付就算是完成了
    }
}