239 lines
6.2 KiB
Go
239 lines
6.2 KiB
Go
package service
|
|
|
|
import (
|
|
"electricity_bill_calc/config"
|
|
"electricity_bill_calc/exceptions"
|
|
"electricity_bill_calc/global"
|
|
"electricity_bill_calc/model"
|
|
"time"
|
|
|
|
"github.com/fufuok/utils"
|
|
"github.com/samber/lo"
|
|
"xorm.io/builder"
|
|
"xorm.io/xorm"
|
|
)
|
|
|
|
type _ChargeService struct{}
|
|
|
|
var ChargeService _ChargeService
|
|
|
|
func (c _ChargeService) CreateChargeRecord(charge *model.UserCharge, extendWithIgnoreSettle bool) error {
|
|
// var seqs = make([]int64, 0)
|
|
// err := global.DBConn.Table(&model.UserCharge{}).Cols("seq").Find(&seqs)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// maxSeq := utils.Reduce(seqs, 0, func(acc, elem int64) int64 {
|
|
// if elem > acc {
|
|
// return elem
|
|
// } else {
|
|
// return acc
|
|
// }
|
|
// })
|
|
tx := global.DBConn.NewSession()
|
|
defer tx.Close()
|
|
if err := tx.Begin(); err != nil {
|
|
return err
|
|
}
|
|
charge.Seq = 0
|
|
_, err := tx.Insert(charge)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
if extendWithIgnoreSettle {
|
|
err := c.updateUserExpiration(tx, charge.UserId, charge.ChargeTo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c _ChargeService) SettleCharge(seq int64, uid string) error {
|
|
var record *model.UserCharge
|
|
has, err := global.DBConn.Where(builder.Eq{"seq": seq, "user_id": uid}).NoAutoCondition().Get(record)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
if !has {
|
|
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
|
}
|
|
tx := global.DBConn.NewSession()
|
|
defer tx.Close()
|
|
if err := tx.Begin(); err != nil {
|
|
return err
|
|
}
|
|
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})
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
err = c.updateUserExpiration(tx, uid, record.ChargeTo)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c _ChargeService) RefundCharge(seq int64, uid string) error {
|
|
tx := global.DBConn.NewSession()
|
|
defer tx.Close()
|
|
if err := tx.Begin(); err != nil {
|
|
return err
|
|
}
|
|
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})
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
if rows == 0 {
|
|
tx.Rollback()
|
|
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
|
}
|
|
lastValidExpriation, err := c.lastValidChargeTo(uid)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return exceptions.NewNotFoundError("未找到最后合法的计费时间。")
|
|
}
|
|
err = c.updateUserExpiration(tx, uid, lastValidExpriation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c _ChargeService) CancelCharge(seq int64, uid string) error {
|
|
tx := global.DBConn.NewSession()
|
|
defer tx.Close()
|
|
if err := tx.Begin(); err != nil {
|
|
return err
|
|
}
|
|
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})
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
if rows == 0 {
|
|
tx.Rollback()
|
|
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
|
|
}
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
tx = global.DBConn.NewSession()
|
|
defer tx.Close()
|
|
if err := tx.Begin(); err != nil {
|
|
return err
|
|
}
|
|
lastValidExpriation, err := c.lastValidChargeTo(uid)
|
|
if err != nil {
|
|
return exceptions.NewNotFoundError("未找到最后合法的计费时间。")
|
|
}
|
|
err = c.updateUserExpiration(tx, uid, lastValidExpriation)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = tx.Commit()
|
|
if err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (_ChargeService) updateUserExpiration(tx *xorm.Session, uid string, expiration time.Time) error {
|
|
_, err := tx.ID(uid).Cols("service_expiration").Update(&model.UserDetail{ServiceExpiration: expiration})
|
|
if err != nil {
|
|
tx.Rollback()
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (_ChargeService) ListPagedChargeRecord(keyword, beginDate, endDate string, page int) ([]model.ChargeWithName, int64, error) {
|
|
var cond = builder.NewCond()
|
|
if len(keyword) != 0 {
|
|
cond = cond.And(builder.Like{"d.name", keyword}.Or(builder.Like{"d.abbr", keyword}))
|
|
}
|
|
if len(beginDate) != 0 {
|
|
beginTime, err := time.ParseInLocation("2006-01-02", beginDate, time.Local)
|
|
beginTime = utils.BeginOfDay(beginTime)
|
|
if err != nil {
|
|
return make([]model.ChargeWithName, 0), 0, err
|
|
}
|
|
cond = cond.And(builder.Gte{"c.created_at": beginTime})
|
|
}
|
|
if len(endDate) != 0 {
|
|
endTime, err := time.ParseInLocation("2006-01-02", endDate, time.Local)
|
|
endTime = utils.EndOfDay(endTime)
|
|
if err != nil {
|
|
return make([]model.ChargeWithName, 0), 0, err
|
|
}
|
|
cond = cond.And(builder.Lte{"c.created_at": endTime})
|
|
}
|
|
startItem := (page - 1) * config.ServiceSettings.ItemsPageSize
|
|
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
|
|
}
|
|
charges := make([]model.ChargeWithName, 0)
|
|
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)
|
|
return charges, total, err
|
|
}
|
|
|
|
func (_ChargeService) lastValidChargeTo(uid string) (time.Time, error) {
|
|
veryBlankTime, _ := time.Parse("2006-01-02 15:04:05", "0001-01-01 00:00:00")
|
|
var records []string
|
|
err := global.DBConn.
|
|
Table(&model.UserCharge{}).
|
|
Where(builder.Eq{"settled": true, "cancelled": false, "refunded": false, "user_id": uid}).
|
|
Cols("charge_to").
|
|
Find(&records)
|
|
if err != nil {
|
|
return veryBlankTime, nil
|
|
}
|
|
mappedRecords := lo.Map(records, func(elem string, index int) time.Time {
|
|
t, _ := time.Parse(time.RFC3339, elem)
|
|
return utils.BeginOfDay(t)
|
|
})
|
|
lastValid := lo.Reduce(mappedRecords, func(acc, elem time.Time, index int) time.Time {
|
|
if elem.After(acc) {
|
|
return elem
|
|
} else {
|
|
return acc
|
|
}
|
|
}, veryBlankTime)
|
|
return lastValid, nil
|
|
}
|