package service import ( "electricity_bill_calc/cache" "electricity_bill_calc/config" "electricity_bill_calc/exceptions" "electricity_bill_calc/global" "electricity_bill_calc/logger" "electricity_bill_calc/model" "fmt" "strconv" "time" "github.com/samber/lo" "github.com/uptrace/bun" "go.uber.org/zap" ) type _WithdrawService struct { l *zap.Logger } var WithdrawService = _WithdrawService{ l: logger.Named("Service", "Withdraw"), } func (_WithdrawService) ApplyWithdraw(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() var report *model.Report err := global.DB.NewSelect().Model(report). Where("id = ?", reportId). Scan(ctx) if err != nil || report == nil { return false, exceptions.NewNotFoundErrorFromError("指定报表未能找到", err) } if !report.Published { return false, exceptions.NewImproperOperateError("指定报表尚未发布。") } var maxPublished *time.Time err = global.DB.NewSelect().Model((*model.Report)(nil)). ColumnExpr("max(period)"). Where("park_id = ?", report.ParkId). Where("published = ?", true). Scan(ctx, maxPublished) if err != nil { return false, exceptions.NewNotFoundError("未能找到匹配的系列报表。") } if maxPublished != nil && !report.Period.Equal(*maxPublished) { return false, exceptions.NewImproperOperateError("申请撤回的报表必须是最新已发布的报表。") } report.Withdraw = model.REPORT_WITHDRAW_APPLIED report.LastWithdrawAppliedAt = lo.ToPtr(time.Now()) _, err = global.DB.NewUpdate().Model(report). WherePK(). Column("withdraw", "last_withdraw_applied_at"). Exec(ctx) if err != nil { return false, err } cache.AbolishRelation("withdraw_stat") cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) cache.AbolishRelation(fmt.Sprintf("publicity:%s", reportId)) return true, nil } func (_WithdrawService) FetchPagedWithdrawApplies(page int, keyword string) ([]model.JoinedReportForWithdraw, int64, error) { var ( conditions = make([]string, 0) reports = make([]model.Report, 0) cond = global.DB.NewSelect().Model(&reports). Relation("Park", func(q *bun.SelectQuery) *bun.SelectQuery { return q.Relation("Enterprise") }) ) conditions = append(conditions, strconv.Itoa(int(model.REPORT_WITHDRAW_APPLIED)), strconv.Itoa(page)) cond = cond.Where("r.withdraw = ?", model.REPORT_WITHDRAW_APPLIED) if len(keyword) > 0 { keywordCond := "%" + keyword + "%" cond = cond.WhereGroup(" and ", func(q *bun.SelectQuery) *bun.SelectQuery { return q.Where("p.name like ?", keywordCond). WhereOr("p.abbr like ?", keywordCond). WhereOr("d.name like ?", keywordCond). WhereOr("d.abbr like ?", keywordCond) }) conditions = append(conditions, keyword) } if cachedTotal, err := cache.RetreiveCount("join_report_for_withdraw", conditions...); cachedTotal != -1 && err == nil { if cachedReports, _ := cache.RetreiveSearch[[]model.JoinedReportForWithdraw]("join_user_detail", conditions...); cachedReports != nil { return *cachedReports, cachedTotal, err } } ctx, cancel := global.TimeoutContext() defer cancel() startItem := (page - 1) * config.ServiceSettings.ItemsPageSize total, err := cond.Limit(config.ServiceSettings.ItemsPageSize). Offset(startItem). ScanAndCount(ctx) var ( joinedReports = make([]model.JoinedReportForWithdraw, 0) relations = []string{"report", "park"} ) for _, r := range reports { joinedReports = append(joinedReports, model.JoinedReportForWithdraw{ Report: r, Park: model.FromPark(*r.Park), User: model.FromUserDetail(*r.Park.Enterprise), }) relations = append(relations, fmt.Sprintf("report:%s", r.Id), fmt.Sprintf("publicity:%s", r.Id)) } cache.CacheCount(relations, "join_report_for_withdraw", int64(total), conditions...) cache.CacheSearch(joinedReports, relations, "join_report_for_withdraw", conditions...) return joinedReports, int64(total), err } func (_WithdrawService) AuditWithdraw(reportId string, granted bool) error { ctx, cancel := global.TimeoutContext() defer cancel() var report = new(model.Report) err := global.DB.NewSelect().Model(report). Where("id = ?", reportId). Scan(ctx) if err != nil { return exceptions.NewNotFoundErrorFromError("指定公示报表未找到。", err) } report.Withdraw = lo.If(granted, model.REPORT_WITHDRAW_GRANTED).Else(model.REPORT_WITHDRAW_DENIED) report.LastWithdrawAuditAt = lo.ToPtr(time.Now()) if granted { report.Published = false } _, err = global.DB.NewUpdate().Model(report). WherePK(). Column("withdraw", "last_withdraw_audit_at", "published"). Exec(ctx) if err == nil { cache.AbolishRelation("withdraw_stat") cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) } return err } func (_WithdrawService) AuditWaits() (int64, error) { if cachedWaits, err := cache.RetreiveCount("withdraw_waits"); cachedWaits != -1 && err == nil { return cachedWaits, nil } ctx, cancel := global.TimeoutContext() defer cancel() total, err := global.DB.NewSelect().Model((*model.Report)(nil)). Where("withdraw = ?", model.REPORT_WITHDRAW_APPLIED). Count(ctx) if err == nil { cache.CacheCount([]string{"withdraw_stat"}, "withdraw_waits", int64(total)) } return int64(total), err }