From a9738b1bc82339e24531336f61905adf6a9a94d2 Mon Sep 17 00:00:00 2001 From: JNG <365252428@qq.com> Date: Tue, 9 Jun 2026 13:51:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/dao/orderGateDao.go | 44 +++++++++++++++++++++++++++++ internal/logic/orderGateLogic.go | 36 +++++++++++++++-------- internal/logic/orderRecordsLogic.go | 15 ++++++++-- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/internal/dao/orderGateDao.go b/internal/dao/orderGateDao.go index ce72bdf..dfcf79d 100644 --- a/internal/dao/orderGateDao.go +++ b/internal/dao/orderGateDao.go @@ -27,6 +27,27 @@ func ExistsOverduePayLaterBundle(customerID string) (bool, error) { return cnt > 0, nil } +// ExistsUnpaidNormalBundle 是否存在「套餐 + 普通支付 + 未支付」订单 +// 命中即应拦截普通支付类型的套餐下单。 +func ExistsUnpaidNormalBundle(customerID string) (bool, error) { + if customerID == "" { + return false, nil + } + var cnt int64 + err := app.ModuleClients.BundleDB. + Model(&model.BundleOrderRecords{}). + Where("customer_id = ? AND order_mode = ? AND status IN (?, ?)", + customerID, + model.OrderModeNormal, + model.BundleStatusSignedUnpaid, + model.BundleStatusOverdue, + ).Count(&cnt).Error + if err != nil { + return false, err + } + return cnt > 0, nil +} + // ExistsPendingPayLaterBundle 是否存在「套餐 + 先用后付 + 待付款(未逾期)」订单。 // 命中即提示用户去支付,避免同时存在多个先用后付未支付套餐订单。 func ExistsPendingPayLaterBundle(customerID string) (bool, error) { @@ -70,6 +91,29 @@ func ExistsActiveBundle(customerID string) (bool, error) { return cnt > 0, nil } +// ExistsValidBundleForValueAdd 是否存在有效的套餐订单可用于增值服务下单 +// 规则:普通已支付 或 先用后付未逾期未支付 +func ExistsValidBundleForValueAdd(customerID string) (bool, error) { + if customerID == "" { + return false, nil + } + var cnt int64 + err := app.ModuleClients.BundleDB. + Model(&model.BundleOrderRecords{}). + Where(`customer_id = ? AND ( + (order_mode = ? AND status = ?) OR + (order_mode = ? AND pay_later_status IN (?, ?) AND status != ?) + )`, + customerID, + model.OrderModeNormal, model.BundleStatusPaid, + model.OrderModePayLater, model.PayLaterStatusPending, model.PayLaterStatusPaid, model.BundleStatusOverdue, + ).Count(&cnt).Error + if err != nil { + return false, err + } + return cnt > 0, nil +} + // MarkBundleOverdue 套餐先用后付到期扫描:将到期且未付的订单置为 Overdue func MarkBundleOverdue(now time.Time) (int64, error) { t := now.Format("2006-01-02 15:04:05") diff --git a/internal/logic/orderGateLogic.go b/internal/logic/orderGateLogic.go index c14db76..5ef6c2b 100644 --- a/internal/logic/orderGateLogic.go +++ b/internal/logic/orderGateLogic.go @@ -7,11 +7,11 @@ import ( "time" ) -// CheckOrderEligibility 下单前置校验(先用后付)。 +// CheckOrderEligibility 下单前置校验。 // 规则: -// 4. 套餐订单 + 先用后付 + 到期未付:禁止所有套餐下单 -// 5. 套餐到期未付不影响增值下单(无限续杯) -// 3. 套餐有效期内只允许存在一笔 +// 1. 套餐订单:存在先用后付逾期未支付 或 普通订单未支付 → 拦截下单 +// 2. 增值服务:必须有套餐订单且该套餐是(普通已支付 或 先用后付未逾期)→ 才能下单 +// 3. 套餐订单有效期内只允许存在一笔 func CheckOrderEligibility(req *bundle.CheckOrderEligibilityRequest) (*bundle.CheckOrderEligibilityResponse, error) { res := &bundle.CheckOrderEligibilityResponse{Allow: true} if req == nil || req.CustomerID == "" { @@ -21,9 +21,9 @@ func CheckOrderEligibility(req *bundle.CheckOrderEligibilityRequest) (*bundle.Ch return res, nil } - // 套餐下单校验(增值订单不受这些限制:无限续杯) + // 套餐下单校验 if req.OrderKind == model.OrderKindBundle { - // 1. 先用后付套餐逾期未付 → 不可再下单任何套餐(普通/先用后付)。 + // 1. 先用后付逾期未付 → 拦截 overdue, err := dao.ExistsOverduePayLaterBundle(req.CustomerID) if err != nil { return res, err @@ -35,19 +35,19 @@ func CheckOrderEligibility(req *bundle.CheckOrderEligibilityRequest) (*bundle.Ch return res, nil } - // 2. 已存在先用后付且未支付(待付款)的套餐订单 → 提示去支付。 - pending, err := dao.ExistsPendingPayLaterBundle(req.CustomerID) + // 2. 普通订单未支付 → 拦截 + unpaid, err := dao.ExistsUnpaidNormalBundle(req.CustomerID) if err != nil { return res, err } - if pending { + if unpaid { res.Allow = false - res.Reason = model.OrderGateReasonPayLaterBundlePending - res.Msg = "当前已存在未支付订单,请去我的页面支付" + res.Reason = "NORMAL_BUNDLE_UNPAID" + res.Msg = "当前已存在未支付订单,请先完成支付" return res, nil } - // 3. 有效期内已存在套餐订单 → 保证套餐有效期内只存在一笔。 + // 3. 有效期内已存在套餐订单 → 保证套餐有效期内只存在一笔 exists, err := dao.ExistsActiveBundle(req.CustomerID) if err != nil { return res, err @@ -58,6 +58,18 @@ func CheckOrderEligibility(req *bundle.CheckOrderEligibilityRequest) (*bundle.Ch res.Msg = "有效期内已存在套餐订单" return res, nil } + } else if req.OrderKind == model.OrderKindValueAdd { + // 增值服务下单校验:必须有有效的套餐订单 + hasValid, err := dao.ExistsValidBundleForValueAdd(req.CustomerID) + if err != nil { + return res, err + } + if !hasValid { + res.Allow = false + res.Reason = "NO_VALID_BUNDLE" + res.Msg = "请先购买套餐订单后再购买增值服务" + return res, nil + } } return res, nil diff --git a/internal/logic/orderRecordsLogic.go b/internal/logic/orderRecordsLogic.go index 65ec4c7..d128c3b 100644 --- a/internal/logic/orderRecordsLogic.go +++ b/internal/logic/orderRecordsLogic.go @@ -16,10 +16,14 @@ import ( func CreateOrderRecord(req *bundle.OrderCreateRecord) (res *bundle.CommonResponse, err error) { res = new(bundle.CommonResponse) - // 先用后付下单前置校验 + // 下单前置校验 + orderKind := model.OrderKindBundle + if req.OrderType == model.OrderTypeValueAdd { + orderKind = model.OrderKindValueAdd + } if eligibility, e := CheckOrderEligibility(&bundle.CheckOrderEligibilityRequest{ CustomerID: req.CustomerID, - OrderKind: model.OrderKindBundle, + OrderKind: orderKind, OrderMode: req.OrderMode, }); e != nil { return nil, e @@ -86,6 +90,11 @@ func CreateOrderRecord(req *bundle.OrderCreateRecord) (res *bundle.CommonRespons if orderMode == model.OrderModePayLater && payLaterStatus == 0 && req.Status != model.BundleStatusPaid { payLaterStatus = model.PayLaterStatusPending } + // OrderType 从请求中获取,不写死 + orderType := req.OrderType + if orderType == 0 { + orderType = model.OrderTypeBundle // 默认套餐订单 + } orderRecord := &model.BundleOrderRecords{ UUID: orderUUID, OrderNo: orderNo, @@ -117,7 +126,7 @@ func CreateOrderRecord(req *bundle.OrderCreateRecord) (res *bundle.CommonRespons DueTime: req.DueTime, PayLaterStatus: payLaterStatus, ContractTplType: req.ContractTplType, - OrderType: model.OrderTypeBundle, // 套餐订单 + OrderType: orderType, } res, err = dao.CreateOrderRecord(orderRecord) return