From f4ee7cf8a4366202c952c638b3acbf469b78503c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=B6=9B?= Date: Thu, 22 Sep 2022 09:56:33 +0800 Subject: [PATCH] =?UTF-8?q?enhance(enduser):=E5=9F=BA=E6=9C=AC=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=BB=88=E7=AB=AF=E7=94=A8=E6=88=B7=E8=A1=A8=E8=AE=A1?= =?UTF-8?q?=E5=9C=A8=E4=B8=80=E4=B8=AA=E6=97=B6=E9=97=B4=E9=98=B6=E6=AE=B5?= =?UTF-8?q?=E5=86=85=E7=9A=84=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/end_user.go | 32 ++++++++++ controller/maintenance_fee.go | 1 + controller/meter04kv.go | 1 - model/end_user_detail.go | 19 ++++++ model/meter_04kv.go | 1 - model/types.go | 14 ++++- service/end_user.go | 111 ++++++++++++++++++++++++++++++++++ 7 files changed, 176 insertions(+), 3 deletions(-) diff --git a/controller/end_user.go b/controller/end_user.go index 9445102..269c538 100644 --- a/controller/end_user.go +++ b/controller/end_user.go @@ -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}, + ) +} diff --git a/controller/maintenance_fee.go b/controller/maintenance_fee.go index 072bd3d..8f2d5c5 100644 --- a/controller/maintenance_fee.go +++ b/controller/maintenance_fee.go @@ -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 } } diff --git a/controller/meter04kv.go b/controller/meter04kv.go index cd02d2d..79d698e 100644 --- a/controller/meter04kv.go +++ b/controller/meter04kv.go @@ -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) diff --git a/model/end_user_detail.go b/model/end_user_detail.go index 74d3977..233b6bd 100644 --- a/model/end_user_detail.go +++ b/model/end_user_detail.go @@ -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"` +} diff --git a/model/meter_04kv.go b/model/meter_04kv.go index 585d769..407f79b 100644 --- a/model/meter_04kv.go +++ b/model/meter_04kv.go @@ -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:"-"` } diff --git a/model/types.go b/model/types.go index 4103591..90f5713 100644 --- a/model/types.go +++ b/model/types.go @@ -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) { diff --git a/service/end_user.go b/service/end_user.go index e0928ee..d42f3eb 100644 --- a/service/end_user.go +++ b/service/end_user.go @@ -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 +}