electricity_bill_calc_service/repository/charge.go

166 lines
6.2 KiB
Go

package repository
import (
"context"
"electricity_bill_calc/cache"
"electricity_bill_calc/config"
"electricity_bill_calc/global"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/tools"
"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))
cacheConditions := []string{
fmt.Sprintf("%d", page),
tools.DefaultTo(keyword, ""),
tools.CondFn(func(t *types.Date) bool { return t != nil }, beginTime, beginTime.Format("2006-01-02"), "UNDEF"),
tools.CondFn(func(t *types.Date) bool { return t != nil }, endTime, endTime.Format("2006-01-02"), "UNDEF"),
}
if charges, total, err := cache.RetrievePagedSearch[[]*model.UserChargeDetail]("charges", cacheConditions...); err == nil && charges != nil {
cr.log.Info("从缓存中获取用户的充值记录成功。", zap.Int("count", len(*charges)), zap.Int64("total", total))
return *charges, total, nil
}
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
}
cache.CachePagedSearch(charges, total, []string{"charges"}, "charges", cacheConditions...)
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
}