package repository import ( "context" "electricity_bill_calc/config" "electricity_bill_calc/global" "electricity_bill_calc/logger" "electricity_bill_calc/model" "electricity_bill_calc/types" "fmt" "github.com/doug-martin/goqu/v9" _ "github.com/doug-martin/goqu/v9/dialect/postgres" "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5" "github.com/samber/lo" "go.uber.org/zap" ) type _ChargeRepository struct { log *zap.Logger ds goqu.DialectWrapper } var ChargeRepository = &_ChargeRepository{ log: logger.Named("Repository", "Charge"), ds: goqu.Dialect("postgres"), } // 分页查询用户的充值记录 func (cr _ChargeRepository) FindCharges(page uint, beginTime, endTime *types.Date, keyword *string) ([]*model.UserChargeDetail, int64, error) { cr.log.Info("查询用户的充值记录。", logger.DateFieldp("beginTime", beginTime), logger.DateFieldp("endTime", endTime), zap.Stringp("keyword", keyword), zap.Uint("page", page)) ctx, cancel := global.TimeoutContext() defer cancel() chargeQuery := cr.ds. From(goqu.T("user_charge").As("c")). Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("c.user_id").Eq(goqu.I("ud.id")))). Join(goqu.T("user").As("u"), goqu.On(goqu.I("ud.id").Eq(goqu.I("u.id")))). Select( "c.seq", "c.user_id", "ud.name", "c.fee", "c.discount", "c.amount", "c.charge_to", "c.settled", "c.settled_at", "c.cancelled", "c.cancelled_at", "c.refunded", "c.refunded_at", "c.created_at", ) countQuery := cr.ds. From(goqu.T("user_charge").As("c")). Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("c.user_id").Eq(goqu.I("ud.id")))). Join(goqu.T("user").As("u"), goqu.On(goqu.I("ud.id").Eq(goqu.I("u.id")))). Select(goqu.COUNT("*")) if keyword != nil && len(*keyword) > 0 { pattern := fmt.Sprintf("%%%s%%", *keyword) chargeQuery = chargeQuery.Where(goqu.Or( goqu.I("ud.name").ILike(pattern), goqu.I("ud.abbr").ILike(pattern), goqu.I("u.username").ILike(pattern), )) countQuery = countQuery.Where(goqu.Or( goqu.I("ud.name").ILike(pattern), goqu.I("ud.abbr").ILike(pattern), goqu.I("u.username").ILike(pattern), )) } if beginTime != nil { chargeQuery = chargeQuery.Where(goqu.I("c.created_at").Gte(beginTime.ToBeginningOfDate())) countQuery = countQuery.Where(goqu.I("c.created_at").Gte(beginTime.ToBeginningOfDate())) } if endTime != nil { chargeQuery = chargeQuery.Where(goqu.I("c.created_at").Lte(endTime.ToEndingOfDate())) countQuery = countQuery.Where(goqu.I("c.created_at").Lte(endTime.ToEndingOfDate())) } chargeQuery = chargeQuery.Order(goqu.I("c.created_at").Desc()) currentPostion := (page - 1) * config.ServiceSettings.ItemsPageSize chargeQuery = chargeQuery.Offset(currentPostion).Limit(config.ServiceSettings.ItemsPageSize) chargeSql, chargeArgs, _ := chargeQuery.Prepared(true).ToSQL() countSql, countArgs, _ := countQuery.Prepared(true).ToSQL() var ( charges []*model.UserChargeDetail = make([]*model.UserChargeDetail, 0) total int64 ) if err := pgxscan.Select(ctx, global.DB, &charges, chargeSql, chargeArgs...); err != nil { cr.log.Error("查询用户的充值记录失败。", zap.Error(err)) return make([]*model.UserChargeDetail, 0), 0, err } if err := pgxscan.Get(ctx, global.DB, &total, countSql, countArgs...); err != nil { cr.log.Error("查询用户的充值记录总数失败。", zap.Error(err)) return make([]*model.UserChargeDetail, 0), 0, err } return charges, total, nil } // 在用户充值记录中创建一条新的记录 func (cr _ChargeRepository) CreateChargeRecord(tx pgx.Tx, ctx context.Context, uid string, fee, discount, amount *float64, chargeTo types.Date) (bool, error) { createQuery, createArgs, _ := cr.ds. Insert(goqu.T("user_charge")). Cols("user_id", "fee", "discount", "amount", "charge_to", "created_at"). Vals(goqu.Vals{uid, fee, discount, amount, chargeTo, types.Now()}). Prepared(true).ToSQL() rs, err := tx.Exec(ctx, createQuery, createArgs...) if err != nil { cr.log.Error("创建用户充值记录失败。", zap.Error(err)) return false, err } return rs.RowsAffected() > 0, nil } // 撤销用户的充值记录 func (cr _ChargeRepository) CancelCharge(tx pgx.Tx, ctx context.Context, uid string, seq int64) (bool, error) { updateQuerySql, updateArgs, _ := cr.ds. Update(goqu.T("user_charge")). Set(goqu.Record{"cancelled": true, "cancelled_at": types.Now()}). Where(goqu.I("user_id").Eq(uid), goqu.I("seq").Eq(seq)). Prepared(true).ToSQL() rs, err := tx.Exec(ctx, updateQuerySql, updateArgs...) if err != nil { cr.log.Error("撤销用户的充值记录失败。", zap.Error(err)) return false, err } return rs.RowsAffected() > 0, nil } // 检索用户最近有效的服务期限 func (cr _ChargeRepository) LatestValidChargeTo(tx pgx.Tx, ctx context.Context, uid string) (*types.Date, error) { searchSql, searchArgs, _ := cr.ds. From(goqu.T("user_charge")). Select("charge_to"). Where( goqu.I("settled").Eq(true), goqu.I("cancelled").Eq(false), goqu.I("refunded").Eq(false), goqu.I("user_id").Eq(uid), ). Prepared(true).ToSQL() var chargeTo []*types.Date if err := pgxscan.Select(ctx, tx, &chargeTo, searchSql, searchArgs...); err != nil { cr.log.Error("检索用户有效服务期限列表失败。", zap.Error(err)) return nil, err } if len(chargeTo) == 0 { return nil, fmt.Errorf("无法找到用户最近的有效服务期限。") } lastCharge := lo.MaxBy(chargeTo, func(a, b *types.Date) bool { return a.Time.After(b.Time) }) return lastCharge, nil }