167 lines
6.1 KiB
Go
167 lines
6.1 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"
|
|
"github.com/shopspring/decimal"
|
|
"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 {
|
|
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.user_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.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.user_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.charge_to").Gte(*beginTime))
|
|
countQuery = countQuery.Where(goqu.I("c.charge_to").Gte(*beginTime))
|
|
}
|
|
|
|
if endTime != nil {
|
|
chargeQuery = chargeQuery.Where(goqu.I("c.charge_to").Lte(*endTime))
|
|
countQuery = countQuery.Where(goqu.I("c.charge_to").Lte(*endTime))
|
|
}
|
|
|
|
chargeQuery = chargeQuery.Order(goqu.I("c.created_by").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
|
|
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 *decimal.Decimal, 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
|
|
}
|