refactor(pricing): DAO 按 (subject_type, subject_id) 键查询/幂等
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
|
||||
pricingConsts "shop-user-trade/consts/pricing"
|
||||
"shop-user-trade/consts/public"
|
||||
pricingDto "shop-user-trade/model/dto/pricing"
|
||||
pricingEntity "shop-user-trade/model/entity/pricing"
|
||||
)
|
||||
|
||||
// chargeOrderDao 计费单数据访问:薄查询/状态迁移原语(同 model-gateway dao 规范)。
|
||||
// 方法入参统一吃 DTO(model/dto/pricing);无锁、无事务、不定义业务错误。
|
||||
var ChargeOrder = &chargeOrderDao{}
|
||||
|
||||
type chargeOrderDao struct{}
|
||||
|
||||
// GetOrder 按 ID 或 subject_type+subject_id+biz_order_no 查询计费单(Id>0 走 ID)。
|
||||
// 幂等查询复用:工作流断点续跑/恢复 execId 不变,据此去重。
|
||||
func (d *chargeOrderDao) GetOrder(ctx context.Context, req *pricingDto.GetChargeOrderReq) (res *pricingEntity.ChargeOrder, err error) {
|
||||
m := gfdb.DB(ctx).Model(ctx, public.TableNameChargeOrder).Model
|
||||
if req.Id > 0 {
|
||||
m = m.Where(pricingEntity.ChargeOrderCol.Id, req.Id)
|
||||
} else {
|
||||
m = m.Where(pricingEntity.ChargeOrderCol.SubjectType, req.SubjectType).
|
||||
Where(pricingEntity.ChargeOrderCol.SubjectID, req.SubjectID).
|
||||
Where(pricingEntity.ChargeOrderCol.BizOrderNo, req.BizOrderNo)
|
||||
}
|
||||
r, err := m.One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if r.IsEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Insert 创建计费单(事务透明:在调用方事务内执行)
|
||||
func (d *chargeOrderDao) Insert(ctx context.Context, req *pricingDto.CreateChargeOrderReq) (id int64, err error) {
|
||||
entity := &pricingEntity.ChargeOrder{
|
||||
SubjectType: req.SubjectType,
|
||||
SubjectID: req.SubjectID,
|
||||
BizOrderNo: req.BizOrderNo,
|
||||
UserId: req.UserId,
|
||||
ChargeMode: req.ChargeMode,
|
||||
Status: req.Status,
|
||||
RuleSnapshot: req.RuleSnapshot,
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, public.TableNameChargeOrder).Data(entity).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// UpdateToSettled 结算迁移:仅 CREATED → SETTLED;rows=0 表示已处理(幂等)
|
||||
func (d *chargeOrderDao) UpdateToSettled(ctx context.Context, req *pricingDto.SettleChargeOrderReq) (bool, error) {
|
||||
return d.migrateStatus(ctx, req.Id, gdb.Map{
|
||||
"status": int(pricingConsts.ChargeOrderStatusSettled),
|
||||
"actual_amount": req.ActualAmount,
|
||||
"usage": req.Usage,
|
||||
"rule_snapshot": req.RuleSnapshot,
|
||||
"settle_time": req.SettleTime,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateToFailed 失败迁移:仅 CREATED → FAILED(不扣费,不动钱)
|
||||
func (d *chargeOrderDao) UpdateToFailed(ctx context.Context, req *pricingDto.FailChargeOrderReq) (bool, error) {
|
||||
return d.migrateStatus(ctx, req.Id, gdb.Map{
|
||||
"status": int(pricingConsts.ChargeOrderStatusFailed),
|
||||
})
|
||||
}
|
||||
|
||||
// migrateStatus 条件状态迁移(幂等:非 CREATED 时 Update 影响 0 行返回 false)
|
||||
func (d *chargeOrderDao) migrateStatus(ctx context.Context, id int64, data gdb.Map) (bool, error) {
|
||||
result, err := gfdb.DB(ctx).Model(ctx, public.TableNameChargeOrder).
|
||||
Data(data).
|
||||
Where(pricingEntity.ChargeOrderCol.Id, id).
|
||||
Where(pricingEntity.ChargeOrderCol.Status, int(pricingConsts.ChargeOrderStatusCreated)).
|
||||
Update()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
rows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return rows > 0, nil
|
||||
}
|
||||
|
||||
// ListByUser 分页查询某用户的计费单
|
||||
func (d *chargeOrderDao) ListByUser(ctx context.Context, req *pricingDto.ListOrdersReq) (res []pricingEntity.ChargeOrder, total int, err error) {
|
||||
r, total, err := gfdb.DB(ctx).Model(ctx, public.TableNameChargeOrder).
|
||||
Where(pricingEntity.ChargeOrderCol.UserId, req.UserId).
|
||||
OrderDesc(pricingEntity.ChargeOrderCol.CreatedAt).
|
||||
Page(req.Page, req.PageSize).
|
||||
AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitea.redpowerfuture.com/red-future/common/db/gfdb"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
|
||||
pricingConsts "shop-user-trade/consts/pricing"
|
||||
"shop-user-trade/consts/public"
|
||||
pricingDto "shop-user-trade/model/dto/pricing"
|
||||
pricingEntity "shop-user-trade/model/entity/pricing"
|
||||
)
|
||||
|
||||
// pricingConfigDao 计价配置数据访问:薄 CRUD(同 model-gateway dao 规范)。
|
||||
// 方法入参统一吃 DTO(model/dto/pricing);无锁、无事务、不定义业务错误。
|
||||
var PricingConfig = &pricingConfigDao{}
|
||||
|
||||
type pricingConfigDao struct{}
|
||||
|
||||
// Get 按计价对象(subject_type + subject_id)获取计价配置
|
||||
func (d *pricingConfigDao) Get(ctx context.Context, req *pricingDto.GetConfigReq) (res *pricingEntity.PricingConfig, err error) {
|
||||
r, err := gfdb.DB(ctx).Model(ctx, public.TableNamePricingConfig).
|
||||
Where(pricingEntity.PricingConfigCol.SubjectType, req.SubjectType).
|
||||
Where(pricingEntity.PricingConfigCol.SubjectID, req.SubjectID).
|
||||
One()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if r.IsEmpty() {
|
||||
return nil, nil
|
||||
}
|
||||
err = r.Struct(&res)
|
||||
return
|
||||
}
|
||||
|
||||
// Save 新增或更新计价配置(subject_type+subject_id 唯一,更新走整行覆盖)
|
||||
func (d *pricingConfigDao) Save(ctx context.Context, req *pricingDto.SaveConfigReq) (id int64, err error) {
|
||||
if req.Id > 0 {
|
||||
_, err = gfdb.DB(ctx).Model(ctx, public.TableNamePricingConfig).
|
||||
Data(gdb.Map{
|
||||
"subject_type": req.SubjectType,
|
||||
"subject_id": req.SubjectID,
|
||||
"rules": req.Rules,
|
||||
"min_balance": req.MinBalance,
|
||||
"currency": req.Currency,
|
||||
"enabled": req.Enabled,
|
||||
"version": gdb.Raw("version + 1"),
|
||||
}).
|
||||
Where(pricingEntity.PricingConfigCol.Id, req.Id).
|
||||
Update()
|
||||
return req.Id, err
|
||||
}
|
||||
entity := &pricingEntity.PricingConfig{
|
||||
SubjectType: pricingConsts.SubjectType(req.SubjectType),
|
||||
SubjectID: req.SubjectID,
|
||||
Rules: req.Rules,
|
||||
MinBalance: req.MinBalance,
|
||||
Currency: req.Currency,
|
||||
Enabled: req.Enabled,
|
||||
Version: 1,
|
||||
}
|
||||
r, err := gfdb.DB(ctx).Model(ctx, public.TableNamePricingConfig).Data(entity).Insert()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return r.LastInsertId()
|
||||
}
|
||||
|
||||
// List 分页查询计价配置(可按 subjectType / enabled 过滤)
|
||||
func (d *pricingConfigDao) List(ctx context.Context, req *pricingDto.ListConfigsReq) (res []pricingEntity.PricingConfig, total int, err error) {
|
||||
m := gfdb.DB(ctx).Model(ctx, public.TableNamePricingConfig).Model
|
||||
if req.SubjectType != "" {
|
||||
m = m.Where(pricingEntity.PricingConfigCol.SubjectType, req.SubjectType)
|
||||
}
|
||||
if req.Enabled != 0 {
|
||||
m = m.Where(pricingEntity.PricingConfigCol.Enabled, req.Enabled)
|
||||
}
|
||||
r, total, err := m.OrderDesc(pricingEntity.PricingConfigCol.UpdatedAt).Page(req.Page, req.PageSize).AllAndCount(false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = r.Structs(&res)
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user