feat(charge):基本完成所有用户服务延期记录部分的功能,待测。

This commit is contained in:
徐涛 2022-08-15 15:40:33 +08:00
parent 68c34f540f
commit f033691aa4
5 changed files with 232 additions and 11 deletions

View File

@ -1,13 +1,17 @@
package controller
import (
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/shopspring/decimal"
)
type _ChargesController struct {
@ -22,7 +26,8 @@ func InitializeChargesController(router *gin.Engine) {
}
ChargesController.Router.GET("/charges", security.OPSAuthorize, listAllCharges)
ChargesController.Router.POST("/charge", security.OPSAuthorize, recordNewCharge)
ChargesController.Router.PUT("/charge/:uid/:seq", security.OPSAuthorize, modifyChargeState)
}
func listAllCharges(c *gin.Context) {
@ -46,3 +51,55 @@ func listAllCharges(c *gin.Context) {
gin.H{"records": charges},
)
}
type _NewChargeFormData struct {
UserId string `json:"userId" form:"userId"`
Fee decimal.NullDecimal `json:"fee" form:"fee"`
Discount decimal.NullDecimal `json:"discount" form:"discount"`
Amount decimal.NullDecimal `json:"amount" form:"amount"`
ChargeTo time.Time `json:"chargeTo" form:"chargeTo" time_format:"simple_date" time_location:"shanghai"`
}
func recordNewCharge(c *gin.Context) {
result := response.NewResult(c)
formData := new(_NewChargeFormData)
c.BindJSON(formData)
currentTime := time.Now()
newRecord := &model.UserCharge{
UserId: formData.UserId,
Fee: formData.Fee,
Discount: formData.Discount,
Amount: formData.Amount,
Settled: true,
SettledAt: &currentTime,
ChargeTo: formData.ChargeTo,
}
err := service.ChargeService.CreateChargeRecord(newRecord, true)
if err != nil {
result.Error(http.StatusInternalServerError, err.Error())
return
}
result.Success("指定用户的服务已延期。")
}
type _StateChangeFormData struct {
Cancelled bool `json:"cancelled"`
}
func modifyChargeState(c *gin.Context) {
result := response.NewResult(c)
formData := new(_StateChangeFormData)
c.BindJSON(formData)
requestUserID := c.Param("uid")
requestChargeSeq, err := strconv.Atoi(c.Param("seq"))
if err != nil {
result.Error(http.StatusNotAcceptable, "参数[记录流水号]解析错误。")
return
}
err = service.ChargeService.CancelCharge(int64(requestChargeSeq), requestUserID)
if err != nil {
result.Error(http.StatusInternalServerError, err.Error())
return
}
result.Success("指定用户服务延期记录状态已经更新。")
}

View File

@ -8,13 +8,16 @@ import (
type UserCharge struct {
Created `xorm:"extends"`
Seq int64 `xorm:"bigint pk not null " json:"seq"`
Seq int64 `xorm:"bigint pk not null autoincr" json:"seq"`
UserId string `xorm:"varchar(120) not null" json:"userId"`
Fee decimal.Decimal `xorm:"numeric(12,2) not null" json:"fee"`
Discount decimal.Decimal `xorm:"numeric(5,4) not null" json:"discount"`
Amount decimal.Decimal `xorm:"numeric(12,2) not null" json:"amount"`
Fee decimal.NullDecimal `xorm:"numeric(12,2)" json:"fee"`
Discount decimal.NullDecimal `xorm:"numeric(5,4)" json:"discount"`
Amount decimal.NullDecimal `xorm:"numeric(12,2)" json:"amount"`
ChargeTo time.Time `xorm:"date not null" json:"chargeTo" time_format:"simple_date" time_location:"shanghai"`
Settled bool `xorm:"bool not null default false" json:"settled"`
SettledAt *time.Time `xorm:"timestampz" json:"settledAt" time_format:"simple_datetime" time_location:"shanghai"`
Cancelled bool `xorm:"bool not null default false" json:"cancelled"`
CancelledAt *time.Time `xorm:"timestampz" json:"cancelledAt" time_format:"simple_datetime" time_location:"shanghai"`
Refunded bool `xorm:"bool not null default false" json:"refunded"`
RefundedAt *time.Time `xorm:"timestampz" json:"refundedAt" time_format:"simple_datetime" time_location:"shanghai"`
}

View File

@ -4,6 +4,7 @@ import (
"electricity_bill_calc/config"
"electricity_bill_calc/global"
"electricity_bill_calc/model"
"electricity_bill_calc/utils"
"time"
"xorm.io/builder"
@ -50,3 +51,20 @@ func (_ChargeRepository) ListPagedChargeRecord(keyword, beginDate, endDate strin
Find(&charges)
return charges, total, err
}
func (_ChargeRepository) LastValidChargeTo(uid string) (time.Time, error) {
veryBlankTime, _ := time.Parse("2006-01-02 15:04:05", "0001-01-01 00:00:00")
var records = make([]time.Time, 0)
err := global.DBConn.Where(builder.Eq{"settled": true, "cancelled": false, "refunded": false}).Cols("charged_to").Find(&records)
if err != nil {
return veryBlankTime, nil
}
lastValid := utils.Reduce(records, veryBlankTime, func(acc, elem time.Time) time.Time {
if elem.After(acc) {
return elem
} else {
return acc
}
})
return lastValid, nil
}

View File

@ -17,6 +17,7 @@ func Router() *gin.Engine {
controller.InitializeUserController(router)
controller.InitializeRegionController(router)
controller.InitializeChargesController(router)
return router
}

View File

@ -1,5 +1,147 @@
package service
import (
"electricity_bill_calc/exceptions"
"electricity_bill_calc/global"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"time"
"xorm.io/builder"
"xorm.io/xorm"
)
type _ChargeService struct{}
var ChargeService _ChargeService
func (c _ChargeService) CreateChargeRecord(charge *model.UserCharge, extendWithIgnoreSettle bool) error {
tx := global.DBConn.NewSession()
defer tx.Close()
if err := tx.Begin(); err != nil {
return err
}
_, 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: &currentTime})
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: &currentTime})
if err != nil {
tx.Rollback()
return err
}
if rows == 0 {
tx.Rollback()
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
}
lastValidExpriation, err := repository.ChargeRepo.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: &currentTime})
if err != nil {
tx.Rollback()
return err
}
if rows == 0 {
tx.Rollback()
return exceptions.NewNotFoundError("未找到匹配指定条件的计费记录。")
}
lastValidExpriation, err := repository.ChargeRepo.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 (_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
}