fix: enforce WeChat Pay JSAPI field limits

This commit is contained in:
2026-05-14 20:22:49 +08:00
parent 514365fdec
commit 5c5a8d4a40
4 changed files with 213 additions and 9 deletions

View File

@@ -927,10 +927,47 @@ pub fn build_runtime_profile_recharge_order_id(
created_at_micros: i64,
product_id: &str,
) -> String {
format!(
"recharge:{}",
build_runtime_profile_recharge_wallet_ledger_id(user_id, created_at_micros, product_id)
)
// 微信支付 v3 的 out_trade_no 只接受较短的字母、数字和部分符号。
// 订单号同时作为本地 profile_recharge_order 主键,因此统一使用可支付渠道兼容的紧凑格式。
let timestamp = encode_runtime_profile_recharge_order_base36(created_at_micros.unsigned_abs());
let hash = hash_runtime_profile_recharge_order_key(user_id, product_id, created_at_micros);
format!("rcg{timestamp}{:010x}", hash & 0x0000_0003_ffff_ffff)
}
fn encode_runtime_profile_recharge_order_base36(mut value: u64) -> String {
const DIGITS: &[u8; 36] = b"0123456789abcdefghijklmnopqrstuvwxyz";
if value == 0 {
return "0".to_string();
}
let mut buffer = Vec::new();
while value > 0 {
buffer.push(DIGITS[(value % 36) as usize] as char);
value /= 36;
}
buffer.iter().rev().collect()
}
fn hash_runtime_profile_recharge_order_key(
user_id: &str,
product_id: &str,
created_at_micros: i64,
) -> u64 {
let mut hash = 14_695_981_039_346_656_037u64;
for byte in user_id
.trim()
.as_bytes()
.iter()
.copied()
.chain([b':'])
.chain(product_id.trim().as_bytes().iter().copied())
.chain([b':'])
.chain(created_at_micros.to_le_bytes())
{
hash ^= u64::from(byte);
hash = hash.wrapping_mul(1_099_511_628_211);
}
hash
}
pub fn resolve_runtime_profile_points_recharge_delta(

View File

@@ -683,9 +683,13 @@ mod tests {
build_runtime_profile_recharge_wallet_ledger_id("user-1", 200, "points_60"),
"user-1:200:points_60"
);
assert_eq!(
build_runtime_profile_recharge_order_id("user-1", 200, "points_60"),
"recharge:user-1:200:points_60"
let order_id = build_runtime_profile_recharge_order_id("user-1", 200, "points_60");
assert!(order_id.starts_with("rcg"));
assert!(order_id.len() <= 32);
assert!(
order_id
.chars()
.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit())
);
assert_eq!(
build_runtime_profile_redeem_code_usage_id("GIFT", "user-1", 300, 2),