1. 微信小程序支付及异步通知
微信小程序内支付可以使用微信支付,在用户确认支付后,会返回一个支付结果通知给小程序后台,这就是异步通知的内容。在小程序后台可以通过这个通知来处理订单,生成订单的方法可以参考下面的内容。
1.1 支付流程
支付流程的大致过程如下:
用户打开小程序选择需要购买的商品
小程序调用微信支付接口获取支付参数,并把参数传递到微信支付页面让用户进行支付操作
用户支付成功,微信会返回支付结果通知给小程序后台
小程序后台根据通知中的信息来处理订单状态
其中,第三步的异步通知是最关键的一步,因为只有异步通知到了,订单才能算是完成了支付。
1.2 异步通知需要注意的事项
异步通知接口是微信支付的核心接口,因此需要注意以下几点:
异步通知接口是需要设置安全证书的,以确保通知的来源可靠(防止被模拟或篡改),具体可以参考微信支付文档中的内容。
异步通知是不能修改订单状态的,只能查询订单状态,然后根据查询结果来进行订单状态的更新。
订单状态的更新必须是幂等操作,也就是说多次更新不能造成系统状态的变化。
1.3 异步通知代码示例
异步通知需要在服务器端实现,下面是一个简单的异步通知处理方法的示例:
app.post('/notify', async function (req, res) {
let xml = ''
req.on('data', (chunk) => {
xml += chunk
})
req.on('end', async function () {
try {
let notifyData = await wxpay.Payment.parseAsyncNotify(xml)
//查询订单状态更新订单
await updateOrderStatus(notifyData.out_trade_no, 'PAID')
res.send(wxpay.Payment.buildAsyncNotifyReply('SUCCESS', 'OK'))
} catch (err) {
res.sendStatus(500)
}
})
})
2. 订单处理方法
在小程序中,订单处理的具体实现方式会根据实际情况而有所不同。下面介绍一种比较通用的实现方式。
2.1 生成订单号
在处理订单之前,需要生成一个唯一的订单号,这个订单号可以由时间、用户ID和随机数等信息组成,保证唯一性。可以使用以下代码来生成一个订单号:
function makeOrderNo ({ user_id }) {
let now = new Date()
let year = now.getFullYear()
let month = now.getMonth() + 1
let date = now.getDate()
let hours = now.getHours()
let minutes = now.getMinutes()
let seconds = now.getSeconds()
let ms = now.getMilliseconds()
let rand = Math.floor(Math.random() * 900 + 100)
return `${year}${month}${date}${hours}${minutes}${seconds}${ms}${rand}${user_id}`
}
2.2 订单状态
订单状态通常有以下几种:
待支付
已支付
已发货
已完成
已取消
在实现订单状态时,需要考虑到订单状态的流转和可维护性,可以使用状态机来处理订单状态的转移。
2.3 订单模型
在处理订单之前,需要定义一个订单模型,包括以下几个字段:
订单号,唯一标识一个订单
用户ID,标识谁下的订单
订单状态,表示订单当前的状态,可能有多种状态
订单详情,记录订单中具体商品的信息,比如名称、价格、数量等
订单金额,记录订单总金额
订单创建时间,记录订单创建的时间
订单支付时间,记录订单支付的时间
订单发货时间,记录订单发货的时间
订单完成时间,记录订单完成的时间
订单取消时间,记录订单取消的时间
订单模型的具体实现可能会依据业务场景的不同而有所不同。
2.4 更新订单状态
更新订单状态的方法需要先查询订单的状态,然后再更新订单状态,这样可以保证多次更新状态不会造成系统状态的变化。下面是一个更新订单状态的代码示例:
async function updateOrderStatus (orderNo, status) {
let order = await Order.findOne({ where: { order_no: orderNo } })
if (order && order.status !== status) {
order.status = status
await order.save()
}
}
2.5 订单处理流程
订单处理流程的大致过程如下:
生成一个唯一的订单号
根据订单详情生成订单的总金额
创建一个新的订单,保存订单号、用户ID、订单状态、订单详情、订单金额、订单创建时间等信息
将订单号和订单金额传递给微信支付接口,进行支付操作
支付成功后,更新订单状态为已支付
等待发货,或者发货后更新订单状态为已发货
订单完成后,更新订单状态为已完成
其中,第二步、第三步、第五步、第六步和第七步可能会因业务场景不同而有所不同。
2.6 订单处理代码示例
订单处理代码的具体实现可能会因业务场景不同而有所不同,下面是一个比较通用的订单处理代码示例:
app.post('/order', async function (req, res) {
let orderNo = makeOrderNo({ user_id: req.body.userId })
let totalAmount = calculateTotalAmount(req.body.orderItems)
let order = await Order.create({
order_no: orderNo,
user_id: req.body.userId,
status: 'PENDING',
detail: req.body.orderItems,
total_amount: totalAmount,
created_at: new Date()
})
let paymentParams = {
body: '微信支付测试',
out_trade_no: orderNo,
total_fee: totalAmount,
trade_type: 'JSAPI',
openid: req.body.openId,
notify_url: 'https://www.example.com/notify'
}
let paymentResult = await wxpay.Payment.unifiedOrder(paymentParams)
if (paymentResult.return_code === 'SUCCESS' && paymentResult.result_code === 'SUCCESS') {
await updateOrderStatus(orderNo, 'PAID')
res.send({
orderNo: orderNo,
paymentParams: paymentResult
})
} else {
//处理支付失败的情况
res.sendStatus(500)
}
})
3. 总结
微信小程序中支付后调用SDK的异步通知及验证处理订单方法是小程序开发中不可避免的一个环节,需要掌握一定的知识和技巧。在实现订单处理时,需要考虑到订单状态的流转和可维护性。