286 lines
10 KiB
Go
286 lines
10 KiB
Go
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
|
||
}
|