【愚公系列】2022年10月 微信小程序-电商项目-微信支付后端功能实现(node版)

举报
愚公搬代码 发表于 2022/10/31 19:32:17 2022/10/31
【摘要】 前言微信支付是腾讯集团旗下的第三方支付平台,致力于为用户和企业提供安全、便捷、专业的在线支付服务。以“微信支付,不止支付”为核心理念,为个人用户创造了多种便民服务和应用场景。微信支付为各类企业以及小微商户提供专业的收款能力,运营能力,资金结算解决方案,以及安全保障。用户可以使用微信支付来购物、吃饭、旅游、就医、交水电费等。企业、商品、门店、用户已经通过微信连在了一起,让智慧生活,变成了现实...

前言

微信支付是腾讯集团旗下的第三方支付平台,致力于为用户和企业提供安全、便捷、专业的在线支付服务。以“微信支付,不止支付”为核心理念,为个人用户创造了多种便民服务和应用场景。微信支付为各类企业以及小微商户提供专业的收款能力,运营能力,资金结算解决方案,以及安全保障。用户可以使用微信支付来购物、吃饭、旅游、就医、交水电费等。企业、商品、门店、用户已经通过微信连在了一起,让智慧生活,变成了现实。

小程序实现微信支付主要有两种方式:

  • 小程序内部API,要求商户开通了小程序支付功能
  • 第三方网站

一、微信支付后端功能实现(node版)

1.相关文档

微信支付开发文档V2、V3选择:
https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/api.shtml
在这里插入图片描述
微信小程序调用微信支付接口需要5个参数都是来源于后端接口生成的

wx.requestPayment({
	timeStamp: payArgs.timeStamp,
	nonceStr: payArgs.nonceStr,
	package: payArgs. package,
	signType:'MD5',
	paySign: payArgs. paySign
})

小程序ID(appld)
时间戳(timeStamp)当前的时间,从1970年1月1日00:00:00至今的秒数
随机串(nonceStr) 一个32位的随机字符串
数据包(package) prepay_id=wx2017033010242291fcfe0db70013231072
签名方式(signType)默认为MD5,也有其它支持的类型
签名字符串(paySign)

2.项目配置

node安装相关依赖

router .js

npm install koa3-wechat
npm install short-uuid
npm i raw-body
npm i redis
npm i babel-runtime@6.26.0

在路由模块中引入支付模块

const Pay = require("./pay")
const Router = require("@koa/router")
const router = new Router({
  prefix: '/user'
});

Pay.init(router)

module.exports = router

pay.js

const { wepay: WechatPay } = require('koa3-wechat');
const short = require('short-uuid');
// const fs = require('fs');
const wepay = require("../lib/wepay")
const Order = require("../models/order-model")
const wepay2 = require('../lib/wepay2')

function init(router) {
  // post /user/my/order
  // 下新定单,准备支付
  router.post('/my/order', async ctx => {
    let { uid: userId, openId } = ctx.user
    let { totalFee, addressId, addressDesc, goodsCartsIds, goodsNameDesc } = ctx.request.body
    // 为测试方便,所有金额支付数均为1分
    totalFee = 1
    let payState = 0
    // 依照Order模型接收参数
    let outTradeNo = `${new Date().getFullYear()}${short().new()}`
    // 获取订单的预支付信息
    var trade = {
      body: goodsNameDesc.substr(0, 127), //最长127字节
      attach: '支付测试', //最长127字节
      out_trade_no: outTradeNo, //
      total_fee: totalFee, //以分为单位,货币的最小金额
      trade_type: 'JSAPI',//NATIVE
      spbill_create_ip: ctx.request.ip, //ctx.request.ip
      openid: openId
    };
    var params = await wepay.getBrandWCPayRequestParams(trade);
    let err = '', res
    if (params && params.package && params.paySign) {
      // 创建记录
      res = await Order.create({
        userId,
        outTradeNo,
        payState,
        totalFee,
        addressId,
        addressDesc,
        goodsCartsIds,
        goodsNameDesc
      })
      if (!res) err = 'db create error'
    } else {
      err = 'error! return null!'
      console.log(err);
    }
    ctx.status = 200
    ctx.body = {
      code: 200,
      msg: !err ? 'ok' : '',
      data: {
        res,
        params
      }
    }
  })

  // post /user/my/order2
  // 使用weixin-pay实现的接口,测试通过
  router.post('/my/order2', async ctx => {
    let { uid: userId, openId } = ctx.user
    let { totalFee, addressId, addressDesc, goodsCartsIds, goodsNameDesc } = ctx.request.body
    // 为测试方便,所有金额支付数均为1分
    totalFee = 1
    let payState = 0
    // 依照Order模型接收参数
    let outTradeNo = `${new Date().getFullYear()}${short().new()}`
    console.log('outTradeNo', outTradeNo);
    // 获取订单的预支付信息
    var trade = {
      body: goodsNameDesc.substr(0, 127), //最长127字节
      out_trade_no: outTradeNo, //
      total_fee: totalFee, //以分为单位,货币的最小金额
      spbill_create_ip: ctx.request.ip, //ctx.request.ip
      notify_url: 'https://rxyk.cn/apis/pay_notify', // 支付成功通知地址
      trade_type: 'JSAPI',
      openid: openId
    };
    let params = await (() => {
      return new Promise((resolve, reject) => {
        wepay2.getBrandWCPayRequestParams(trade, (err, result) => {
          console.log(err, result);
          if (err) reject(err)
          else resolve(result)
        });
      })
    })()
    let err = '', res
    if (params && params.package && params.paySign) {
      // 创建记录
      res = await Order.create({
        userId,
        outTradeNo,
        payState,
        totalFee,
        addressId,
        addressDesc,
        goodsCartsIds,
        goodsNameDesc
      })
      if (!res) err = 'db create error'
    } else {
      err = 'error! getBrandWCPayRequestParams() return null!'
      console.log(err);
    }
    ctx.status = 200
    ctx.body = {
      code: 200,
      msg: !err ? 'ok' : '',
      data: {
        res,
        params
      }
    }
  })

}

module.exports = {
  init
}

order.js

const DataTypes = require('sequelize')
const db = require("./mysql-db")

module.exports = db.define("order",{
  id:{
    type:DataTypes.INTEGER(11),
    allowNull:false,
    primaryKey:true,
    autoIncrement:true
  },
  userId:{
    type:DataTypes.INTEGER(20),
    allowNull:false
  },
  outTradeNo:{// 微信商号单号
    type:DataTypes.STRING(50),
    allowNull:false
  },
  transactionId:{// 微信交易单号
    type:DataTypes.STRING(50),
    allowNull:true //允许为空
  },
  payState:{// 支付订单的状态,0=未支付,1=已支付,2=取消或其它
    type:DataTypes.INTEGER,
    defaultValue:0,
    allowNull: false
  },
  totalFee:{//总价,单位分
    type:DataTypes.INTEGER(11),
    allowNull:false
  },
  addressId:{//收货地址id
    type:DataTypes.INTEGER(20),
    allowNull:false
  },
  addressDesc:{//收货地址总描述
    type:DataTypes.TEXT('tiny'),//最大长度255个字节
    allowNull:false
  },
  goodsCartsIds:{//购买车商品ids
    type:DataTypes.JSON,
    allowNull:false
  },
  goodsNameDesc:{//商品名称描述
    type:DataTypes.TEXT('tiny'),//最大长度255个字节
    allowNull:false
  }
},{
  indexes: [{
    unique: true,// 唯一索引
    fields: ['out_trade_no']
  }],
  underscored: true,
  freezeTableName:true,
  timestamps:true
});

wepay.js

const {wepay:WechatPay} = require('koa3-wechat');
// const short = require('short-uuid');
const fs = require('fs');

 // 普通商户的参数
 let config = {
  appId: '自己的APPID', // 小程序APPID
  mchId: '自己的商户id',//商户id
  notifyUrl: '自己的通知地址', // 支付成功通知地址
  partnerKey: '自己的api key', // 微信商户平台的api key,在pay.weixin.qq.com设置
  pfx: fs.readFileSync(__dirname + '/apiclient_cert.p12'),
  // passphrase: '预留信息',// 添加了无法退款
}

// 初始化
let wepay = new WechatPay(config);

module.exports = wepay

wepay2.js

const WXPay = require('weixin-pay')
// const short = require('short-uuid')
const fs = require('fs')

const wxpay2 = WXPay({
  appid: "自己的APPID",//小程序APPID
  mch_id: '自己的商户id',//商户id
  notify_url: '自己的通知地址', // 支付成功通知地址
  partnerKey: '自己的api key', // 微信商户平台的api key,在 API secret,非小程序 secret
  pfx: fs.readFileSync(__dirname + '/apiclient_cert.p12'), 
  passphrase: '预留信息'
});

module.exports = wxpay2
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。