enhance(report):基本完成报表查询部分的综合服务部分。
This commit is contained in:
parent
fbe4036389
commit
fa03bf5dbd
70
repository/calculate.go
Normal file
70
repository/calculate.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/global"
|
||||
"electricity_bill_calc/logger"
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/types"
|
||||
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
|
||||
"github.com/georgysavva/scany/v2/pgxscan"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type _CalculateRepository struct {
|
||||
log *zap.Logger
|
||||
ds goqu.DialectWrapper
|
||||
}
|
||||
|
||||
var CalculateRepository = _CalculateRepository{
|
||||
log: logger.Named("Repository", "Calculate"),
|
||||
ds: goqu.Dialect("postgres"),
|
||||
}
|
||||
|
||||
// 获取当前正在等待计算的核算任务ID列表
|
||||
func (cr _CalculateRepository) ListPendingTasks() ([]string, error) {
|
||||
cr.log.Info("获取当前正在等待计算的核算任务ID列表")
|
||||
ctx, cancel := global.TimeoutContext()
|
||||
defer cancel()
|
||||
|
||||
var ids []string
|
||||
querySql, queryArgs, _ := cr.ds.
|
||||
From("report_task").
|
||||
Select("id").
|
||||
Where(goqu.C("status").Eq(model.REPORT_CALCULATE_TASK_STATUS_PENDING)).
|
||||
Prepared(true).ToSQL()
|
||||
if err := pgxscan.Select(ctx, global.DB, &ids, querySql, queryArgs...); err != nil {
|
||||
cr.log.Error("未能获取到当前正在等待计算的核算任务ID列表", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// 更新指定报表的核算状态
|
||||
func (cr _CalculateRepository) UpdateReportTaskStatus(rid string, status int16, message *string) (bool, error) {
|
||||
cr.log.Info("更新指定报表的核算状态", zap.String("Report", rid), zap.Int16("Status", status))
|
||||
ctx, cancel := global.TimeoutContext()
|
||||
defer cancel()
|
||||
|
||||
currentTime := types.Now()
|
||||
updateSql, updateArgs, _ := cr.ds.
|
||||
Update("report_task").
|
||||
Set(goqu.Record{
|
||||
"status": status,
|
||||
"last_modified_at": currentTime,
|
||||
"message": message,
|
||||
}).
|
||||
Where(goqu.C("id").Eq(rid)).
|
||||
Prepared(true).ToSQL()
|
||||
res, err := global.DB.Exec(ctx, updateSql, updateArgs...)
|
||||
if err != nil {
|
||||
cr.log.Error("未能更新指定报表的核算状态", zap.Error(err))
|
||||
return false, err
|
||||
}
|
||||
if res.RowsAffected() == 0 {
|
||||
cr.log.Warn("未能保存指定报表的核算状态", zap.String("Report", rid))
|
||||
return false, nil
|
||||
}
|
||||
return res.RowsAffected() > 0, nil
|
||||
}
|
198
service/report.go
Normal file
198
service/report.go
Normal file
|
@ -0,0 +1,198 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/exceptions"
|
||||
"electricity_bill_calc/logger"
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/repository"
|
||||
"electricity_bill_calc/types"
|
||||
"electricity_bill_calc/vo"
|
||||
|
||||
"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
|
||||
}
|
|
@ -135,3 +135,12 @@ func EmptyToNil(val string) *string {
|
|||
}
|
||||
return &val
|
||||
}
|
||||
|
||||
// 将一个`decimal.NullDecimal`类型的值转换为字符串指针,并且在转换的过程中设定其展示位数,默认使用银行进位法。
|
||||
func NullDecimalToString(d decimal.NullDecimal, precision ...int32) *string {
|
||||
precision = append(precision, 2)
|
||||
if !d.Valid {
|
||||
return nil
|
||||
}
|
||||
return lo.ToPtr(d.Decimal.StringFixedBank(precision[0]))
|
||||
}
|
||||
|
|
|
@ -112,3 +112,25 @@ func (dr *DateRange) SetUpperUnbounded() {
|
|||
dr.Range.Upper = MaxDate()
|
||||
dr.Range.UpperType = pgtype.Unbounded
|
||||
}
|
||||
|
||||
func (dr DateRange) SafeUpper() Date {
|
||||
switch dr.Range.UpperType {
|
||||
case pgtype.Inclusive:
|
||||
return dr.Range.Upper
|
||||
case pgtype.Exclusive:
|
||||
return Date{dr.Range.Upper.AddDate(0, 0, -1)}
|
||||
default:
|
||||
return MaxDate()
|
||||
}
|
||||
}
|
||||
|
||||
func (dr DateRange) SafeLower() Date {
|
||||
switch dr.Range.LowerType {
|
||||
case pgtype.Inclusive:
|
||||
return dr.Range.Lower
|
||||
case pgtype.Exclusive:
|
||||
return Date{dr.Range.Lower.AddDate(0, 0, 1)}
|
||||
default:
|
||||
return MinDate()
|
||||
}
|
||||
}
|
||||
|
|
29
vo/park.go
29
vo/park.go
|
@ -3,6 +3,8 @@ package vo
|
|||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/tools"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
type ParkInformationForm struct {
|
||||
|
@ -65,3 +67,30 @@ type ParkBuildingInformationForm struct {
|
|||
Name string `json:"name"`
|
||||
Floors string `json:"floors"`
|
||||
}
|
||||
|
||||
type SimplifiedParkDetail struct {
|
||||
Id string `json:"id"`
|
||||
UserId string `json:"user_id"`
|
||||
Name string `json:"name"`
|
||||
TenementStr *string `json:"tenement"`
|
||||
AreaStr *string `json:"area"`
|
||||
CapacityStr *string `json:"capacity"`
|
||||
Category int16 `json:"category"`
|
||||
MeterType int16 `json:"meter04kvType"`
|
||||
Region *string `json:"region"`
|
||||
Address *string `json:"address"`
|
||||
Contact *string `json:"contact"`
|
||||
Phone *string `json:"phone"`
|
||||
}
|
||||
|
||||
func (spd *SimplifiedParkDetail) TenementQuantity(tq decimal.NullDecimal) {
|
||||
spd.TenementStr = tools.NullDecimalToString(tq)
|
||||
}
|
||||
|
||||
func (spd *SimplifiedParkDetail) Area(area decimal.NullDecimal) {
|
||||
spd.AreaStr = tools.NullDecimalToString(area)
|
||||
}
|
||||
|
||||
func (spd *SimplifiedParkDetail) Capacity(capacity decimal.NullDecimal) {
|
||||
spd.CapacityStr = tools.NullDecimalToString(capacity)
|
||||
}
|
||||
|
|
30
vo/report.go
30
vo/report.go
|
@ -40,3 +40,33 @@ type ReportModifyForm struct {
|
|||
BasicFee decimal.Decimal `json:"basicFee"`
|
||||
AdjustFee decimal.Decimal `json:"adjustFee"`
|
||||
}
|
||||
|
||||
type SimplifiedReportIndex struct {
|
||||
Id string `json:"id"`
|
||||
Park string `json:"parkId"`
|
||||
PeriodBegin types.Date `json:"periodBegin"`
|
||||
PeriodEnd types.Date `json:"periodEnd"`
|
||||
Published bool `json:"published"`
|
||||
PublishedAt *types.DateTime `json:"publishedAt"`
|
||||
Withdraw int16 `json:"withdraw"`
|
||||
LastWithdrawAppliedAt *types.DateTime `json:"lastWithdrawAppliedAt"`
|
||||
LastWithdrawAuditAt *types.DateTime `json:"lastWithdrawAuditAt"`
|
||||
Status int16 `json:"status"`
|
||||
Message *string `json:"message"`
|
||||
}
|
||||
|
||||
func (sri *SimplifiedReportIndex) Period(p types.DateRange) {
|
||||
sri.PeriodBegin = p.SafeLower()
|
||||
sri.PeriodEnd = p.SafeUpper()
|
||||
}
|
||||
|
||||
type ReportIndexQueryResponse struct {
|
||||
Park SimplifiedParkDetail `json:"park"`
|
||||
Report *SimplifiedReportIndex `json:"report"`
|
||||
}
|
||||
|
||||
type ComprehensiveReportQueryResponse struct {
|
||||
Report SimplifiedReportIndex `json:"report"`
|
||||
Park SimplifiedParkDetail `json:"park"`
|
||||
User SimplifiedUserDetail `json:"user"`
|
||||
}
|
||||
|
|
14
vo/user.go
14
vo/user.go
|
@ -2,6 +2,7 @@ package vo
|
|||
|
||||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/tools"
|
||||
"electricity_bill_calc/types"
|
||||
"time"
|
||||
|
||||
|
@ -125,3 +126,16 @@ type RepasswordForm struct {
|
|||
Username string `json:"uname"`
|
||||
NewPassword string `json:"newPass"`
|
||||
}
|
||||
|
||||
type SimplifiedUserDetail struct {
|
||||
Id string `json:"id"`
|
||||
NameStr string `json:"name"`
|
||||
Contact *string `json:"contact"`
|
||||
Phone *string `json:"phone"`
|
||||
Region *string `json:"region"`
|
||||
Address *string `json:"address"`
|
||||
}
|
||||
|
||||
func (sud *SimplifiedUserDetail) Name(n *string) {
|
||||
sud.NameStr = tools.DefaultTo(n, "")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user