小程序虚拟支付

This commit is contained in:
李琦
2026-09-17 17:47:09 +08:00
parent 7ea8cdd982
commit 0cb70a7618

View File

@@ -183,6 +183,18 @@ func prepareXpayOrder(
for k, v := range orderFields {
order[k] = v
}
// plan_key / level_key 是会员专有列,但老表把它们建成了 NOT NULL 且无默认值
// (次数包订单没有这两个语义)→ 不补值会报
// `Error 1364: Field 'plan_key' doesn't have a default value`。
//
// 这里统一兜底成空串,而不是去把库列改成 DEFAULT ''
// level_key 一旦被静默填成空串,发货时 extendMembership 会把用户等级写成空,
// 属于「无声降级」。保持列严格、由唯一的下单入口显式补齐,才是安全的做法。
for _, k := range []string{"plan_key", "level_key"} {
if _, ok := order[k]; !ok {
order[k] = ""
}
}
if _, err = g.Model(consts.TableMemberOrders).Data(order).Insert(); err != nil {
return nil, err
}
@@ -423,6 +435,11 @@ func deliverOrder(ctx context.Context, outTradeNo, wxOrderId string) error {
case consts.OrderTypeQuota:
toolKey := row["tool_key"].String()
times := row["times"].Int()
// 空 toolKey 会写出一条挂在空工具上的额度记录times<=0 则是「发了等于没发」,
// 两者都属于数据异常,直接拒绝发货并告警,不要静默放过。
if toolKey == "" || times <= 0 {
return gerror.Newf("订单 %s 次数包信息异常: toolKey=%q times=%d", outTradeNo, toolKey, times)
}
expireAt, err := grantToolQuota(ctx, tx, userId, toolKey, times, days)
if err != nil {
return err
@@ -431,6 +448,11 @@ func deliverOrder(ctx context.Context, outTradeNo, wxOrderId string) error {
userId, outTradeNo, toolKey, times, expireAt.String())
default:
levelKey := row["level_key"].String()
// 空等级会让 extendMembership 把 users.level_key 写成空串(等于无声降权),
// 这里拦住:宁可发货失败留一条告警日志,也不要污染用户数据。
if levelKey == "" {
return gerror.Newf("订单 %s 缺少等级信息level_key 为空),拒绝发货以免清空用户等级", outTradeNo)
}
expireAt, finalLevel, err := extendMembership(ctx, tx, userId, levelKey, days)
if err != nil {
return err