enhance(enduser):基本完成终端用户表计在一个时间阶段内的统计功能。

This commit is contained in:
徐涛 2022-09-22 09:56:33 +08:00
parent f8f8a0ced1
commit f4ee7cf8a4
7 changed files with 176 additions and 3 deletions

View File

@ -4,6 +4,7 @@ import (
"database/sql"
"electricity_bill_calc/excel"
"electricity_bill_calc/global"
"electricity_bill_calc/model"
"electricity_bill_calc/response"
"electricity_bill_calc/security"
"electricity_bill_calc/service"
@ -21,6 +22,7 @@ func InitializeEndUserController(router *gin.Engine) {
router.GET("/report/:rid/meter/template", downloadEndUserRegisterTemplate)
router.POST("/report/:rid/meter/batch", security.EnterpriseAuthorize, uploadEndUserRegisterTemplate)
router.PUT("/report/:rid/submeter/:pid/:mid", security.EnterpriseAuthorize, modifyEndUserRegisterRecord)
router.GET("/end/user/adjusts", security.MustAuthenticated, statEndUserInPeriod)
}
func fetchEndUserInReport(c *gin.Context) {
@ -224,3 +226,33 @@ func modifyEndUserRegisterRecord(c *gin.Context) {
}
result.Success("指定终端用户抄表记录已经更新。")
}
func statEndUserInPeriod(c *gin.Context) {
result := response.NewResult(c)
session, err := _retreiveSession(c)
if err != nil {
result.Unauthorized(err.Error())
return
}
requestUser := lo.
If(session.Type == model.USER_TYPE_ENT, session.Uid).
Else(c.DefaultQuery("user", ""))
requestPark := c.DefaultQuery("park", "")
if len(requestPark) > 0 && session.Type == model.USER_TYPE_ENT {
if !ensureParkBelongs(c, result, requestPark) {
result.Unauthorized("不能获取不属于自己的园区。")
return
}
}
startDate := c.DefaultQuery("start", "")
endDate := c.DefaultQuery("end", "")
stat, err := service.EndUserService.StatEndUserRecordInPeriod(requestUser, requestPark, startDate, endDate)
if err != nil {
result.Error(http.StatusInternalServerError, err.Error())
return
}
result.Success(
"已经完成终端用户的费用统计",
gin.H{"details": stat},
)
}

View File

@ -186,6 +186,7 @@ func statAdditionalCharges(c *gin.Context) {
requestPark := c.DefaultQuery("park", "")
if len(requestPark) > 0 && session.Type == model.USER_TYPE_ENT {
if !ensureParkBelongs(c, result, requestPark) {
result.Unauthorized("不能获取不属于自己的园区。")
return
}
}

View File

@ -190,7 +190,6 @@ func batchImport04kVMeterArchive(c *gin.Context) {
mergedMeters := lo.Map(records, func(meter model.Meter04KV, index int) model.Meter04KV {
meter.ParkId = requestParkId
meter.Enabled = true
meter.WillDilute = false
return meter
})
errs = service.Meter04kVService.DuplicateMeterCodeValidate(mergedMeters)

View File

@ -56,6 +56,8 @@ type EndUserDetail struct {
FinalCharge decimal.NullDecimal `bun:"type:numeric" json:"finalCharge"`
Initialize bool `bun:"-" json:"-"`
Origin *Meter04KV `bun:"rel:belongs-to,join:park_id=park_id,join:meter_04kv_id=code" json:"-"`
Report *Report `bun:"rel:belongs-to,join:report_id=id" json:"-"`
Park *Park `bun:"rel:belongs-to,join:park_id=id" json:"-"`
}
var _ bun.BeforeAppendModelHook = (*EndUserDetail)(nil)
@ -110,3 +112,20 @@ type EndUserImport struct {
AdjustFlat decimal.NullDecimal `excel:"adjustFlat"`
AdjustValley decimal.NullDecimal `excel:"adjustValley"`
}
type EndUserPeriodStat struct {
CustomerName string `json:"customerName"`
Address string `json:"address"`
MeterId string `bun:"meter_04kv_id" json:"meterId"`
IsPublicMeter bool `bun:"public_meter" json:"isPublicMeter"`
Overall decimal.NullDecimal `json:"overall"`
Critical decimal.NullDecimal `json:"critical"`
Peak decimal.NullDecimal `json:"peak"`
Valley decimal.NullDecimal `json:"valley"`
OverallFee decimal.NullDecimal `json:"overallFee"`
CriticalFee decimal.NullDecimal `json:"criticalFee"`
PeakFee decimal.NullDecimal `json:"peakFee"`
ValleyFee decimal.NullDecimal `json:"valleyFee"`
AdjustFee decimal.NullDecimal `bun:"final_diluted" json:"adjustFee"`
AdjustProportion decimal.NullDecimal `bun:"-" json:"adjustProportion"`
}

View File

@ -20,7 +20,6 @@ type Meter04KV struct {
Ratio decimal.Decimal `bun:"type:numeric,notnull" json:"ratio" excel:"ratio"`
Seq int64 `bun:"type:bigint,notnull" json:"seq" excel:"seq"`
IsPublicMeter bool `bun:"public_meter,notnull" json:"isPublicMeter" excel:"public"`
WillDilute bool `bun:"dilute,notnull" json:"willDilute" excel:"dilute"`
Enabled bool `bun:",notnull" json:"enabled"`
ParkDetail *Park `bun:"rel:belongs-to,join:park_id=id" json:"-"`
}

View File

@ -29,7 +29,7 @@ func NewEmptyDate() Date {
panic(err)
}
return Date{
Time: time.Date(2000, 1, 1, 0, 0, 0, 0, loc),
Time: time.Time{}.In(loc),
}
}
@ -47,6 +47,18 @@ func ParseDate(t string) (Date, error) {
}, nil
}
func (d Date) IsEmpty() bool {
return d.Time.IsZero()
}
func (d Date) Format(fmt string) string {
return d.Time.Format(fmt)
}
func (d Date) ToString() string {
return d.Time.Format("2006-01-02")
}
var _ driver.Valuer = (*Date)(nil)
func (d Date) Value() (driver.Value, error) {

View File

@ -13,7 +13,9 @@ import (
"fmt"
"io"
"strconv"
"time"
mapset "github.com/deckarep/golang-set/v2"
"github.com/samber/lo"
"github.com/shopspring/decimal"
"github.com/uptrace/bun"
@ -353,3 +355,112 @@ func (es _EndUserService) BatchImportPVRegister(reportId string, file io.Reader)
cache.AbolishRelation("end_user_detail")
return errs
}
func (es _EndUserService) StatEndUserRecordInPeriod(requestUser, requestPark, startDate, endDate string) ([]model.EndUserPeriodStat, error) {
var (
conditions = make([]string, 0)
relations = []string{
fmt.Sprintf("park:%s", requestPark),
"end_user_detail",
}
cond = global.DB.NewSelect().
Model((*model.EndUserDetail)(nil)).
Relation("Report", func(sq *bun.SelectQuery) *bun.SelectQuery {
return sq.ExcludeColumn("*")
}).
Relation("Park", func(sq *bun.SelectQuery) *bun.SelectQuery {
return sq.ExcludeColumn("*")
})
)
if len(requestUser) > 0 {
cond = cond.Where("Park.user_id = ?", requestUser)
conditions = append(conditions, requestUser)
} else {
conditions = append(conditions, "_")
}
if len(requestPark) > 0 {
cond = cond.Where("eud.park_id = ?", requestPark)
conditions = append(conditions, requestPark)
} else {
conditions = append(conditions, "_")
}
if len(startDate) > 0 {
parseTime, err := time.Parse("2006-01", startDate)
if err != nil {
return make([]model.EndUserPeriodStat, 0), fmt.Errorf("不能解析给定的参数[startDate]%w", err)
}
start := model.NewDate(parseTime)
cond = cond.Where("report.period >= ?::date", start.ToString())
conditions = append(conditions, startDate)
} else {
conditions = append(conditions, "_")
}
if len(endDate) > 0 {
parseTime, err := time.Parse("2006-01", endDate)
if err != nil {
return make([]model.EndUserPeriodStat, 0), fmt.Errorf("不能解析给定的参数[endDate]%w", err)
}
end := model.NewDate(parseTime)
cond = cond.Where("report.period <= ?::date", end.ToString())
conditions = append(conditions, endDate)
}
if cached, err := cache.RetreiveSearch[[]model.EndUserPeriodStat]("end_user_stat", conditions...); cached != nil && err == nil {
return *cached, nil
}
ctx, cancel := global.TimeoutContext(120)
defer cancel()
var endUserSums []model.EndUserPeriodStat
err := cond.Column("eud.meter_04kv_id").
ColumnExpr("sum(?) as overall", bun.Ident("eud.overall")).
ColumnExpr("sum(?) as overall_fee", bun.Ident("eud.overall_fee")).
ColumnExpr("sum(?) as critical", bun.Ident("eud.critical")).
ColumnExpr("sum(?) as critical_fee", bun.Ident("eud.critical_fee")).
ColumnExpr("sum(?) as peak", bun.Ident("eud.peak")).
ColumnExpr("sum(?) as peak_fee", bun.Ident("eud.peak_fee")).
ColumnExpr("sum(?) as valley", bun.Ident("eud.valley")).
ColumnExpr("sum(?) as valley_fee", bun.Ident("eud.valley_fee")).
ColumnExpr("sum(?) as final_diluted", bun.Ident("eud.final_diluted")).
Group("eud.meter_04kv_id").
Scan(ctx, &endUserSums)
if err != nil {
return make([]model.EndUserPeriodStat, 0), fmt.Errorf("未能完成终端用户在指定期限内的统计,%w", err)
}
meterIds := lo.Reduce(
endUserSums,
func(acc mapset.Set[string], elem model.EndUserPeriodStat, _ int) mapset.Set[string] {
acc.Add(elem.MeterId)
return acc
},
mapset.NewSet[string](),
)
meterArchives := make([]model.Meter04KV, 0)
if len(meterIds.ToSlice()) > 0 {
err = global.DB.NewSelect().Model(&meterArchives).
Where("code in (?)", bun.In(meterIds.ToSlice())).
Scan(ctx)
if err != nil {
return make([]model.EndUserPeriodStat, 0), fmt.Errorf("未能获取到终端表计的最新基础档案,%w", err)
}
}
filledStats := lo.Map(
endUserSums,
func(elem model.EndUserPeriodStat, _ int) model.EndUserPeriodStat {
archive, has := lo.Find(meterArchives, func(meter model.Meter04KV) bool {
return meter.Code == elem.MeterId
})
if has {
elem.Address = *archive.Address
elem.CustomerName = *archive.CustomerName
elem.IsPublicMeter = archive.IsPublicMeter
}
if !elem.Overall.Decimal.IsZero() {
elem.AdjustProportion = decimal.NewNullDecimal(
elem.AdjustFee.Decimal.Div(elem.OverallFee.Decimal).RoundBank(8),
)
}
return elem
},
)
cache.CacheSearch(filledStats, relations, "end_user_stat", conditions...)
return filledStats, nil
}