1. Technology Stack Overview
- MidwayJS: Node.js framework from Alibaba
- TypeORM: Robust ORM framework for relational databases
- wechatpay-node-v3: Official WeChat Pay V3 SDK
- MySQL: Relational database (Replaceable as needed)
2. Project Configuration Setup
1. WeChat Payment Configuration
// config/config.default.ts
export default {
payment: {
wechat: {
appId: 'Your public account ID',
mchId: 'Merchant ID',
privateKey: fs.readFileSync('apiclient_key.pem'),
certSerialNo: 'Certificate serial number',
apiKey: 'APIv3 key',
publicKey: fs.readFileSync('certificate.pem'),
notifyUrl: 'Payment callback URL',
refundNotifyUrl: 'Refund notification URL'
}
}
}
2. Database Entity Design
// Payment order entity
@Entity()
export class WechatOrder {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
outTradeNo: string; // Merchant order number
@Column()
totalAmount: number; // Order amount (in cents)
@Column()
status: string; // Order status
}
// Status log entity
@Entity()
export class WechatStatusLog {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne(() => WechatOrder)
order: WechatOrder;
@Column()
status: string; // Status value
@Column()
remark: string; // Change description
}
3. Core Function Implementation
1. Create Payment Order
async createOrder(params: WechatCreateOrderParams) {
// 1. Create database record
const order = new WechatOrder();
await this.wechatOrderModel.save(order);
// 2. Call WeChat API
const result = await this.wechatPay.transactions_jsapi({
description: params.description,
out_trade_no: params.outTradeNo,
amount: { total: params.totalAmount }
});
// 3. Return prepay ID
return { prepayId: result.prepay_id };
}
2. Query Order Status
async queryOrder(outTradeNo: string) {
// 1. Find local order
const order = await this.wechatOrderModel.findOne({ where: { outTradeNo } });
// 2. Call WeChat query API
const result = await this.wechatPay.query({ out_trade_no: outTradeNo });
// 3. Sync and log status changes
if (result.trade_state !== order.status) {
await this.updateOrderStatus(order, result);
await this.recordStatusChange(...);
}
}
3. Handle Payment Notification
async handleNotify(params: any) {
// 1. Verify merchant order
const order = await this.wechatOrderModel.findOne({
where: { outTradeNo: params.out_trade_no }
});
// 2. Update order status
if (params.trade_state !== order.status) {
order.status = params.trade_state;
await this.wechatOrderModel.save(order);
await this.recordStatusChange(...);
}
return true; // Return success response
}
4. Process Refund Request
async refund(params: WechatRefundParams) {
// 1. Generate refund ID
const outRefundNo = `${params.outTradeNo}_${Date.now()}`;
// 2. Call refund API
const result = await this.wechatPay.refund({
out_trade_no: params.outTradeNo,
out_refund_no: outRefundNo,
amount: { refund: params.refundAmount }
});
// 3. Update order status
order.status = 'REFUND';
await this.wechatOrderModel.save(order);
}
4. Best Practice Recommendations
1. Status Management
- Maintain complete state transitions (NOTPAY → SUCCESS/CLOSED/REFUND)
- Use dedicated status log table
- Regular reconciliation with WeChat
2. Error Handling
- Implement retry mechanism for API calls
- Use transactions for database operations
- Add comprehensive logging
3. Security Measures
- Verify WeChat callback signatures
- Encrypt sensitive data
- Store amounts in cents
5. Common Issues Troubleshooting
1. Certificate Configuration
- Verify certificate file paths
- Ensure serial number matches merchant platform
- Use correct PEM format
2. Callback Handling
- Check reverse proxy configurations
- Return proper success response
- Log raw callback data
3. Signature Verification
- Validate APIv3 key correctness
- Ensure server time synchronization
- Verify signature algorithm
6. Optimization Directions
- Distributed Lock: Prevent duplicate callback processing
- Auto Reconciliation: Daily order verification job
- Monitoring System: Track failure rates & response times
- Multi-merchant Support: Dynamic configuration loading
This implementation provides a robust WeChat payment integration solution covering essential payment workflows. The modular design allows easy extension for business-specific requirements like marketing campaigns or data analytics dashboards.