electricity_bill_calc_service/service/report.go

362 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"electricity_bill_calc/exceptions"
"electricity_bill_calc/global"
"electricity_bill_calc/model"
"electricity_bill_calc/tools"
"time"
"github.com/fufuok/utils"
"github.com/google/uuid"
"github.com/samber/lo"
"github.com/shopspring/decimal"
"xorm.io/builder"
)
type _ReportService struct{}
var ReportService _ReportService
func (_ReportService) FetchParksWithNewestReport(uid string) ([]model.ParkNewestReport, error) {
parks := make([]model.ParkNewestReport, 0)
err := global.DBConn.
Alias("p").
Join("LEFT", []string{"report", "r"}, "r.park_id=p.id").
Where(builder.Eq{"p.user_id": uid, "p.enabled": true}).
Find(&parks)
if err != nil {
return make([]model.ParkNewestReport, 0), err
}
reducedParks := lo.Reduce(
parks,
func(acc map[string]model.ParkNewestReport, elem model.ParkNewestReport, index int) map[string]model.ParkNewestReport {
if v, ok := acc[elem.Park.Id]; ok {
if elem.Report != nil {
if v.Report == nil || (elem.Report.Period.After(v.Report.Period)) {
acc[elem.Park.Id] = elem
}
}
} else {
acc[elem.Park.Id] = elem
}
return acc
},
make(map[string]model.ParkNewestReport, 0),
)
return lo.Values(reducedParks), nil
}
func (_ReportService) IsNewPeriodValid(uid string, period time.Time) (bool, error) {
reports := make([]model.Report, 0)
err := global.DBConn.
Table("report").Alias("r").
Join("INNER", []string{"park", "p"}, "r.park_id=p.id").
Where(builder.Eq{"p.user_id": uid}).
Find(&reports)
if err != nil {
return false, nil
}
// 检查给定的期数在目前的记录中是否已经存在
exists := lo.Reduce(
reports,
func(acc bool, elem model.Report, index int) bool {
if elem.Period.Equal(period) {
return acc || true
} else {
return acc || false
}
},
false,
)
if exists {
return false, nil
}
// 检查给定的期数与目前已发布的最大期数的关系
maxPublished := lo.Reduce(
reports,
func(acc *time.Time, elem model.Report, index int) *time.Time {
if elem.Published {
if acc == nil || (acc != nil && elem.Period.After(*acc)) {
return &elem.Period
}
}
return acc
},
nil,
)
// 检查给定的期数与目前未发布的最大期数的关系
maxUnpublished := lo.Reduce(
reports,
func(acc *time.Time, elem model.Report, index int) *time.Time {
if acc == nil || (acc != nil && elem.Period.After(*acc)) {
return &elem.Period
}
return acc
},
nil,
)
if maxUnpublished == nil {
return true, nil
}
if maxPublished != nil && maxUnpublished.Equal(*maxPublished) {
// 此时不存在未发布的报表
return tools.IsNextMonth(*maxPublished, period), nil
} else {
// 存在未发布的报表
return false, nil
}
}
func (_ReportService) InitializeNewReport(parkId string, period time.Time) (err error) {
periods := make([]model.Report, 0)
err = global.DBConn.
Table("report").
Where(builder.Eq{"park_id": parkId, "published": true}).
Asc("period").
Find(&periods)
if err != nil {
return
}
// 获取上一期的报表索引信息
maxPublishedReport := lo.Reduce(
periods,
func(acc *model.Report, elem model.Report, index int) *model.Report {
if acc == nil || (acc != nil && elem.Period.After(acc.Period)) {
return &elem
}
return acc
},
nil,
)
var indexedLastPeriodCustomers map[string]model.EndUserDetail
if maxPublishedReport != nil {
// 获取上一期的所有户表信息,并获取当前已启用的所有用户
lastPeriodCustomers := make([]model.EndUserDetail, 0)
err = global.DBConn.Where(builder.Eq{"report_id": maxPublishedReport.Id}).Find(&lastPeriodCustomers)
if err != nil {
return
}
indexedLastPeriodCustomers = lo.Reduce(
lastPeriodCustomers,
func(acc map[string]model.EndUserDetail, elem model.EndUserDetail, index int) map[string]model.EndUserDetail {
acc[elem.MeterId] = elem
return acc
},
make(map[string]model.EndUserDetail, 0),
)
} else {
indexedLastPeriodCustomers = make(map[string]model.EndUserDetail, 0)
}
currentActivatedCustomers := make([]model.Meter04KV, 0)
err = global.DBConn.Where(builder.Eq{"park_id": parkId, "enabled": true}).Find(&currentActivatedCustomers)
if err != nil {
return
}
// 生成新一期的报表
tx := global.DBConn.NewSession()
if err = tx.Begin(); err != nil {
return
}
defer tx.Close()
// 插入已经生成的报表索引信息和园区概况信息
newReport := model.Report{
Id: uuid.New().String(),
ParkId: parkId,
Period: period,
StepState: model.NewSteps(),
Published: false,
Withdraw: model.REPORT_NOT_WITHDRAW,
}
newReportSummary := model.ReportSummary{
ReportId: newReport.Id,
}
_, err = tx.Insert(newReport, newReportSummary)
if err != nil {
tx.Rollback()
return
}
// 生成并插入户表信息
for _, customer := range currentActivatedCustomers {
newEndUser := model.EndUserDetail{
ReportId: newReport.Id,
ParkId: parkId,
MeterId: customer.Code,
Seq: customer.Seq,
Ratio: customer.Ratio,
Address: customer.Address,
CustomerName: customer.CustomerName,
ContactName: customer.ContactName,
ContactPhone: customer.ContactPhone,
IsPublicMeter: customer.IsPublicMeter,
WillDilute: customer.WillDilute,
LastPeriodOverall: decimal.Zero,
LastPeriodCritical: decimal.Zero,
LastPeriodPeak: decimal.Zero,
LastPeriodFlat: decimal.Zero,
LastPeriodValley: decimal.Zero,
}
if lastPeriod, ok := indexedLastPeriodCustomers[customer.Code]; ok {
newEndUser.LastPeriodOverall = lastPeriod.CurrentPeriodOverall
newEndUser.LastPeriodCritical = lastPeriod.CurrentPeriodCritical
newEndUser.LastPeriodPeak = lastPeriod.CurrentPeriodPeak
newEndUser.LastPeriodFlat = lastPeriod.CurrentPeriodFlat
newEndUser.LastPeriodValley = lastPeriod.CurrentPeriodValley
}
_, err = tx.Insert(newEndUser)
if err != nil {
tx.Rollback()
return
}
}
err = tx.Commit()
if err != nil {
tx.Rollback()
return
}
return nil
}
func (_ReportService) RetreiveReportIndex(rid string) (*model.Report, error) {
reports := make([]model.Report, 0)
err := global.DBConn.Where(builder.Eq{"id": rid}).Find(&reports)
if err != nil {
return nil, err
}
if len(reports) > 0 {
return &reports[0], nil
} else {
return nil, nil
}
}
func (_ReportService) RetreiveReportSummary(rid string) (*model.ReportSummary, error) {
var summary = new(model.ReportSummary)
_, err := global.DBConn.ID(rid).NoAutoCondition().Get(summary)
if err != nil {
return nil, err
}
return summary, nil
}
func (_ReportService) UpdateReportSummary(summary *model.ReportSummary) error {
_, err := global.DBConn.ID(summary.ReportId).Cols("overall", "overall_fee", "critical", "critical_fee", "peak", "peak_fee", "valley", "valley_fee", "basic_fee", "adjust_fee").Update(summary)
return err
}
func (_ReportService) CalculateSummaryAndFinishStep(reportId string) error {
var report = new(model.Report)
has, err := global.DBConn.ID(reportId).NoAutoCondition().Get(report)
if err != nil {
return err
}
if !has {
return exceptions.NewNotFoundError("未找到指定报表")
}
var summary = new(model.ReportSummary)
has, err = global.DBConn.ID(reportId).NoAutoCondition().Get(summary)
if err != nil {
return err
}
if !has {
return exceptions.NewNotFoundError("未找到指定报表的园区概况")
}
tx := global.DBConn.NewSession()
if err = tx.Begin(); err != nil {
return err
}
defer tx.Close()
summary.CalculatePrices()
_, err = tx.ID(summary.ReportId).Cols("overall_price", "critical_price", "peak_price", "flat", "flat_fee", "flat_price", "valley_price").Update(summary)
if err != nil {
tx.Rollback()
return err
}
report.StepState.Summary = true
_, err = tx.ID(report.Id).Cols("step_state").Update(report)
if err != nil {
tx.Rollback()
return err
}
err = tx.Commit()
if err != nil {
tx.Rollback()
return err
}
return nil
}
func (_ReportService) FetchWillDulutedMaintenanceFees(reportId string) ([]model.WillDilutedFee, error) {
fees := make([]model.WillDilutedFee, 0)
err := global.DBConn.Where(builder.Eq{"report_id": reportId}).Asc("created_at").Find(&fees)
if err != nil {
return make([]model.WillDilutedFee, 0), nil
}
return fees, nil
}
func (_ReportService) CreateTemporaryWillDilutedMaintenanceFee(fee model.WillDilutedFee) error {
fee.Id = utils.UUIDString()
_, err := global.DBConn.Insert(fee)
return err
}
func (_ReportService) BatchSaveMaintenanceFee(reportId string, fees []model.WillDilutedFee) error {
tx := global.DBConn.NewSession()
if err := tx.Begin(); err != nil {
return err
}
defer tx.Close()
// 首先删除所有预定义的部分条件是指定报表IDSourceID不为空。
cond := builder.Eq{"report_id": reportId}.And(builder.NotNull{"source_id"})
_, err := tx.Table(new(model.WillDilutedFee)).Where(cond).Delete()
if err != nil {
tx.Rollback()
return err
}
// 然后插入新的记录
_, err = tx.Insert(fees)
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
tx.Rollback()
return err
}
return nil
}
func (_ReportService) UpdateMaintenanceFee(feeId string, updates map[string]interface{}) (err error) {
_, err = global.DBConn.Table(new(model.WillDilutedFee)).ID(feeId).Update(updates)
return
}
func (_ReportService) DeleteWillDilutedFee(fee string) (err error) {
_, err = global.DBConn.ID(fee).NoAutoCondition().Delete(new(model.WillDilutedFee))
return
}
func (_ReportService) ProgressReportWillDilutedFee(report model.Report) (err error) {
report.StepState.WillDiluted = true
_, err = global.DBConn.ID(report.Id).Cols("step_state").Update(report)
return
}
func (_ReportService) RetreiveParkEndUserMeterType(reportId string) (int, error) {
var types = make([]int, 0)
err := global.DBConn.
Table("park").Alias("p").
Join("INNER", []string{"report", "r"}, "r.park_id=p.id").
Where(builder.Eq{"r.id": reportId}).
Select("p.meter_04kv_type").
Find(&types)
if err != nil {
return -1, err
}
if len(types) == 0 {
return -1, nil
}
return types[0], nil
}