electricity_bill_calc_service/service/report.go

287 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/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/service/calculate"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"github.com/pkg/errors"
"sync"
"github.com/doug-martin/goqu/v9"
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
"github.com/jinzhu/copier"
"github.com/samber/lo"
"go.uber.org/zap"
)
type _ReportService struct {
log *zap.Logger
ds goqu.DialectWrapper
}
var ReportService = _ReportService{
log: logger.Named("Service", "Report"),
ds: goqu.Dialect("postgres"),
}
// 将指定报表列入计算任务
func (rs _ReportService) DispatchReportCalculate(rid string) error {
rs.log.Info("将指定报表列入计算任务", zap.String("Report", rid))
_, err := repository.CalculateRepository.UpdateReportTaskStatus(rid, model.REPORT_CALCULATE_TASK_STATUS_PENDING, nil)
if err != nil {
rs.log.Error("未能将指定报表列入计算任务", zap.Error(err))
return err
}
return nil
}
// 列出指定用户下的所有尚未发布的报表索引
func (rs _ReportService) ListDraftReportIndicies(uid string) ([]*vo.ReportIndexQueryResponse, error) {
rs.log.Info("列出指定用户下的所有尚未发布的报表", zap.String("User", uid))
indicies, err := repository.ReportRepository.ListDraftReportIndicies(uid)
if err != nil {
rs.log.Error("未能获取指定用户下所有未发布报表的索引", zap.Error(err))
return make([]*vo.ReportIndexQueryResponse, 0), err
}
parkIds := lo.Map(indicies, func(elem *model.ReportIndex, _ int) string {
return elem.Park
})
parks, err := repository.ParkRepository.RetrieveParks(parkIds)
if err != nil {
rs.log.Error("未能获取到相应报表对应的园区详细信息", zap.Error(err))
return make([]*vo.ReportIndexQueryResponse, 0), err
}
assembled := lo.Reduce(indicies, func(acc []*vo.ReportIndexQueryResponse, elem *model.ReportIndex, _ int) []*vo.ReportIndexQueryResponse {
park, _ := lo.Find(parks, func(park *model.Park) bool {
return park.Id == elem.Park
})
var (
simplifiedPark vo.SimplifiedParkDetail
simplifiedReport vo.SimplifiedReportIndex
)
copier.Copy(&simplifiedPark, park)
copier.Copy(&simplifiedReport, elem)
acc = append(acc, &vo.ReportIndexQueryResponse{
Park: simplifiedPark,
Report: lo.ToPtr(simplifiedReport),
})
return acc
}, make([]*vo.ReportIndexQueryResponse, 0))
return assembled, nil
}
// 获取指定报表中的包含索引、园区以及用户信息的详细信息
func (rs _ReportService) RetrieveReportIndexDetail(rid string) (*model.UserDetail, *model.Park, *model.ReportIndex, error) {
index, err := repository.ReportRepository.GetReportIndex(rid)
if err != nil {
rs.log.Error("未能获取到指定报表的索引", zap.Error(err))
return nil, nil, nil, exceptions.NewNotFoundErrorFromError("未能获取到指定报表的索引", err)
}
park, err := repository.ParkRepository.RetrieveParkDetail(index.Park)
if err != nil {
rs.log.Error("未能获取到指定报表对应的园区详细信息", zap.Error(err))
return nil, nil, nil, exceptions.NewNotFoundErrorFromError("未能获取到指定报表对应的园区详细信息", err)
}
user, err := repository.UserRepository.FindUserDetailById(park.UserId)
if err != nil {
rs.log.Error("未能获取到指定报表对应的用户详细信息", zap.Error(err))
return nil, nil, nil, exceptions.NewNotFoundErrorFromError("未能获取到指定报表对应的用户详细信息", err)
}
return user, park, index, nil
}
// 根据给定的园区ID列表查询园区以及用户的详细信息
func (rs _ReportService) queryParkAndUserDetails(pids []string) ([]*model.Park, []*model.UserDetail, error) {
parks, err := repository.ParkRepository.RetrieveParks(pids)
if err != nil {
rs.log.Error("未能获取到相应报表对应的园区详细信息", zap.Error(err))
return make([]*model.Park, 0), make([]*model.UserDetail, 0), exceptions.NewNotFoundErrorFromError("未能获取到相应报表对应的园区详细信息", err)
}
userIds := lo.Map(parks, func(elem *model.Park, _ int) string {
return elem.UserId
})
users, err := repository.UserRepository.RetrieveUsersDetail(userIds)
if err != nil {
rs.log.Error("未能获取到相应报表对应的用户详细信息", zap.Error(err))
return make([]*model.Park, 0), make([]*model.UserDetail, 0), exceptions.NewNotFoundErrorFromError("未能获取到相应报表对应的用户详细信息", err)
}
return parks, users, nil
}
// 查询指定的核算报表列表
func (rs _ReportService) QueryReports(uid, pid *string, page uint, keyword *string, periodBegin, periodEnd *types.Date) ([]*vo.ComprehensiveReportQueryResponse, int64, error) {
rs.log.Info("查询指定的核算报表列表", zap.Stringp("User", uid), zap.Stringp("Park", pid), zap.Uint("Page", page), zap.Stringp("Keyword", keyword), logger.DateFieldp("PeriodBegin", periodBegin), logger.DateFieldp("PeriodEnd", periodEnd))
reports, total, err := repository.ReportRepository.ComprehensiveReportSearch(uid, pid, page, keyword, periodBegin, periodEnd)
if err != nil {
rs.log.Error("未能查询到指定的核算报表列表", zap.Error(err))
return make([]*vo.ComprehensiveReportQueryResponse, 0), 0, err
}
parkIds := lo.Map(reports, func(elem *model.ReportIndex, _ int) string {
return elem.Park
})
parks, users, err := rs.queryParkAndUserDetails(parkIds)
if err != nil {
return make([]*vo.ComprehensiveReportQueryResponse, 0), 0, err
}
assembled := lo.Reduce(
reports,
func(acc []*vo.ComprehensiveReportQueryResponse, elem *model.ReportIndex, _ int) []*vo.ComprehensiveReportQueryResponse {
park, _ := lo.Find(parks, func(park *model.Park) bool {
return park.Id == elem.Park
})
user, _ := lo.Find(users, func(user *model.UserDetail) bool {
return user.Id == park.UserId
})
var (
simplifiedUser vo.SimplifiedUserDetail
simplifiedPark vo.SimplifiedParkDetail
simplifiedReport vo.SimplifiedReportIndex
)
copier.Copy(&simplifiedUser, user)
copier.Copy(&simplifiedPark, park)
copier.Copy(&simplifiedReport, elem)
acc = append(acc, &vo.ComprehensiveReportQueryResponse{
User: simplifiedUser,
Park: simplifiedPark,
Report: simplifiedReport,
})
return acc
},
make([]*vo.ComprehensiveReportQueryResponse, 0),
)
return assembled, total, nil
}
// 查询当前待审核的核算报表撤回申请列表
func (rs _ReportService) ListWithdrawalRequests(page uint, keyword *string) ([]*vo.ComprehensiveReportQueryResponse, int64, error) {
rs.log.Info("查询当前待审核的核算报表撤回申请列表", zap.Uint("Page", page), zap.Stringp("Keyword", keyword))
reports, total, err := repository.ReportRepository.ListWithdrawAppliedReports(page, keyword)
if err != nil {
rs.log.Error("未能查询到当前待审核的核算报表撤回申请列表", zap.Error(err))
return make([]*vo.ComprehensiveReportQueryResponse, 0), 0, err
}
parkIds := lo.Map(reports, func(elem *model.ReportIndex, _ int) string {
return elem.Park
})
parks, users, err := rs.queryParkAndUserDetails(parkIds)
if err != nil {
return make([]*vo.ComprehensiveReportQueryResponse, 0), 0, err
}
assembled := lo.Reduce(
reports,
func(acc []*vo.ComprehensiveReportQueryResponse, elem *model.ReportIndex, _ int) []*vo.ComprehensiveReportQueryResponse {
park, _ := lo.Find(parks, func(park *model.Park) bool {
return park.Id == elem.Park
})
user, _ := lo.Find(users, func(user *model.UserDetail) bool {
return user.Id == park.UserId
})
var (
simplifiedUser vo.SimplifiedUserDetail
simplifiedPark vo.SimplifiedParkDetail
simplifiedReport vo.SimplifiedReportIndex
)
copier.Copy(&simplifiedUser, user)
copier.Copy(&simplifiedPark, park)
copier.Copy(&simplifiedReport, elem)
acc = append(acc, &vo.ComprehensiveReportQueryResponse{
User: simplifiedUser,
Park: simplifiedPark,
Report: simplifiedReport,
})
return acc
},
make([]*vo.ComprehensiveReportQueryResponse, 0),
)
return assembled, total, nil
}
// 定时检测执行电费核算任务的分发
func (rs _ReportService) ReportCalcuateDispatch(rid string) error {
err := rs.CalculateReport(rid)
if err != nil {
return errors.Wrap(err, "报表计算调度时发生错误")
}
return nil
}
// 创建一个新的核算报表,并同时完成核算报表的计算
func (rs _ReportService) CreateNewReport(createFrom *vo.ReportCreationForm) (bool, error) {
state, report, err := repository.ReportRepository.CreateReport(createFrom)
if err != nil {
rs.log.Error("创建核算报表错误", zap.Error(err))
return false, err
}
if !state {
status, err := repository.CalculateRepository.UpdateReportCalculateStatus(report, "InsufficientData",
"创建报表时发生错误,需手动再次计算")
if err != nil {
rs.log.Error("创建报表时发生错误,需手动再次计算", zap.Error(err))
return false, err
}
return status, nil
}
err = rs.CalculateReport(report)
if err != nil {
rs.log.Error("计算时出错", zap.Error(err))
return false, err
}
return true, nil
}
// 更新一个核算报表中的数据,并同时完成计算
func (rs _ReportService) UpdateRepoet(rid string, updateForm *vo.ReportModifyForm) (bool, error) {
state, err := repository.ReportRepository.UpdateReportSummary(rid, updateForm)
if err != nil {
rs.log.Error("更新摘要出错", zap.Error(err))
return false, err
}
if !state {
return false, nil
}
err = rs.CalculateReport(rid)
if err != nil {
rs.log.Error("计算时出错", zap.Error(err))
return false, err
}
return true, nil
}
var CALCULATE_TASK_PARALLEL_CONTROL = func() *sync.Mutex {
s := sync.Mutex{}
s.Lock()
return &s
}()
// 执行一个核算报表的计算任务
func (rs _ReportService) CalculateReport(rid string) error {
semaphore := CALCULATE_TASK_PARALLEL_CONTROL
semaphore.Lock()
defer semaphore.Unlock()
errs := calculate.MainCalculateProcess(rid)
if errs == nil {
_, err := repository.CalculateRepository.UpdateReportCalculateStatus(rid, "success", "")
if err != nil {
rs.log.Error("执行核算报表计算任务失败", zap.Error(err))
return err
}
} else {
_, err := repository.CalculateRepository.UpdateReportCalculateStatus(rid, "InsufficientData", errs.Error())
if err != nil {
rs.log.Error("执行核算报表计算任务失败", zap.Error(err))
return err
}
rs.log.Error("核算报表"+rid+"时发生错误:"+errs.Error()+"", zap.Error(errs))
return err
}
return nil
}