package controller import ( "electricity_bill_calc/logger" "electricity_bill_calc/model" "electricity_bill_calc/repository" "electricity_bill_calc/response" "electricity_bill_calc/security" "electricity_bill_calc/service" "electricity_bill_calc/tools" "electricity_bill_calc/types" "electricity_bill_calc/vo" "log" "strconv" "github.com/gofiber/fiber/v2" "github.com/jinzhu/copier" "github.com/samber/lo" "go.uber.org/zap" ) var reportLog = logger.Named("Handler", "Report") func InitializeReportHandlers(router *fiber.App) { router.Get("/reports", security.MustAuthenticated, reportComprehensiveSearch) router.Post("/report", security.EnterpriseAuthorize, initNewReportCalculateTask) router.Get("/report/draft", security.EnterpriseAuthorize, listDraftReportIndicies) router.Post("/report/calcualte", security.EnterpriseAuthorize, testCalculateReportSummary) //TODO: 2023-07-20将calcualte错误请求改为正确的calculate请求 router.Post("/report/calculate", security.EnterpriseAuthorize, testCalculateReportSummary) router.Get("/report/calculate/status", security.EnterpriseAuthorize, listCalculateTaskStatus) router.Get("/report/:rid", security.EnterpriseAuthorize, getReportDetail) router.Put("/report/:rid", security.EnterpriseAuthorize, updateReportCalculateTask) router.Post("/report/:rid/publish", security.EnterpriseAuthorize, publishReport) router.Put("/report/:rid/calculate", security.EnterpriseAuthorize, initiateCalculateTask) router.Get("/report/:rid/publics", security.MustAuthenticated, listPublicMetersInReport) router.Get("/report/:rid/summary", security.MustAuthenticated, getReportSummary) router.Get("/report/:rid/summary/filled", security.EnterpriseAuthorize, getParkFilledSummary) router.Get("/report/:rid/pooled", security.MustAuthenticated, listPooledMetersInReport) router.Get("/report/:rid/pooled/:code/submeter", security.MustAuthenticated, listSubmetersInPooledMeter) router.Get("/report/:rid/tenement", security.MustAuthenticated, listTenementsInReport) router.Get("/report/:rid/tenement/:tid", security.MustAuthenticated, getTenementDetailInReport) } // 检查指定报表是否属于当前用户 func checkReportBelongs(reportId string, log *zap.Logger, c *fiber.Ctx, result *response.Result) (bool, error) { session, err := _retreiveSession(c) if err != nil { log.Error("无法获取当前用户的会话信息", zap.Error(err)) return false, result.Unauthorized("无法获取当前用户的会话信息。") } ok, err := repository.ReportRepository.IsBelongsTo(reportId, session.Uid) if err != nil { log.Error("无法检查核算报表的所有权", zap.Error(err)) return false, result.Error(fiber.StatusInternalServerError, "无法检查核算报表的所有权。") } if !ok { log.Error("核算报表不属于当前用户") return false, result.Forbidden("核算报表不属于当前用户。") } return true, nil } // 获取当前登录用户下所有园区的尚未发布的核算报表索引 func listDraftReportIndicies(c *fiber.Ctx) error { result := response.NewResult(c) session, err := _retreiveSession(c) if err != nil { reportLog.Error("无法获取当前用户的会话信息", zap.Error(err)) return result.Unauthorized("无法获取当前用户的会话信息。") } reportLog.Info("检索指定用户下的未发布核算报表索引", zap.String("User", session.Uid)) indicies, err := service.ReportService.ListDraftReportIndicies(session.Uid) if err != nil { reportLog.Error("无法获取当前用户的核算报表索引", zap.Error(err)) return result.NotFound("当前用户下未找到核算报表索引。") } return result.Success( "已经获取到指定用户的报表索引。", fiber.Map{"reports": indicies}, ) } // 初始化一个新的核算任务 func initNewReportCalculateTask(c *fiber.Ctx) error { result := response.NewResult(c) session, err := _retreiveSession(c) if err != nil { reportLog.Error("无法获取当前用户的会话信息", zap.Error(err)) return result.Unauthorized("无法获取当前用户的会话信息。") } reportLog.Info("初始化指定用户的一个新核算任务", zap.String("User", session.Uid)) var form vo.ReportCreationForm if err := c.BodyParser(&form); err != nil { reportLog.Error("无法解析创建核算报表的请求数据。", zap.Error(err)) return result.BadRequest("无法解析创建核算报表的请求数据。") } if pass, err := checkParkBelongs(form.Park, reportLog, c, &result); !pass { return err } ok, err := service.ReportService.CreateNewReport(&form) log.Println("??????????????????????kkkkkkkkkkkkkkkkkkkkkkkkk", ok) if err != nil { reportLog.Error("无法创建核算报表", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法创建核算报表。") } if !ok { reportLog.Error("未能完成核算报表的保存。") return result.NotAccept("未能完成核算报表的保存。") } return result.Success("已经成功创建核算报表。") } // 更新指定的核算任务 func updateReportCalculateTask(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass { return err } var form vo.ReportModifyForm if err := c.BodyParser(&form); err != nil { reportLog.Error("无法解析更新核算报表的请求数据。", zap.Error(err)) return result.BadRequest("无法解析更新核算报表的请求数据。") } ok, err := service.ReportService.UpdateRepoet(reportId, &form) if err != nil { reportLog.Error("无法更新核算报表", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法更新核算报表。") } if !ok { reportLog.Error("未能完成核算报表的更新。") return result.NotAccept("未能完成核算报表的更新。") } return result.Success("已经成功更新核算报表。") } // 启动指定的核算任务 func initiateCalculateTask(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass { return err } err := service.ReportService.DispatchReportCalculate(reportId) if err != nil { reportLog.Error("无法启动核算报表计算任务", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法启动核算报表计算任务。") } //开启核算任务 err = service.ReportService.ReportCalcuateDispatch(reportId) if err != nil { return result.Error(500, "核算任务启动失败"+err.Error()) } return result.Success("已经成功启动核算报表计算任务。") } // 获取自己园区的已经填写的园区电量信息 func getParkFilledSummary(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass { return err } reportLog.Info("获取园区电量信息", zap.String("Report", reportId)) summary, err := repository.ReportRepository.RetrieveReportSummary(reportId) if err != nil { reportLog.Error("无法获取核算报表的园区电量信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表的园区电量信息。") } if summary == nil { reportLog.Error("未找到核算报表的园区电量信息") return result.NotFound("未找到核算报表的园区电量信息。") } var summaryResponse vo.SimplifiedReportSummary copier.Copy(&summaryResponse, summary) return result.Success( "已经获取到核算报表的园区电量信息。", fiber.Map{"summary": summaryResponse}, ) } // 对提供的园区电量信息进行试计算,返回试计算结果 func testCalculateReportSummary(c *fiber.Ctx) error { result := response.NewResult(c) reportLog.Info("试计算园区电量信息") var form vo.TestCalculateForm if err := c.BodyParser(&form); err != nil { reportLog.Error("无法解析试计算核算报表的请求数据。", zap.Error(err)) return result.BadRequest("无法解析试计算核算报表的请求数据。") } return result.Success( "电量电费试计算已经完成。", fiber.Map{"summary": form.Calculate()}, ) } // 获取指定园区中尚未发布的核算报表计算状态 func listCalculateTaskStatus(c *fiber.Ctx) error { result := response.NewResult(c) session, err := _retreiveSession(c) if err != nil { reportLog.Error("无法获取当前用户的会话信息", zap.Error(err)) return result.Unauthorized("无法获取当前用户的会话信息。") } status, err := repository.ReportRepository.GetReportTaskStatus(session.Uid) if err != nil { reportLog.Error("无法获取核算报表计算状态", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表计算状态。") } statusResponse := make([]*vo.ReportCalculateTaskStatusResponse, 0) copier.Copy(&statusResponse, &status) return result.Success( "已经获取到核算报表计算状态。", fiber.Map{"status": statusResponse}, ) } // 获取指定报表的详细信息 func getReportDetail(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") reportLog.Info("获取核算报表的详细信息", zap.String("Report", reportId)) user, park, report, err := service.ReportService.RetrieveReportIndexDetail(reportId) if err != nil { reportLog.Error("无法获取核算报表的详细信息", zap.Error(err)) return result.NotFound("无法获取核算报表的详细信息。") } return result.Success( "已经获取到核算报表的详细信息。", fiber.Map{ "detail": vo.NewReportDetailQueryResponse(user, park, report), }, ) } // 获取指定核算报表的总览信息 func getReportSummary(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") report, err := repository.ReportRepository.RetrieveReportSummary(reportId) if err != nil { reportLog.Error("无法获取核算报表的总览信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表的总览信息。") } if report == nil { reportLog.Error("未找到核算报表的总览信息") return result.NotFound("未找到核算报表的总览信息。") } summaryResponse := vo.ParkSummaryResponse{ ReportId: report.ReportId, OverallDisplay: vo.ConsumptionDisplay{ AmountStr: strconv.FormatFloat(report.Overall.Amount.InexactFloat64(), 'f', -1, 64), FeeStr: strconv.FormatFloat(report.Overall.Fee.InexactFloat64(), 'f', -1, 64), PriceStr: strconv.FormatFloat(report.Overall.Price.InexactFloat64(), 'f', -1, 64), ProportionStr: strconv.FormatFloat(report.Overall.Proportion.InexactFloat64(), 'f', -1, 64), }, Area: report.OverallArea, BasicFee: report.BasicFee, PooledBasicFeeByAmount: report.BasicPooledPriceConsumption.Decimal, PooledBasicFeeByArea: report.BasicPooledPriceArea.Decimal, AdjustFee: report.AdjustFee, PooledAdjustFeeByAmount: report.AdjustPooledPriceConsumption.Decimal, PooledAdjustFeeByArea: report.AdjustPooledPriceArea.Decimal, Consumption: report.ConsumptionFee.Decimal, //Loss: report.Loss.Decimal, Loss: report.AuthorizeLoss.Amount, //LossRate: report.LossFee.Decimal, LossRate: report.AuthorizeLoss.Proportion, } //copier.Copy(&summaryResponse, report) return result.Success( "已经获取到核算报表的总览信息。", fiber.Map{"summary": summaryResponse}, ) } // 获取指定报表中分页的公共表计的核算摘要信息 func listPublicMetersInReport(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") reportLog.Info("获取核算报表中的公共表计信息", zap.String("Report", reportId)) page := c.QueryInt("page", 1) keyword := tools.EmptyToNil(c.Query("keyword")) meters, total, err := repository.ReportRepository.ListPublicMetersInReport(reportId, uint(page), keyword) if err != nil { reportLog.Error("无法获取核算报表中的公共表计信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公共表计信息。") } var meterResponses []vo.Public for _, meter := range meters { meterResponse := vo.Public{ Address: meter.Address, AdjustLoss: model.ConsumptionUnit{ Amount: meter.LossAdjust.Amount, Fee: meter.LossAdjust.Fee, Price: meter.LossAdjust.Price, Proportion: meter.LossAdjust.Proportion, }, Area: meter.Area.Decimal.String(), AttachedAt: meter.AttachedAt, Building: meter.Building, BuildingName: meter.BuildingName, Code: meter.ParkMeterID, DetachedAt: meter.DetachedAt, DisplayRatio: strconv.FormatFloat(meter.DisplayRatio, 'f', -1, 64), Enabled: meter.Enabled, OnFloor: meter.OnFloor, Overall: model.ConsumptionUnit{ Amount: meter.Overall.Amount, Fee: meter.Overall.Fee, Price: meter.Overall.Price, Proportion: meter.Overall.Proportion, }, ParkID: meter.ParkID, Ratio: meter.Ratio.String(), Seq: meter.Seq, Type: float64(meter.MeterType), } meterResponses = append(meterResponses, meterResponse) } return result.Success( "已经获取到指定核算报表中的分页公共表计的核算信息。", response.NewPagedResponse(page, total).ToMap(), fiber.Map{"public": meterResponses}, ) } // 获取指定报表中的分页的公摊表计的核算摘要信息 func listPooledMetersInReport(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") reportLog.Info("获取核算报表中的公摊表计信息", zap.String("Report", reportId)) page := c.QueryInt("page", 1) keyword := tools.EmptyToNil(c.Query("keyword")) meters, total, err := repository.ReportRepository.ListPooledMetersInReport(reportId, uint(page), keyword) if err != nil { reportLog.Error("无法获取核算报表中的公摊表计信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公摊表计信息。") } meterResponse := lo.Map(meters, func(meter *model.ReportDetailedPooledConsumption, _ int) *vo.ReportPooledQueryResponse { m := &vo.ReportPooledQueryResponse{} m.FromReportDetailPooledConsumption(meter) return m }) return result.Success( "已经获取到指定核算报表中的分页公摊表计的核算信息。", response.NewPagedResponse(page, total).ToMap(), fiber.Map{"pooled": meterResponse}, ) } // 列出指定报表中指定公共表计下各个分摊表计的消耗数据 func listSubmetersInPooledMeter(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") meterId := c.Params("code") if len(meterId) == 0 { reportLog.Error("未提供公共表计的编号") return result.BadRequest("未提供公共表计的编号。") } meters, err := repository.ReportRepository.ListPooledMeterDetailInReport(reportId, meterId) if err != nil { reportLog.Error("无法获取核算报表中的公共表计信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公共表计信息。") } meterResponse := lo.Map(meters, func(meter *model.ReportDetailNestedMeterConsumption, _ int) *vo.ReportPooledQueryResponse { m := &vo.ReportPooledQueryResponse{} m.FromReportDetailNestedMeterConsumption(meter) return m }) return result.Success( "已经获取到指定核算报表中的公共表计的核算信息。", fiber.Map{"meters": meterResponse}, ) } // 获取指定报表中分页的商户核算电量电费概要数据 func listTenementsInReport(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") page := c.QueryInt("page", 1) keyword := tools.EmptyToNil(c.Query("keyword")) tenements, total, err := repository.ReportRepository.ListTenementInReport(reportId, uint(page), keyword) if err != nil { reportLog.Error("无法获取核算报表中的商户信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的商户信息。") } tenementsResponse := lo.Map(tenements, func(tenement *model.ReportTenement, _ int) *vo.ReportTenementSummaryResponse { t := &vo.ReportTenementSummaryResponse{} t.FromReportTenement(tenement) return t }) return result.Success( "已经获取到指定核算报表中的分页商户的核算信息。", response.NewPagedResponse(page, total).ToMap(), fiber.Map{"tenements": tenementsResponse}, ) } // 获取指定报表中指定商户的详细核算信息 func getTenementDetailInReport(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") tenementId := c.Params("tid") detail, err := repository.ReportRepository.GetTenementDetailInReport(reportId, tenementId) if err != nil { reportLog.Error("无法获取核算报表中的商户信息", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的商户信息。") } var detailResponse vo.ReportTenementDetailResponse detailResponse.FromReportTenement(detail) return result.Success( "已经获取到指定核算报表中的商户的详细核算信息。", fiber.Map{"detail": detailResponse}, ) } // 发布指定的核算报表 func publishReport(c *fiber.Ctx) error { result := response.NewResult(c) reportId := c.Params("rid") if pass, err := checkReportBelongs(reportId, reportLog, c, &result); !pass { return err } ok, err := repository.ReportRepository.PublishReport(reportId) if err != nil { reportLog.Error("无法发布核算报表", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "发布核算报表出错。") } if !ok { reportLog.Error("未能完成核算报表的发布。") return result.NotAccept("未能完成核算报表的发布。") } return result.Success("已经成功发布核算报表。") } // 对核算报表进行综合检索 func reportComprehensiveSearch(c *fiber.Ctx) error { result := response.NewResult(c) user := tools.EmptyToNil(c.Query("user")) session, err := _retreiveSession(c) if err != nil { reportLog.Error("无法获取当前用户的会话信息", zap.Error(err)) return result.Unauthorized("无法获取当前用户的会话信息。") } park := tools.EmptyToNil(c.Query("park")) if session.Type == model.USER_TYPE_ENT && park != nil && len(*park) > 0 { if pass, err := checkParkBelongs(*park, reportLog, c, &result); !pass { return err } } var requestUser *string if session.Type == model.USER_TYPE_ENT { requestUser = lo.ToPtr(tools.DefaultTo(user, session.Uid)) } else { requestUser = user } page := c.QueryInt("page", 1) keyword := tools.EmptyToNil(c.Query("keyword")) startDate, err := types.ParseDatep(c.Query("period_start")) if err != nil { reportLog.Error("无法解析核算报表查询的开始日期", zap.Error(err)) return result.BadRequest("无法解析核算报表查询的开始日期。") } endDate, err := types.ParseDatep(c.Query("period_end")) if err != nil { reportLog.Error("无法解析核算报表查询的结束日期", zap.Error(err)) return result.BadRequest("无法解析核算报表查询的结束日期。") } reports, total, err := service.ReportService.QueryReports(requestUser, park, uint(page), keyword, startDate, endDate) if err != nil { reportLog.Error("无法查询核算报表", zap.Error(err)) return result.Error(fiber.StatusInternalServerError, "无法查询核算报表。") } return result.Success( "已经获取到指定核算报表的分页信息。", response.NewPagedResponse(page, total).ToMap(), fiber.Map{"reports": reports}, ) }