WeChat Payment Integration Guide with MidwayJS and TypeORM

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

  1. Distributed Lock: Prevent duplicate callback processing
  2. Auto Reconciliation: Daily order verification job
  3. Monitoring System: Track failure rates & response times
  4. 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.