feat(charge):基本完成用户充值管理部分接口。
This commit is contained in:
parent
f8ef6aba98
commit
98f3bdec0a
101
controller/charge.go
Normal file
101
controller/charge.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"electricity_bill_calc/logger"
|
||||||
|
"electricity_bill_calc/model"
|
||||||
|
"electricity_bill_calc/repository"
|
||||||
|
"electricity_bill_calc/response"
|
||||||
|
"electricity_bill_calc/service"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
var chargeLog = logger.Named("Handler", "Charge")
|
||||||
|
|
||||||
|
func InitializeChargeHandlers(router *fiber.App) {
|
||||||
|
router.Get("/charge", searchCharges)
|
||||||
|
router.Post("/charge", createNewUserChargeRecord)
|
||||||
|
router.Put("/charge/:uid/:seq", modifyUserChargeState)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检索用户的充值记录列表
|
||||||
|
func searchCharges(c *fiber.Ctx) error {
|
||||||
|
chargeLog.Info("检索用户的充值记录列表。")
|
||||||
|
result := response.NewResult(c)
|
||||||
|
keyword := c.Query("keyword", "")
|
||||||
|
page := c.QueryInt("page", 1)
|
||||||
|
beginTime, err := model.ParseDate(c.Query("begin"))
|
||||||
|
if err != nil {
|
||||||
|
chargeLog.Error("无法解析查询起始时间。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
endTime, err := model.ParseDate(c.Query("end"))
|
||||||
|
if err != nil {
|
||||||
|
chargeLog.Error("无法解析查询结束时间。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
charges, total, err := repository.ChargeRepository.FindCharges(uint(page), &beginTime.Time, &endTime.Time, &keyword)
|
||||||
|
if err != nil {
|
||||||
|
chargeLog.Error("检索用户的充值记录列表失败。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
return result.Success(
|
||||||
|
"已经获取到符合条件的计费记录。",
|
||||||
|
response.NewPagedResponse(page, total).ToMap(),
|
||||||
|
fiber.Map{"records": charges},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一条新的用户充值记录
|
||||||
|
func createNewUserChargeRecord(c *fiber.Ctx) error {
|
||||||
|
chargeLog.Info("创建一条新的用户充值记录。")
|
||||||
|
result := response.NewResult(c)
|
||||||
|
createionForm := new(model.ChargeRecordCreationForm)
|
||||||
|
if err := c.BodyParser(createionForm); err != nil {
|
||||||
|
chargeLog.Error("无法解析创建充值记录的请求数据。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
ok, err := service.ChargeService.RecordUserCharge(
|
||||||
|
createionForm.UserId,
|
||||||
|
createionForm.Fee,
|
||||||
|
createionForm.Discount,
|
||||||
|
createionForm.Amount,
|
||||||
|
createionForm.ChargeTo,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
chargeLog.Error("创建用户充值记录失败。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
chargeLog.Error("创建用户充值记录失败。")
|
||||||
|
return result.NotAccept("创建用户充值记录失败。")
|
||||||
|
} else {
|
||||||
|
return result.Success("创建用户充值记录成功, 指定用户的服务已延期。")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 改变用户充值记录的状态
|
||||||
|
func modifyUserChargeState(c *fiber.Ctx) error {
|
||||||
|
chargeLog.Info("改变用户充值记录的状态。")
|
||||||
|
result := response.NewResult(c)
|
||||||
|
uid := c.Params("uid")
|
||||||
|
seq, err := c.ParamsInt("seq")
|
||||||
|
if err != nil {
|
||||||
|
chargeLog.Error("无法解析请求参数。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
ok, err := service.ChargeService.CancelUserCharge(uid, int64(seq))
|
||||||
|
if err != nil {
|
||||||
|
chargeLog.Error("取消用户充值记录失败。", zap.Error(err))
|
||||||
|
return result.Error(http.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
chargeLog.Error("取消用户充值记录失败。")
|
||||||
|
return result.NotAccept("取消用户充值记录失败。")
|
||||||
|
} else {
|
||||||
|
return result.Success("取消用户充值记录成功。")
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
package logger
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"electricity_bill_calc/model"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
)
|
)
|
||||||
@ -130,3 +132,11 @@ func With(fields ...zap.Field) *zap.Logger {
|
|||||||
func WithSugar(fields ...zap.Field) *zap.SugaredLogger {
|
func WithSugar(fields ...zap.Field) *zap.SugaredLogger {
|
||||||
return logger.With(fields...).Sugar()
|
return logger.With(fields...).Sugar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DecimalField(key string, val *decimal.Decimal) zap.Field {
|
||||||
|
return zap.String(key, val.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateField(key string, val *model.Date) zap.Field {
|
||||||
|
return zap.String(key, val.Format("2006-01-02"))
|
||||||
|
}
|
||||||
|
30
model/charge.go
Normal file
30
model/charge.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserChargeDetail struct {
|
||||||
|
Seq int64 `json:"seq"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Fee *decimal.Decimal `json:"fee"`
|
||||||
|
Discount *decimal.Decimal `json:"discount"`
|
||||||
|
Amount *decimal.Decimal `json:"amount"`
|
||||||
|
ChargeTo Date `json:"charge_to"`
|
||||||
|
Settled bool `json:"settled"`
|
||||||
|
SettledAt *time.Time `json:"settled_at"`
|
||||||
|
Cancelled bool `json:"cancelled"`
|
||||||
|
CancelledAt *time.Time `json:"cancelled_at"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChargeRecordCreationForm struct {
|
||||||
|
UserId string `json:"userId"`
|
||||||
|
Fee *decimal.Decimal `json:"fee"`
|
||||||
|
Discount *decimal.Decimal `json:"discount"`
|
||||||
|
Amount *decimal.Decimal `json:"amount"`
|
||||||
|
ChargeTo Date `json:"chargeTo"`
|
||||||
|
}
|
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
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"electricity_bill_calc/cache"
|
"electricity_bill_calc/cache"
|
||||||
"electricity_bill_calc/config"
|
"electricity_bill_calc/config"
|
||||||
"electricity_bill_calc/global"
|
"electricity_bill_calc/global"
|
||||||
@ -16,6 +17,7 @@ import (
|
|||||||
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
|
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
|
||||||
"github.com/fufuok/utils"
|
"github.com/fufuok/utils"
|
||||||
"github.com/georgysavva/scany/v2/pgxscan"
|
"github.com/georgysavva/scany/v2/pgxscan"
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"go.uber.org/zap"
|
"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))
|
ur.log.Info("更新指定用户的服务有效期限。", zap.String("user id", uid))
|
||||||
ctx, cancel := global.TimeoutContext()
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
userDetailUpdateQuery := ur.ds.
|
userDetailUpdateQuery := ur.ds.
|
||||||
Update("user_detail").
|
Update("user_detail").
|
||||||
@ -462,7 +462,7 @@ func (ur _UserRepository) UpdateServiceExpiration(uid string, expiration stdTime
|
|||||||
userDetailSql, userDetailParams, _ := userDetailUpdateQuery.
|
userDetailSql, userDetailParams, _ := userDetailUpdateQuery.
|
||||||
Prepared(true).ToSQL()
|
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))
|
ur.log.Error("向数据库更新指定用户的服务有效期限失败。", zap.String("user id", uid), zap.Error(err))
|
||||||
return false, err
|
return false, err
|
||||||
} else {
|
} else {
|
||||||
|
@ -46,6 +46,7 @@ func App() *fiber.App {
|
|||||||
|
|
||||||
controller.InitializeUserHandlers(app)
|
controller.InitializeUserHandlers(app)
|
||||||
controller.InitializeRegionHandlers(app)
|
controller.InitializeRegionHandlers(app)
|
||||||
|
controller.InitializeChargeHandlers(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
121
service/charge.go
Normal file
121
service/charge.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"electricity_bill_calc/cache"
|
||||||
|
"electricity_bill_calc/global"
|
||||||
|
"electricity_bill_calc/logger"
|
||||||
|
"electricity_bill_calc/model"
|
||||||
|
"electricity_bill_calc/repository"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type _ChargeService struct {
|
||||||
|
log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var ChargeService = &_ChargeService{
|
||||||
|
log: logger.Named("Service", "Charge"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一条新的用户充值记录,同时更新用户的服务期限
|
||||||
|
func (cs _ChargeService) RecordUserCharge(uid string, fee, discount, amount *decimal.Decimal, chargeTo model.Date, extendExpriationIgnoringSettle bool) (bool, error) {
|
||||||
|
cs.log.Info(
|
||||||
|
"创建一条新的用户充值记录。",
|
||||||
|
zap.String("uid", uid),
|
||||||
|
logger.DecimalField("fee", fee),
|
||||||
|
logger.DecimalField("discount", discount),
|
||||||
|
logger.DecimalField("amount", amount),
|
||||||
|
logger.DateField("chargeTo", &chargeTo),
|
||||||
|
zap.Bool("extendExpriationIgnoringSettle", extendExpriationIgnoringSettle),
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx, cancel := global.TimeoutContext()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tx, err := global.DB.Begin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
cs.log.Error("开启数据库事务失败。", zap.Error(err))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
ok, err := repository.ChargeRepository.CreateChargeRecord(tx, ctx, uid, fee, discount, amount, chargeTo)
|
||||||
|
switch {
|
||||||
|
case err == nil && !ok:
|
||||||
|
cs.log.Error("未能成功创建用户充值记录", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, fmt.Errorf("未能成功创建用户充值记录")
|
||||||
|
case err != nil:
|
||||||
|
cs.log.Error("创建用户充值记录失败。", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if extendExpriationIgnoringSettle {
|
||||||
|
ok, err = repository.UserRepository.UpdateServiceExpiration(tx, ctx, uid, chargeTo.Time)
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
cs.log.Error("更新用户服务期限失败。", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, err
|
||||||
|
case !ok:
|
||||||
|
cs.log.Error("未能成功更新用户服务期限", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, fmt.Errorf("未能成功更新用户服务期限")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = tx.Commit(ctx)
|
||||||
|
if err != nil {
|
||||||
|
cs.log.Error("提交数据库事务失败。", zap.Error(err))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
cache.AbolishRelation("charge")
|
||||||
|
cache.AbolishRelation(fmt.Sprintf("user:%s", uid))
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 撤销用户的某一条充值记录,同时重新设置用户的服务期限
|
||||||
|
func (cs _ChargeService) CancelUserCharge(uid string, seq int64) (bool, error) {
|
||||||
|
cs.log.Info("撤销用户的充值记录。", zap.String("uid", uid), zap.Int64("seq", seq))
|
||||||
|
ctx, cancel := global.TimeoutContext()
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
tx, err := global.DB.Begin(ctx)
|
||||||
|
if err != nil {
|
||||||
|
cs.log.Error("开启数据库事务失败。", zap.Error(err))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
ok, err := repository.ChargeRepository.CancelCharge(tx, ctx, uid, seq)
|
||||||
|
switch {
|
||||||
|
case err == nil && !ok:
|
||||||
|
cs.log.Error("未能成功撤销用户充值记录", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, fmt.Errorf("未能成功撤销用户充值记录")
|
||||||
|
case err != nil:
|
||||||
|
cs.log.Error("撤销用户充值记录失败。", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
lastValidCharge, err := repository.ChargeRepository.LatestValidChargeTo(tx, ctx, uid)
|
||||||
|
if err != nil {
|
||||||
|
cs.log.Error("查询用户最近一次有效的充值记录失败。", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
ok, err = repository.UserRepository.UpdateServiceExpiration(tx, ctx, uid, lastValidCharge.Time)
|
||||||
|
if err != nil || !ok {
|
||||||
|
cs.log.Error("更新用户服务期限失败。", zap.Error(err))
|
||||||
|
tx.Rollback(ctx)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = tx.Commit(ctx)
|
||||||
|
if err != nil {
|
||||||
|
cs.log.Error("提交数据库事务失败。", zap.Error(err))
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
cache.AbolishRelation("charge")
|
||||||
|
cache.AbolishRelation(fmt.Sprintf("user:%s", uid))
|
||||||
|
return true, nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user