refactor(charge):基本完成用户计费部分的迁移。
This commit is contained in:
parent
cb2908435a
commit
c6c1423364
|
@ -1,10 +1,13 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
"electricity_bill_calc/cache"
|
"electricity_bill_calc/cache"
|
||||||
"electricity_bill_calc/config"
|
"electricity_bill_calc/config"
|
||||||
"electricity_bill_calc/exceptions"
|
"electricity_bill_calc/exceptions"
|
||||||
"electricity_bill_calc/global"
|
"electricity_bill_calc/global"
|
||||||
|
"electricity_bill_calc/logger"
|
||||||
"electricity_bill_calc/model"
|
"electricity_bill_calc/model"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -12,28 +15,32 @@ import (
|
||||||
|
|
||||||
"github.com/fufuok/utils"
|
"github.com/fufuok/utils"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"xorm.io/builder"
|
"github.com/uptrace/bun"
|
||||||
"xorm.io/xorm"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _ChargeService struct{}
|
type _ChargeService struct {
|
||||||
|
l *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
var ChargeService _ChargeService
|
var ChargeService = _ChargeService{
|
||||||
|
l: logger.Named("Service", "Charge"),
|
||||||
|
}
|
||||||
|
|
||||||
func (c _ChargeService) CreateChargeRecord(charge *model.UserCharge, extendWithIgnoreSettle bool) error {
|
func (c _ChargeService) CreateChargeRecord(charge *model.UserCharge, extendWithIgnoreSettle bool) error {
|
||||||
tx := global.DBConn.NewSession()
|
ctx, cancel := global.TimeoutContext()
|
||||||
defer tx.Close()
|
defer cancel()
|
||||||
if err := tx.Begin(); err != nil {
|
tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
charge.Seq = 0
|
_, err = tx.NewInsert().Model(charge).Exec(ctx)
|
||||||
_, err := tx.Insert(charge)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if extendWithIgnoreSettle {
|
if extendWithIgnoreSettle {
|
||||||
err := c.updateUserExpiration(tx, charge.UserId, charge.ChargeTo)
|
err := c.updateUserExpiration(&tx, ctx, charge.UserId, charge.ChargeTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -48,26 +55,35 @@ func (c _ChargeService) CreateChargeRecord(charge *model.UserCharge, extendWithI
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c _ChargeService) SettleCharge(seq int64, uid string) error {
|
func (c _ChargeService) SettleCharge(seq int64, uid string) error {
|
||||||
|
ctx, cancel := global.TimeoutContext()
|
||||||
|
defer cancel()
|
||||||
|
tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
var record *model.UserCharge
|
var record *model.UserCharge
|
||||||
has, err := global.DBConn.Where(builder.Eq{"seq": seq, "user_id": uid}).NoAutoCondition().Get(record)
|
err = tx.NewSelect().Model(&record).
|
||||||
|
Where("seq = ?", seq).
|
||||||
|
Where("user_id = ?", uid).
|
||||||
|
Scan(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !has {
|
if record == nil {
|
||||||
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
||||||
}
|
}
|
||||||
tx := global.DBConn.NewSession()
|
|
||||||
defer tx.Close()
|
|
||||||
if err := tx.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
_, err = tx.Table(new(model.UserCharge)).Where(builder.Eq{"seq": seq, "user_id": uid}).Cols("settled", "settled_at").Update(&model.UserCharge{Settled: true, SettledAt: ¤tTime})
|
_, err = tx.NewUpdate().Model((*model.UserCharge)(nil)).
|
||||||
|
Where("seq = ?", seq).
|
||||||
|
Where("user_id = ?", uid).
|
||||||
|
Set("settled = ?", true).
|
||||||
|
Set("settled_at = ?", currentTime).
|
||||||
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = c.updateUserExpiration(tx, uid, record.ChargeTo)
|
err = c.updateUserExpiration(&tx, ctx, uid, record.ChargeTo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -76,33 +92,38 @@ func (c _ChargeService) SettleCharge(seq int64, uid string) error {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache.AbolishRelation("charge")
|
cache.AbolishRelation(fmt.Sprintf("charge:%s:%d", uid, seq))
|
||||||
cache.AbolishRelation(fmt.Sprintf("charge_%s_%d", uid, seq))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c _ChargeService) RefundCharge(seq int64, uid string) error {
|
func (c _ChargeService) RefundCharge(seq int64, uid string) error {
|
||||||
tx := global.DBConn.NewSession()
|
ctx, cancel := global.TimeoutContext()
|
||||||
defer tx.Close()
|
defer cancel()
|
||||||
if err := tx.Begin(); err != nil {
|
tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
rows, err := tx.Table(new(model.UserCharge)).Where(builder.Eq{"seq": seq, "user_id": uid}).Cols("refunded", "refunded_at").Update(&model.UserCharge{Refunded: true, RefundedAt: ¤tTime})
|
res, err := tx.NewUpdate().Model((*model.UserCharge)(nil)).
|
||||||
|
Where("seq = ?", seq).
|
||||||
|
Where("user_id = ?", uid).
|
||||||
|
Set("refunded = ?", true).
|
||||||
|
Set("refunded_at = ?", currentTime).
|
||||||
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rows == 0 {
|
if rows, _ := res.RowsAffected(); rows == 0 {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
||||||
}
|
}
|
||||||
lastValidExpriation, err := c.lastValidChargeTo(uid)
|
lastValidExpriation, err := c.lastValidChargeTo(&tx, &ctx, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return exceptions.NewNotFoundError("未找到最后合法的计费时间。")
|
return exceptions.NewNotFoundError("未找到最后合法的计费时间。")
|
||||||
}
|
}
|
||||||
err = c.updateUserExpiration(tx, uid, lastValidExpriation)
|
err = c.updateUserExpiration(&tx, ctx, uid, lastValidExpriation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -111,24 +132,29 @@ func (c _ChargeService) RefundCharge(seq int64, uid string) error {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache.AbolishRelation("charge")
|
cache.AbolishRelation(fmt.Sprintf("charge:%s:%d", uid, seq))
|
||||||
cache.AbolishRelation(fmt.Sprintf("charge_%s_%d", uid, seq))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c _ChargeService) CancelCharge(seq int64, uid string) error {
|
func (c _ChargeService) CancelCharge(seq int64, uid string) error {
|
||||||
tx := global.DBConn.NewSession()
|
ctx, cancel := global.TimeoutContext()
|
||||||
defer tx.Close()
|
defer cancel()
|
||||||
if err := tx.Begin(); err != nil {
|
tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{})
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
rows, err := tx.Table(new(model.UserCharge)).Where(builder.Eq{"seq": seq, "user_id": uid}).Cols("cancelled", "cancelled_at").Update(&model.UserCharge{Cancelled: true, CancelledAt: ¤tTime})
|
res, err := tx.NewUpdate().Model((*model.UserCharge)(nil)).
|
||||||
|
Where("seq = ?", seq).
|
||||||
|
Where("user_id = ?", uid).
|
||||||
|
Set("cancelled = ?", true).
|
||||||
|
Set("cancelled_at = ?", currentTime).
|
||||||
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if rows == 0 {
|
if rows, _ := res.RowsAffected(); rows == 0 {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
||||||
}
|
}
|
||||||
|
@ -137,16 +163,15 @@ func (c _ChargeService) CancelCharge(seq int64, uid string) error {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tx = global.DBConn.NewSession()
|
tx, err = global.DB.BeginTx(ctx, &sql.TxOptions{})
|
||||||
defer tx.Close()
|
if err != nil {
|
||||||
if err := tx.Begin(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
lastValidExpriation, err := c.lastValidChargeTo(uid)
|
lastValidExpriation, err := c.lastValidChargeTo(&tx, &ctx, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return exceptions.NewNotFoundError("未找到最后合法的计费时间。")
|
return exceptions.NewNotFoundError("未找到最后合法的计费时间。")
|
||||||
}
|
}
|
||||||
err = c.updateUserExpiration(tx, uid, lastValidExpriation)
|
err = c.updateUserExpiration(&tx, ctx, uid, lastValidExpriation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -156,30 +181,38 @@ func (c _ChargeService) CancelCharge(seq int64, uid string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cache.AbolishRelation("user")
|
cache.AbolishRelation("user")
|
||||||
cache.AbolishRelation(fmt.Sprintf("user_%s", uid))
|
cache.AbolishRelation(fmt.Sprintf("user:%s", uid))
|
||||||
cache.AbolishRelation("charge")
|
cache.AbolishRelation("charge")
|
||||||
cache.AbolishRelation(fmt.Sprintf("charge_%s_%d", uid, seq))
|
cache.AbolishRelation(fmt.Sprintf("charge:%s:%d", uid, seq))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ChargeService) updateUserExpiration(tx *xorm.Session, uid string, expiration time.Time) error {
|
func (_ChargeService) updateUserExpiration(tx *bun.Tx, ctx context.Context, uid string, expiration time.Time) error {
|
||||||
_, err := tx.ID(uid).Cols("service_expiration").Update(&model.UserDetail{ServiceExpiration: expiration})
|
_, err := tx.NewUpdate().Model((*model.UserDetail)(nil)).
|
||||||
|
Set("service_expiration = ?", expiration).
|
||||||
|
Where("id = ?", uid).
|
||||||
|
Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
}
|
}
|
||||||
cache.AbolishRelation("user")
|
cache.AbolishRelation(fmt.Sprintf("user:%s", uid))
|
||||||
cache.AbolishRelation(fmt.Sprintf("user_%s", uid))
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ChargeService) ListPagedChargeRecord(keyword, beginDate, endDate string, page int) ([]model.ChargeWithName, int64, error) {
|
func (_ChargeService) ListPagedChargeRecord(keyword, beginDate, endDate string, page int) ([]model.ChargeWithName, int64, error) {
|
||||||
var (
|
var (
|
||||||
cond = builder.NewCond()
|
cond = global.DB.NewSelect()
|
||||||
condition = make([]string, 0)
|
condition = make([]string, 0)
|
||||||
|
charges = make([]model.UserCharge, 0)
|
||||||
)
|
)
|
||||||
|
cond = cond.Model(&charges).Relation("Detail")
|
||||||
condition = append(condition, strconv.Itoa(page))
|
condition = append(condition, strconv.Itoa(page))
|
||||||
if len(keyword) != 0 {
|
if len(keyword) != 0 {
|
||||||
cond = cond.And(builder.Like{"d.name", keyword}.Or(builder.Like{"d.abbr", keyword}))
|
keywordCond := "%" + keyword + "%"
|
||||||
|
cond = cond.WhereGroup(" and ", func(q *bun.SelectQuery) *bun.SelectQuery {
|
||||||
|
return q.Where("d.mame like ?", keywordCond).
|
||||||
|
WhereOr("d.abbr like ?", keywordCond)
|
||||||
|
})
|
||||||
condition = append(condition, keyword)
|
condition = append(condition, keyword)
|
||||||
}
|
}
|
||||||
if len(beginDate) != 0 {
|
if len(beginDate) != 0 {
|
||||||
|
@ -188,7 +221,7 @@ func (_ChargeService) ListPagedChargeRecord(keyword, beginDate, endDate string,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]model.ChargeWithName, 0), 0, err
|
return make([]model.ChargeWithName, 0), 0, err
|
||||||
}
|
}
|
||||||
cond = cond.And(builder.Gte{"c.created_at": beginTime})
|
cond = cond.Where("c.created_at >= ?", beginTime)
|
||||||
condition = append(condition, strconv.FormatInt(beginTime.Unix(), 10))
|
condition = append(condition, strconv.FormatInt(beginTime.Unix(), 10))
|
||||||
}
|
}
|
||||||
if len(endDate) != 0 {
|
if len(endDate) != 0 {
|
||||||
|
@ -197,51 +230,47 @@ func (_ChargeService) ListPagedChargeRecord(keyword, beginDate, endDate string,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return make([]model.ChargeWithName, 0), 0, err
|
return make([]model.ChargeWithName, 0), 0, err
|
||||||
}
|
}
|
||||||
cond = cond.And(builder.Lte{"c.created_at": endTime})
|
cond = cond.Where("c.created_at <= ?", endTime)
|
||||||
condition = append(condition, strconv.FormatInt(endTime.Unix(), 10))
|
condition = append(condition, strconv.FormatInt(endTime.Unix(), 10))
|
||||||
}
|
}
|
||||||
startItem := (page - 1) * config.ServiceSettings.ItemsPageSize
|
|
||||||
var (
|
|
||||||
total int64
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if cachedTotal, err := cache.RetreiveCount("charge_with_name", condition...); cachedTotal != -1 && err == nil {
|
if cachedTotal, err := cache.RetreiveCount("charge_with_name", condition...); cachedTotal != -1 && err == nil {
|
||||||
total = cachedTotal
|
|
||||||
} else {
|
|
||||||
total, err = global.DBConn.
|
|
||||||
Alias("d").
|
|
||||||
Join("INNER", []string{"user_charge", "c"}, "c.user_id=d.id").
|
|
||||||
Where(cond).
|
|
||||||
NoAutoCondition().
|
|
||||||
Count(&model.ChargeWithName{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, -1, err
|
|
||||||
}
|
|
||||||
cache.CacheCount([]string{"charge"}, "charge_with_name", total, condition...)
|
|
||||||
}
|
|
||||||
charges := make([]model.ChargeWithName, 0)
|
|
||||||
if cachedCharges, _ := cache.RetreiveSearch[[]model.ChargeWithName]("charge_with_name", condition...); cachedCharges != nil {
|
if cachedCharges, _ := cache.RetreiveSearch[[]model.ChargeWithName]("charge_with_name", condition...); cachedCharges != nil {
|
||||||
return *cachedCharges, total, nil
|
return *cachedCharges, cachedTotal, nil
|
||||||
}
|
}
|
||||||
err = global.DBConn.
|
|
||||||
Alias("d").
|
|
||||||
Join("INNER", []string{"user_charge", "c"}, "c.user_id=d.id").
|
|
||||||
Where(cond).
|
|
||||||
Limit(config.ServiceSettings.ItemsPageSize, startItem).
|
|
||||||
NoAutoCondition().
|
|
||||||
Find(&charges)
|
|
||||||
cache.CacheSearch(charges, []string{"charge"}, "charge_with_name", condition...)
|
|
||||||
return charges, total, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ChargeService) lastValidChargeTo(uid string) (time.Time, error) {
|
startItem := (page - 1) * config.ServiceSettings.ItemsPageSize
|
||||||
|
var (
|
||||||
|
total int
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
ctx, cancel := global.TimeoutContext()
|
||||||
|
defer cancel()
|
||||||
|
total, err = cond.Limit(config.ServiceSettings.ItemsPageSize).Offset(startItem).ScanAndCount(ctx)
|
||||||
|
|
||||||
|
relations := []string{"charge"}
|
||||||
|
chargesWithName := make([]model.ChargeWithName, 0)
|
||||||
|
for _, c := range charges {
|
||||||
|
chargesWithName = append(chargesWithName, model.ChargeWithName{
|
||||||
|
UserCharge: c,
|
||||||
|
UserDetail: *c.Detail,
|
||||||
|
})
|
||||||
|
relations = append(relations, fmt.Sprintf("charge:%s:%d", c.UserId, c.Seq))
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.CacheCount(relations, "charge_with_name", int64(total), condition...)
|
||||||
|
cache.CacheSearch(charges, relations, "charge_with_name", condition...)
|
||||||
|
return chargesWithName, int64(total), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ChargeService) lastValidChargeTo(tx *bun.Tx, ctx *context.Context, uid string) (time.Time, error) {
|
||||||
veryBlankTime, _ := time.Parse("2006-01-02 15:04:05", "0001-01-01 00:00:00")
|
veryBlankTime, _ := time.Parse("2006-01-02 15:04:05", "0001-01-01 00:00:00")
|
||||||
var records []string
|
var records []string
|
||||||
err := global.DBConn.
|
err := tx.NewSelect().Table("user_charge").
|
||||||
Table(&model.UserCharge{}).
|
Where("settled = ? and cancelled = ? and refunded = ? and user_id = ?", true, false, false, uid).
|
||||||
Where(builder.Eq{"settled": true, "cancelled": false, "refunded": false, "user_id": uid}).
|
Column("charge_to").
|
||||||
Cols("charge_to").
|
Scan(*ctx, &records)
|
||||||
Find(&records)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return veryBlankTime, nil
|
return veryBlankTime, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user