forked from free-lancers/electricity_bill_calc_service
feat(charge):基本完成用户充值管理部分接口。
This commit is contained in:
167
repository/charge.go
Normal file
167
repository/charge.go
Normal file
@@ -0,0 +1,167 @@
|
||||
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/tools/time"
|
||||
"fmt"
|
||||
st "time"
|
||||
|
||||
"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 *st.Time, keyword *string) ([]*model.UserChargeDetail, int64, error) {
|
||||
cr.log.Info("查询用户的充值记录。", zap.Timep("beginTime", beginTime), zap.Timep("endTime", endTime), zap.Stringp("keyword", keyword), zap.Uint("page", page))
|
||||
cacheConditions := []string{
|
||||
fmt.Sprintf("%d", page),
|
||||
tools.DefaultTo(keyword, ""),
|
||||
tools.CondFn(func(t *st.Time) bool { return t != nil }, beginTime, beginTime.Format("2006-01-02"), "UNDEF"),
|
||||
tools.CondFn(func(t *st.Time) 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 model.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, time.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": time.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) (*model.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 []*model.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 *model.Date) bool { return a.Time.After(b.Time) })
|
||||
return lastCharge, nil
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"electricity_bill_calc/cache"
|
||||
"electricity_bill_calc/config"
|
||||
"electricity_bill_calc/global"
|
||||
@@ -16,6 +17,7 @@ import (
|
||||
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
|
||||
"github.com/fufuok/utils"
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/samber/lo"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -449,10 +451,8 @@ func (ur _UserRepository) SearchUsersWithLimit(userType *int16, keyword *string,
|
||||
}
|
||||
|
||||
// 更新指定用户的服务有效期限
|
||||
func (ur _UserRepository) UpdateServiceExpiration(uid string, expiration stdTime.Time) (bool, error) {
|
||||
func (ur _UserRepository) UpdateServiceExpiration(tx pgx.Tx, ctx context.Context, uid string, expiration stdTime.Time) (bool, error) {
|
||||
ur.log.Info("更新指定用户的服务有效期限。", zap.String("user id", uid))
|
||||
ctx, cancel := global.TimeoutContext()
|
||||
defer cancel()
|
||||
|
||||
userDetailUpdateQuery := ur.ds.
|
||||
Update("user_detail").
|
||||
@@ -462,7 +462,7 @@ func (ur _UserRepository) UpdateServiceExpiration(uid string, expiration stdTime
|
||||
userDetailSql, userDetailParams, _ := userDetailUpdateQuery.
|
||||
Prepared(true).ToSQL()
|
||||
|
||||
if res, err := global.DB.Exec(ctx, userDetailSql, userDetailParams...); err != nil {
|
||||
if res, err := tx.Exec(ctx, userDetailSql, userDetailParams...); err != nil {
|
||||
ur.log.Error("向数据库更新指定用户的服务有效期限失败。", zap.String("user id", uid), zap.Error(err))
|
||||
return false, err
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user