Files
Genarrative/scripts/check-wechat-virtual-payment-reconcile.mjs
T
kdletters 36a8719d0f 补齐微信虚拟支付发货确认
在虚拟支付商品入账后调用微信发货确认接口
允许已入账商品订单只重试发货而不重复发放权益
遇到失效 access token 时强制刷新并最多重放一次
要求使用微信 paid_time 并完善历史补单文件清理和回归测试
2026-07-13 13:39:59 +08:00

143 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
import assert from 'node:assert/strict';
import {
buildReconcileFingerprint,
calcPaySig,
normalizeLocalOrderSnapshot,
notifyWechatGoodsDelivered,
paidAtMicrosFromWechatOrder,
parseEnvText,
validateQueryResult,
} from './reconcile-wechat-virtual-payment-order.mjs';
assert.equal(
calcPaySig(
'12345',
'/xpay/query_user_balance',
'{"openid": "xxx", "user_ip": "127.0.0.1", "env": 0}',
),
'c37809f27c6d7fd1837ad2500a04512b66b34fd793a39a385fade56dca89a4b5',
);
assert.deepEqual(
parseEnvText(
'WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV=0 # 现网\nWECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY="app-key"\n',
),
{
WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_APP_KEY: 'app-key',
WECHAT_MINI_PROGRAM_VIRTUAL_PAYMENT_ENV: '0',
},
);
const localOrder = { amountCents: 600, orderId: 'order-001' };
const paidOrder = {
order_fee: 600,
order_id: 'order-001',
order_type: 0,
status: 2,
};
assert.deepEqual(validateQueryResult(localOrder, paidOrder), {
eligibleForCredit: true,
status: 2,
});
assert.deepEqual(validateQueryResult(localOrder, { ...paidOrder, status: 1 }), {
eligibleForCredit: false,
status: 1,
});
assert.deepEqual(
validateQueryResult(localOrder, { ...paidOrder, order_type: 7 }),
{ eligibleForCredit: true, status: 2 },
);
assert.equal(
paidAtMicrosFromWechatOrder({ paid_time: 1_777_111_200 }),
1_777_111_200_000_000,
);
assert.throws(() => paidAtMicrosFromWechatOrder({}), /paid_time/u);
assert.throws(
() => paidAtMicrosFromWechatOrder({ paid_time: Number.MAX_SAFE_INTEGER }),
/安全整数范围/u,
);
assert.throws(
() => validateQueryResult(localOrder, { ...paidOrder, order_fee: 601 }),
/金额/u,
);
assert.throws(
() => validateQueryResult(localOrder, { ...paidOrder, order_type: 1 }),
/可入账虚拟支付单/u,
);
assert.throws(
() => validateQueryResult(localOrder, { ...paidOrder, order_type: 8 }),
/可入账虚拟支付单/u,
);
assert.equal(
buildReconcileFingerprint({ orderId: 'order-001', status: 2 }),
buildReconcileFingerprint({ orderId: 'order-001', status: 2 }),
);
assert.notEqual(
buildReconcileFingerprint({ orderId: 'order-001', status: 2 }),
buildReconcileFingerprint({ orderId: 'order-001', status: 1 }),
);
assert.deepEqual(
normalizeLocalOrderSnapshot([
'order-001',
'user-001',
'points_60',
'60 泥点',
[0],
600,
[0],
'wechat_mp_virtual',
[1],
[1],
1_777_111_200_000_000,
0,
[1],
[1],
[1],
[1],
[1],
]),
{
amount_cents: 600,
kind: [0],
order_id: 'order-001',
payment_channel: 'wechat_mp_virtual',
status: [0],
user_id: 'user-001',
},
);
const originalFetch = globalThis.fetch;
let notifyRequest;
globalThis.fetch = async (url, init) => {
notifyRequest = { url: String(url), init };
return {
ok: true,
status: 200,
text: async () => '',
};
};
try {
await notifyWechatGoodsDelivered(
{
accessToken: 'access-token-001',
notifyProvideGoodsEndpoint:
'https://api.weixin.qq.com/xpay/notify_provide_goods',
paymentEnv: 0,
},
'order-001',
);
} finally {
globalThis.fetch = originalFetch;
}
assert.equal(
notifyRequest.url,
'https://api.weixin.qq.com/xpay/notify_provide_goods?access_token=access-token-001',
);
assert.equal(notifyRequest.init.method, 'POST');
assert.equal(notifyRequest.init.body, '{"order_id":"order-001","env":0}');
console.log('wechat virtual payment reconcile checks passed');