编程

云开发-微信支付

试用

This skill provides battle-tested guidance for integrating WeChat Mini Program payment and refund flows using Tencent CloudBase. It covers cloud.cloudPay.unifiedOrder() for payments, cloud.cloudPay.refund() for refunds, cloud functions, deployment via CLI, and a catalog of critical pitfalls with fix

它能做什么

This skill provides battle-tested guidance for integrating WeChat Mini Program payment and refund flows using Tencent CloudBase. It covers cloud.cloudPay.unifiedOrder() for payments, cloud.cloudPay.refund() for refunds, cloud functions, deployment via CLI, and a catalog of critical pitfalls with fixes. Use this skill when building, debugging, or reviewing mini-program payment features on CloudBase — especially when payments go to simulated mode, refunds silently fail, or cloud-call access_token errors surface.

技能文档

CloudBase 微信小程序支付集成

一站式指南:微信支付 + 原路退款 + CloudBase 云开发,含踩坑全记录。

Overview

This skill encodes a full payment-refund integration cycle on CloudBase: unified-order payment → order management → server-side refund → historical order backfill. It covers both the happy path and every trap encountered during a real production build, so future integrations skip the debugging marathon.

When to Use

Trigger this skill when:

  • Building a new WeChat Mini Program that needs payment via CloudBase
  • Debugging "payment went to simulated mode" or "env vars missing on deploy"
  • Implementing refunds and getting returnCode / resultCode confusion
  • Seeing -501001 invalid wx openapi access_token during refund calls
  • Historical orders need backfilled refunds
  • Reviewing payment/refund code for correctness

Prerequisites

  • WeChat Mini Program with CloudBase (云开发) enabled
  • WeChat Pay merchant account (微信支付商户号) associated with the mini program
  • CloudBase CLI (tcb) installed and logged in: npm i -g @cloudbase/cli
  • Cloud functions: order, payment (minimum)

Architecture Overview

Mini Program (wx.cloud.callFunction)
    ↓
order 云函数 (business logic, status management)
    ↓
payment 云函数 (wraps cloud.cloudPay.* calls)
    ↓
CloudBase cloud.cloudPay.unifiedOrder() / refund()
    ↓
WeChat Pay API

Key separation principle

Keep payment calls in a dedicated payment cloud function — never spread cloud.cloudPay.* across multiple functions. This isolates the cloud-call context dependency and makes debugging tractable.


Payment Integration Workflow

Step 1: Unified Order (统一下单)

In the payment cloud function, the core call:

const result = await cloud.cloudPay.unifiedOrder({
  body: '商品描述',
  outTradeNo: orderId,       // unique order number
  totalFee: 1,               // integer fen (分), e.g. 1 = 0.01 CNY
  spbillCreateIp: '127.0.0.1',
  tradeType: 'JSAPI',
  envId: 'your-env-id',      // HARDCODE, never DYNAMIC_CURRENT_ENV
  functionName: 'payment',
  subMchId: '',              // omit if not sub-merchant mode
});

Critical:

  • envId does NOT work with cloud.DYNAMIC_CURRENT_ENV — hardcode the environment ID string.
  • Remove subAppId unless in sub-merchant mode. Case mismatches cause cryptic API errors.
  • totalFee is in fen (分), not yuan.

Step 2: Upload Cloud Functions via CLI (NOT DevTools)

DevTools auto-upload does not carry environment variables (WX_MCH_ID, etc.) to the cloud → payment silently falls back to simulated mode (no real charge).

Use CLI deployment:

tcb fn deploy payment --envId 
tcb fn deploy order --envId 

Verify deployment with:

tcb fn list --envId 

Step 3: Environment Variables

In cloudbaserc.json or CloudBase console, ensure:

{
  "env": {
    "WX_APPID": "wx...",
    "WX_MCH_ID": "1...",
    "WX_MCH_KEY": "..."
  }
}

The payment cloud function must read these at runtime:

const mchId = process.env.WX_MCH_ID;
if (!mchId) {
  // This is the symptom of DevTools deploy — abort with clear error
  return { code: -1, message: 'WX_MCH_ID not set — use CLI deployment' };
}

Refund Integration Workflow

Step 1: Core Refund Call

In the payment cloud function, add a refund action:

async function handleRefund(orderId, totalFee, refundFee, outRefundNo) {
  const result = await cloud.cloudPay.refund({
    subMchId: '',                    // omit if not sub-merchant
    transactionId: orderId,
    outTradeNo: orderId,
    outRefundNo: outRefundNo || generateOutRefundNo(orderId),
    totalFee: totalFee,             // original total in fen
    refundFee: refundFee,           // amount to refund in fen
    envId: 'your-env-id',           // hardcoded, same as payment
    functionName: 'payment',
  });

  return result;
}

Step 2: CRITICAL — Double-Layer Return Check

This is the #1 cause of silent refund failures. The refund return object has two layers, both must be checked:

const refundResult = await cloud.cloudPay.refund({...});

// Layer 1: CloudBase wrapper
if (refundResult.returnCode !== 'SUCCESS') {
  return { code: -1, errMsg: refundResult.returnMsg || 'refund wrapper failed' };
}

// Layer 2: WeChat Pay result
if (refundResult.resultCode !== 'SUCCESS') {
  return {
    code: -1,
    errCode: refundResult.errCode,
    errMsg: refundResult.errCodeDes || 'refund payment failed',
  };
}

// Only now is the refund truly successful
// Store refundTransactionId from result.refundId or result.transactionId
return {
  code: 0,
  refundTransactionId: refundResult.refundId,
};

Never check only code and assume success — the old code path that caused refundTransactionId to be empty did exactly this.

Step 3: Order Status After Refund

The order cloud function should:

  1. Call payment cloud function's refund action
  2. Check returnCode AND resultCode on the returned result
  3. Only set refundTransactionId and refundedAt when both succeed
  4. If refund fails, DO NOT change status to user_cancelled — leave as-is and surface the error
// In order cloud function, processRefund action:
const refundRes = await callPaymentCloud('refund', { orderId, totalFee, refundFee });

if (refundRes.returnCode !== 'SUCCESS' || refundRes.resultCode !== 'SUCCESS') {
  return { code: -1, errCode: refundRes.errCode, errMsg: refundRes.errCodeDes };
}

// Only now update the order document:
await db.collection('orders').doc(orderId).update({
  data: {
    status: 'user_cancelled',
    refundedAt: new Date(),
    refundTransactionId: refundRes.refundId,
  },
});

Critical Pitfalls Catalog

For the full pitfall catalog with debugging commands and fix recipes, load references/gotchas.md.

Quick reference of the top 5 pitfalls:

#PitfallSymptomFix
1DevTools deploy loses env varsPayment goes to simulated mode, WX_MCH_ID is emptyUse tcb fn deploy CLI
2envId: cloud.DYNAMIC_CURRENT_ENVunifiedOrder returns unexpected dataHardcode env ID string
3subAppId case mismatchunifiedOrder returns resultCode: FAILRemove subAppId if not using sub-merchant
4Refund return not checked properlyrefundTransactionId stays empty, order marked "refunded" but money never returnedDouble-layer check: returnCode + resultCode
5CLI tcb fn invoke for refund-501001 invalid wx openapi access_tokenCloud calls need mini-program context; use wx.cloud.callFunction from mini program side

Cloud Call Context Rules

cloud.cloudPay.refund() and cloud.cloudPay.unifiedOrder() are cloud calls (云调用). They require WeChat-side authentication context. Only these invocation methods carry valid context:

MethodWorks?Reason
wx.cloud.callFunction from Mini Program✅ YesCarries user session + WeChat auth
Timer trigger (定时触发器)✅ YesPlatform injects context
HTTP API trigger✅ YesPlatform injects context
tcb fn invoke (CLI)❌ NoNo mini-program session → access_token failure
CloudBase console "Test" button❌ NoSame reason as CLI

Rule: Any cloud call needing WeChat Pay access_token must originate from one of the three "✅ Yes" methods. When testing refunds or troubleshooting historical orders, trigger through the Mini Program UI, not CLI.


Deployment Checklist

Before testing payment in production:

  • Cloud functions deployed via tcb fn deploy (not DevTools)
  • envId hardcoded as string in all cloud.cloudPay.* calls
  • WX_MCH_ID, WX_APPID, WX_MCH_KEY set as environment variables
  • Payment cloud function reads env vars and fails fast if missing
  • subAppId removed from unifiedOrder unless sub-merchant mode
  • Refund code has double-layer returnCode + resultCode check
  • Historical order backfill uses mini-program-side trigger (not CLI)

Debugging a Failed Refund

When a user reports "order cancelled but money not returned":

  1. Query the order document: Check refundTransactionId — if empty string, refund never executed.

    tcb db query --envId  -c orders --where '{"_id":""}'
    
  2. Check order status: If status is user_cancelled but refundTransactionId is empty, the old bug is confirmed.

  3. Fix: Add a force_refund action in the payment cloud function that bypasses status checks, then trigger it from the Mini Program via wx.cloud.callFunction({ name: 'payment', data: { action: 'force_refund', orderId } }).

  4. Cleanup: After backfilling, remove force_refund and any related UI buttons — they are temporary fixes, not intended for users.

Resources

  • references/gotchas.md — Full pitfall catalog with debugging commands, error code reference, and the exact chain of bugs encountered during the real build.

相关技能

CloudBase WeChat integration guide for Mini Program WeChat Pay, Mini Program virtual payment (虚拟支付, wx.requestVirtualPayment), Official Account JSAPI Pay, Native QR-code Pay, Official Account OAuth, openid handling, payment callbacks, and CloudBase Integration Center generated functions. This skill should be used when users ask to add, debug, or extend WeChat payment, virtual payment, or official-account flows on CloudBase.

10 次安装

在动手前把 CloudBase 任务路由到正确的子技能,并守住"先准备再实现再 review"的工程流程。

125 次安装

从零快速搭建一个微信小程序(后端用微信云开发/CloudBase)的脚手架与方法论:单函数 REST 路由、幂等建号/幂等建集合、实时统计、订阅消息+定时触发器、全生命周期坑。Scaffold & methodology for building a WeChat Mini Program on WeChat CloudBase: single-function REST routing, idempotent user/collection seeding, real-time stats, subscribe messages + scheduled triggers, full-lifecycle pitfalls. Use when: 做一个云开发小程序 / 从零搭小程序 / 小程序 MVP / building a WeChat Mini Program MVP. Deployment details → wechat-miniprogram-cloudbase-deploy skill.

微信支付(WeChat Pay)相关问题的统一入口,处理与微信支付接入、产品、开发、运营、品牌经营相关的咨询,提供产品选型、官方示例代码、接入质量评估、答疑与排障。Use when user mentions "微信支付", "微信收款", "WeChat Pay", "JSAPI", "APP支付", "H5支...

4 次安装

WeChat Mini Program deployment onto WeChat CloudBase (云开发): deploy cloud functions via tcb, manually create database collections in the console, and upload the frontend via miniprogram-ci. Covers real-environment pitfalls: CLI cannot create collections, tcb fn invoke returns a Namespace metadata bug, the upload IP-whitelist only accepts IPv4 (so an IPv6 egress is always rejected), and the trial env defaults to ap-shanghai. Trigger when the task involves 部署微信小程序, 云开发, CloudBase, tcb 部署云函数, or miniprogram-ci 上传.

Fast path for a minimal CloudBase Web + database demo (最小前后端 / 最小可用 fullstack / Lovable-like BaaS). Defaults to @cloudbase/js-sdk client CRUD (NoSQL app.database / PG app.rdb), MCP-only schema, preview-first, and forbids cloud functions unless secrets, cron/background jobs, or logic that security rules/RLS cannot express. Use for 搭一套 demo、留言板、Todo、Notes、Kanban, or when users say 带云函数+云数据库 but only need CRUD. NOT for production multi-service backends, CloudRun, WeChat Mini Programs, or tasks that truly need server secrets.

1 次安装