Here is to share with you a wechat payment server using egg

Creating an egg application

Initialize the egg application

npm init egg --type=simple
npm i
Copy the code

Second, configure the plug-in used by wechat Payment

Plugin.js necessary plug-in (egg-Weck-pay can be replaced by other plug-ins)

module.exports = {
 cors: {
   enable: true,
   package: 'egg-cors',
 },
 wechatPay: {
   enable: true,
   package: 'egg-wechat-pay'}};Copy the code

Configure middleware

Because the data returned by wechat Pay is in XML format, our parsing XML data cannot receive the request data of wechat Pay callback otherwise

Xmlparse.js (you can use koA’s other middleware)

 module.exports = require('co-wechat-body');
Copy the code

4. Configure config.default.js

Config. security = {CSRF: {enable: false,
        },
        domainWhiteList: [The '*'}// const fs = require('fs')
    const path = require('path')
    
    config.mpWeixin = {
        appid: ' ', wechat official account or short program serial number AppSecret:' 'The key Host:'https://api.weixin.qq.com/',
        MsgToken: ' ',
        EncodingAESKey: ' '
    }
    
    config.wechatPay = {
        client: {
            bodyPrefix: ' ',//
            appId: ' ',// Wechat official account or serial no. MerchantId:' ',// Store id secret:' ',// The merchant key notifyUrl:' ',// Pay successfully callback address REFUNDNotifyUrl:' 'PFX: fs.readfilesync (path.join(__dirname,'.. /app/public/wxpaly/apiclient_cert.p12'}, URLS: {UNIFIED_ORDER:'https://api.mch.weixin.qq.com/pay/unifiedorder',
            ORDER_QUERY: 'https://api.mch.weixin.qq.com/pay/orderquery',
            REFUND: 'https://api.mch.weixin.qq.com/secapi/pay/refund',
            REFUND_QUERY: 'https://api.mch.weixin.qq.com/pay/refundquery',
            DOWNLOAD_BILL: 'https://api.mch.weixin.qq.com/pay/downloadbill',
            SHORT_URL: 'https://api.mch.weixin.qq.com/tools/shorturl',
            CLOSE_ORDER: 'https://api.mch.weixin.qq.com/pay/closeorder',
            REDPACK_SEND: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack',
            REDPACK_QUERY: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo',
            TRANSFERS: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',
            TRANSFERS_QUERY: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo',}}Copy the code

Util. Js

const crypto = require('crypto');
const fs = require('fs')
const path = require('path')

functionRandomString (len) {// isFiniteif(! Number.isFinite(len)) { throw new TypeError('Expected a finite number');
  }
  return crypto.randomBytes(Math.ceil(len / 2)).toString('hex').slice(0, len);
}


function getSign(params, key, type = 'MD5') {// Pay the signature const paramsArr = object.keys (params); paramsArr.sort(); const stringArr = [] paramsArr.map(key => {if(key ! ='sign' && params[key])
      stringArr.push(key + '=' + params[key]);
  })
  if (type= ="MD5") {// Finally add merchant Key stringarr.push ("key=" + key)
    const string = stringArr.join('&');
    const MD5 = crypto.createHash('md5');
    return MD5.update(string).digest('hex').toUpperCase();
  } else {
    return crypto.createHmac('sha256', key)
      .update(stringArr.join('&'))
      .digest('hex').toUpperCase(); }}functionCheckSign (params, key) {// Check whether the signature is correct const {sign} = params; const Newsign = getSign(params, key)if (sign === Newsign) {
    return true
  } else {
    return false}}Copy the code

Write a Service

Payment.js

'use strict';
const Service = require('egg').Service;
const { randomString, ransign, getSign, checkSign, } = require('util.js')
const moment = require('moment');
const Decimal = require('decimal.js'); Class PaymentService extends Service {/** * H5 PaymentService extends Service {/** * H5 PaymentService extends Service {/** * H5 PaymentService extends Service {/** * H5 PaymentService extends Service {/** * H5 PaymentService @memberof PaymentService */ async pay(PayType, body, money) { const { ctx, service, app } = this;let No = Date.now();
        let OrderNo = moment().format('YYYYMMDDHHmm') + randomString(3) + No;
        let createTime = moment().format('YYYY-MM-DD HH:mm:ss');
        letOrder = {device_info:'WEB',
            body,
            out_trade_no: OrderNo,
            total_fee: new Decimal(money).mul(new Decimal(100)).toFixed(),
            attach: `${UserId}`};if (PayType == 'H5') {
            order.scene_info = JSON.stringify({
                h5_info: 'h5_info'.type: 'Wap',
                wap_url: this.config.h5host,
                wap_name: 'Payment for Summit Registration'
            })
        }
        const unifiedRes = await this.unifiedOrder(order, PayType == 'H5' ? 'MWEB' : 'NATIVE'); 
        returnAsync PayAction (params) {const {CTX, service, app} = this; Const {appid, // public ID bank_type, // payment bank cash_fee, // cash payment amount device_info, // device number fee_type, // currency type is_SUBSCRIBE, Openid, // user id out_trade_no, // merchant order number result_code, // business result return_code, // Return status code sign, // signature time_end, // payment completion time total_fee, // order amount trade_type, // transaction type transaction_id, // wechat payment order number attach} = params;if (return_code == "SUCCESS") {
            if(checkSign (params, enclosing the config. WechatPay. Client. The secret)) {/ / parse the callback data is properly conducted by / /}else {
                return {
                    msg: 'Signature error',
                    status: 'error',}}}else {
            return {
                msg: 'Payment failure',
                status: 'error'}} // async refund(out_trade_no,refund_fee,refund_desc,PayPrice) {const {CTX, service, app} = this;let nonce_str = randomString(32);
 
            let out_refund_no  = moment().format('YYYYMMDDHHmmss') + randomString(25);

            letdata = { appid: this.config.wechatPay.client.appId, mch_id: This. Config. WechatPay. Client. MerchantId, nonce_str, / / random string out_trade_no, / / order number out_refund_no, / / a refund order number total_fee: New Decimal(PayPrice).mul(new Decimal(100)).tofixed (),// Total amount refund_fee: New Decimal(refund_fee).mul(new Decimal(100)).tofixed (),// Refund amount refund_desc,// Refund reason description notify_url: This. Config. WechatPay. Client. REFUNDNotifyUrl / / refund success callback address}letsign = getSign(data, this.config.wechatPay.client.secret); / / signatureletxml = { ... data, sign }; try { const curlres = await ctx.curl(`${this.config.wechatPay.URLS.REFUND}`, {
                    method: 'POST', PFX: this config. WechatPay. Client. PFX, / / refund certificate passphrase: This. Config. WechatPay. Client. MerchantId, / / send the original XML data directly, don't need HttpClient do special handling the content: this.app.wechatPay.stringify(xml), });letrdata = await this.app.wechatPay.parse(curlres.data); // Parse XML datareturn {
                    res: rdata
                }
            } catch (error) {
                console.log(error, "error");
                if (error == "invalid refund_fee") {
                    return {
                        msg: 'Incorrect refund amount',
                        status: 'error',}}else {
                    return {
                        msg: 'Refund failed',
                        status: 'error'Async CreatePaymentInfo(Money, openID) {const {CTX, service, app} = this;}}}} // async CreatePaymentInfo(money, openID) {const {CTX, service, app} = this;let No = Date.now();
        let OrderNo = moment().format('YYYYMMDDHHmmss') + randomString(3) + No; Const order = {const order device_info:'WEB',
            body: ""Out_trade_no: OrderNo,// Order number total_fee: New Decimal(money).mul(new Decimal(100)).tofixed (),// The payment amount is divided into units openID,// user openID}; const res = await this.unifiedOrder(order); // Request to generate order informationreturn {
            res
        }
    }

    async unifiedOrder(order, trade_type = 'JSAPI') {
        const {
            ctx,
            service
        } = this;
        letnonce_str = randomString(32); // Random stringletData = { appid: this.config.wechatPay.client.appId, mch_id: This. Config. WechatPay. Client. MerchantId, / / nonce_str merchants, sign_type:'MD5',// Signature spbill_create_IP: ctx. IP,// user IP trade_type,// Payment type notify_URL: This. Config. WechatPay. Client. NotifyUrl, / / pay success callback address time_expire: my moment (). The add (1,'h').format('YYYYMMDDHHmmss'),
            ...order
        }

        letsign = getSign(Data, this.config.wechatPay.client.secret); / / signatureletxml = { ... Data, sign }; const cur = await ctx.curl(`${this.config.wechatPay.URLS.UNIFIED_ORDER}`, {
            method: 'POST', / / send the original XML data directly, don't need to deal with the content: HttpClient do special. This app. WechatPay. Stringify (XML)}); const parseData = await this.app.wechatPay.parse(cur.data);let res = {
            appId: Data.appid,
            nonceStr: nonce_str,
            package: `prepay_id=${parseData.prepay_id}`,
            timeStamp: moment().add(1, 'h').unix().toString(),
            signType: 'MD5',}if (trade_type == 'MWEB') {// pay res.mweb_url = parsedata.mweb_url}if (trade_type == 'NATIVE') {// Can be used to pay res.code_url = parsedata.code_url}return {
            ...res,
            paySign: getSign(res, this.config.wechatPay.client.secret)
        }
    }
    
}

module.exports = PaymentService;
Copy the code

The main code can basically achieve wechat payment server

Write of too rough HHH won’t write can stick code to have what problem can leave a message