package service import ( "context" "database/sql" "electricity_bill_calc/cache" "electricity_bill_calc/exceptions" "electricity_bill_calc/global" "electricity_bill_calc/logger" "electricity_bill_calc/model" "fmt" "time" "github.com/samber/lo" "github.com/shopspring/decimal" "github.com/uptrace/bun" "go.uber.org/zap" ) type _GodModeService struct { l *zap.Logger } var GodModeService = _GodModeService{ l: logger.Named("Service", "GodMode"), } // 从此处开始为删除报表相关的部分 func (_GodModeService) resetReportIndex(tx *bun.Tx, ctx *context.Context, reportId string) (bool, error) { var report = new(model.Report) err := tx.NewSelect().Model(report).Where("id = ?", reportId).Scan(*ctx) if err != nil { tx.Rollback() return false, err } if report == nil { tx.Rollback() return false, exceptions.NewNotFoundError("指定报表索引未找到。") } report.StepState.Summary = false report.StepState.WillDiluted = false report.StepState.Submeter = false report.StepState.Calculate = false report.StepState.Preview = false report.StepState.Publish = false report.Published = false report.PublishedAt = nil report.Withdraw = model.REPORT_NOT_WITHDRAW report.LastWithdrawAppliedAt = nil report.LastWithdrawAuditAt = nil res, err := tx.NewUpdate().Model(report). WherePK(). Column( "step_state", "published", "published_at", "withdraw", "last_withdraw_applied_at", "last_withdraw_audit_at", ). Exec(*ctx) if affected, _ := res.RowsAffected(); err != nil || affected == 0 { tx.Rollback() return false, err } return true, err } func (_GodModeService) resetReportSummary(tx *bun.Tx, ctx *context.Context, reportId string) (bool, error) { var summary = &model.ReportSummary{ ReportId: reportId, } _, err := tx.NewUpdate().Model(summary).WherePK().Exec(*ctx) if err != nil { tx.Rollback() return false, err } var report = new(model.Report) err = tx.NewSelect().Model(report).WhereAllWithDeleted().Scan(*ctx) if err != nil { tx.Rollback() return false, err } report.StepState.Summary = false res, err := tx.NewUpdate().Model(report).Column("step_state").Exec(*ctx) rows, _ := res.RowsAffected() if err != nil { tx.Rollback() } return rows >= 0, err } func (_GodModeService) flushReportMaintenances(tx *bun.Tx, ctx *context.Context, reportId string) (bool, error) { _, err := tx.NewDelete().Model((*model.WillDilutedFee)(nil)). Where("report_id = ?", reportId). Exec(*ctx) if err != nil { tx.Rollback() return false, err } var report = new(model.Report) err = tx.NewSelect().Model(report).Where("id = ?", reportId).Scan(*ctx) if err != nil { tx.Rollback() return false, err } report.StepState.WillDiluted = false res, err := tx.NewUpdate().Model(report). WherePK(). Column("step_state"). Exec(*ctx) rows, _ := res.RowsAffected() if err != nil { tx.Rollback() } return rows >= 0, err } func (_GodModeService) resetSingleEndUserRecord(tx *bun.Tx, ctx *context.Context, record *model.EndUserDetail, additionalColumns ...string) (bool, error) { record.CurrentPeriodOverall = decimal.Zero record.CurrentPeriodCritical = decimal.Zero record.CurrentPeriodPeak = decimal.Zero record.CurrentPeriodFlat = decimal.Zero record.CurrentPeriodValley = decimal.Zero record.AdjustOverall = decimal.Zero record.AdjustCritical = decimal.Zero record.AdjustPeak = decimal.Zero record.AdjustFlat = decimal.Zero record.AdjustValley = decimal.Zero record.Overall.Valid = false record.OverallFee.Valid = false record.OverallProportion = decimal.Zero record.Critical.Valid = false record.CriticalFee.Valid = false record.Peak.Valid = false record.PeakFee.Valid = false record.Flat.Valid = false record.FlatFee.Valid = false record.Valley.Valid = false record.ValleyFee.Valid = false record.BasicFeeDiluted.Valid = false record.AdjustFeeDiluted.Valid = false record.LossDiluted.Valid = false record.LossFeeDiluted.Valid = false record.MaintenanceFeeDiluted.Valid = false record.FinalDiluted.Valid = false record.PublicConsumptionDiluted.Valid = false record.FinalCharge.Valid = false columns := []string{ "current_period_overall", "current_period_critical", "current_period_peak", "current_period_flat", "current_period_valley", "adjust_overall", "adjust_critical", "adjust_peak", "adjust_flat", "adjust_valley", "overall", "overall_fee", "overall_proportion", "critical", "critical_fee", "peak", "peak_fee", "flat", "flat_fee", "valley", "valley_fee", "baseic_fee_diluted", "adjust_fee_diluted", "loss_diluted", "loss_fee_diluted", "maintenance_fee_diluted", "public_consumption_diluted", "final_diluted", "final_charge", } columns = append(columns, additionalColumns...) res, err := tx.NewUpdate().Model(record). WherePK(). Column(columns...). Exec(*ctx) affected, _ := res.RowsAffected() if err != nil || affected == 0 { tx.Rollback() return false, err } return true, nil } func (g _GodModeService) resynchronizeEndUserArchives(tx *bun.Tx, ctx *context.Context, reportId string) (bool, error) { var currentRecords = make([]*model.EndUserDetail, 0) err := tx.NewSelect().Model(¤tRecords). Where("report_id = ?", reportId). Scan(*ctx) if err != nil { tx.Rollback() return false, err } var report = new(model.Report) err = tx.NewSelect().Model(report). Where("id = ?", reportId). WhereAllWithDeleted(). Scan(*ctx) if err != nil || report == nil { tx.Rollback() return false, err } var latestArchives = make([]model.Meter04KV, 0) err = tx.NewSelect().Model(&latestArchives). Where("park_id = ?", report.ParkId). Where("enabled = ?", true). Scan(*ctx) if err != nil { tx.Rollback() return false, err } for _, meter := range latestArchives { record, has := lo.Find(currentRecords, func(rec *model.EndUserDetail) bool { return rec.ParkId == meter.ParkId && rec.MeterId == meter.Code }) if has { record.CustomerName = meter.CustomerName record.Address = meter.Address record.Ratio = meter.Ratio record.ContactName = meter.ContactName record.ContactPhone = meter.ContactPhone record.Seq = meter.Seq record.IsPublicMeter = meter.IsPublicMeter record.WillDilute = meter.WillDilute success, err := g.resetSingleEndUserRecord( tx, ctx, record, "customer_name", "address", "ratio", "contact_name", "contact_phone", "seq", "public_meter", "dilute", ) if err != nil { return success, err } } else { newEndUser := model.EndUserDetail{ ReportId: report.Id, ParkId: report.ParkId, MeterId: meter.Code, Seq: meter.Seq, Ratio: meter.Ratio, Address: meter.Address, CustomerName: meter.CustomerName, ContactName: meter.ContactName, ContactPhone: meter.ContactPhone, IsPublicMeter: meter.IsPublicMeter, WillDilute: meter.WillDilute, LastPeriodOverall: decimal.Zero, LastPeriodCritical: decimal.Zero, LastPeriodPeak: decimal.Zero, LastPeriodFlat: decimal.Zero, LastPeriodValley: decimal.Zero, } _, err = tx.NewInsert().Model(&newEndUser).Exec(*ctx) if err != nil { tx.Rollback() return false, err } } } report.StepState.Submeter = false res, err := tx.NewUpdate().Model(report). WherePK(). Column("step_state"). Exec(*ctx) rows, _ := res.RowsAffected() if err != nil { tx.Rollback() } return rows >= 0, nil } func (g _GodModeService) resetEndUserRecords(tx *bun.Tx, ctx *context.Context, reportId string) (bool, error) { var records = make([]*model.EndUserDetail, 0) err := tx.NewSelect().Model(&records). Where("report_id = ?", reportId). Scan(*ctx) if err != nil { tx.Rollback() return false, err } for _, u := range records { success, err := g.resetSingleEndUserRecord(tx, ctx, u) if err != nil { return success, err } } var report = new(model.Report) err = tx.NewSelect().Model(report).WhereAllWithDeleted(). Where("id = ?", reportId). Scan(*ctx) if err != nil { tx.Rollback() return false, err } report.StepState.Submeter = false res, err := tx.NewUpdate().Model(report). WherePK(). Column("step_state"). Exec(*ctx) rows, _ := res.RowsAffected() if err != nil { tx.Rollback() } return rows >= 0, nil } type ReportPeriod struct { Id string Period time.Time } func (_GodModeService) isTheLatestReport(ctx *context.Context, reportId string) (bool, error) { var report = new(model.Report) err := global.DB.NewSelect().Model(report). Where("id = ?", reportId). WhereAllWithDeleted(). Scan(*ctx) if err != nil || report == nil { return false, exceptions.NewNotFoundErrorFromError("指定报表索引未找到。", err) } var maxPeriod *time.Time err = global.DB.NewSelect().Model((*model.Report)(nil)). ColumnExpr("max(?)", bun.Ident("period")). Where("park_id = ?", report.ParkId). Scan(*ctx, maxPeriod) if err != nil { return false, err } return maxPeriod.Equal(report.Period), nil } func (_GodModeService) forceDeleteReport(tx *bun.Tx, ctx *context.Context, reportId string) (bool, error) { _, err := tx.NewDelete().Model((*model.EndUserDetail)(nil)). Where("report_id = ?", reportId). Exec(*ctx) if err != nil { tx.Rollback() return false, err } _, err = tx.NewDelete().Model((*model.WillDilutedFee)(nil)). Where("report_id = ?", reportId). Exec(*ctx) if err != nil { tx.Rollback() return false, err } _, err = tx.NewDelete().Model((*model.ReportSummary)(nil)). Where("report_id = ?", reportId). Exec(*ctx) if err != nil { tx.Rollback() return false, err } _, err = tx.NewDelete().Model((*model.Report)(nil)). Where("id = ?", reportId). Exec(*ctx) if err != nil { tx.Rollback() return false, err } return true, nil } func (g _GodModeService) ClearReportSummary(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() isLatest, err := g.isTheLatestReport(&ctx, reportId) if err != nil { return false, err } if !isLatest { return false, exceptions.NewImproperOperateError("不能操作非最新期数的报表。") } tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.resetReportSummary(&tx, &ctx, reportId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) return result, nil } func (g _GodModeService) ClearReportMaintenances(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() isLatest, err := g.isTheLatestReport(&ctx, reportId) if err != nil { return false, err } if !isLatest { return false, exceptions.NewImproperOperateError("不能操作非最新期数的报表。") } tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.flushReportMaintenances(&tx, &ctx, reportId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) return result, nil } func (g _GodModeService) ResynchronizeEndUser(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() isLatest, err := g.isTheLatestReport(&ctx, reportId) if err != nil { return false, err } if !isLatest { return false, exceptions.NewImproperOperateError("不能操作非最新期数的报表。") } tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.resynchronizeEndUserArchives(&tx, &ctx, reportId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation("end_user_detail") cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) return result, nil } func (g _GodModeService) ResetEndUserRegisterRecords(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() isLatest, err := g.isTheLatestReport(&ctx, reportId) if err != nil { return false, err } if !isLatest { return false, exceptions.NewImproperOperateError("不能操作非最新期数的报表。") } tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.resetEndUserRecords(&tx, &ctx, reportId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation("end_user_detail") cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) return result, nil } func (g _GodModeService) ResetReport(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() isLatest, err := g.isTheLatestReport(&ctx, reportId) if err != nil { return false, err } if !isLatest { return false, exceptions.NewImproperOperateError("不能操作非最新期数的报表。") } tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } var result = true r, err := g.resetEndUserRecords(&tx, &ctx, reportId) if err != nil { return false, err } result = result && r r, err = g.flushReportMaintenances(&tx, &ctx, reportId) if err != nil { return false, err } result = result && r r, err = g.resetReportSummary(&tx, &ctx, reportId) if err != nil { return false, err } result = result && r r, err = g.resetReportIndex(&tx, &ctx, reportId) if err != nil { return false, err } result = result && r err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation("end_user_detail") cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) return result, nil } func (g _GodModeService) DeleteReport(reportId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() isLatest, err := g.isTheLatestReport(&ctx, reportId) if err != nil { return false, err } if !isLatest { return false, exceptions.NewImproperOperateError("不能删除非最新期数的报表。") } tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.forceDeleteReport(&tx, &ctx, reportId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation("end_user_detail") cache.AbolishRelation(fmt.Sprintf("report:%s", reportId)) return result, nil } // 从此处开始为删除园区相关的内容部分 func (_GodModeService) deleteSpecificMaintenance(tx *bun.Tx, ctx *context.Context, parkId, maintenanceId string) (bool, error) { res, err := tx.NewDelete().Model((*model.MaintenanceFee)(nil)). Where("park_id = ?", parkId). Where("id = ?", maintenanceId). Exec(*ctx) if err != nil { tx.Rollback() return false, nil } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { return rows >= 0, err } } func (_GodModeService) deleteAllMaintenance(tx *bun.Tx, ctx *context.Context, parkId string) (bool, error) { res, err := tx.NewDelete().Model((*model.MaintenanceFee)(nil)). Where("park_id = ?", parkId). Exec(*ctx) if err != nil { tx.Rollback() return false, nil } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { return rows >= 0, err } } func (_GodModeService) deleteAllMeters(tx *bun.Tx, ctx *context.Context, parkId string) (bool, error) { res, err := tx.NewDelete().Model((*model.Meter04KV)(nil)). Where("park_id = ?", parkId). Exec(*ctx) if err != nil { tx.Rollback() return false, nil } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { return rows >= 0, err } } func (_GodModeService) deletePark(tx *bun.Tx, ctx *context.Context, parkId string) (bool, error) { res, err := tx.NewDelete().Model((*model.Park)(nil)). Where("id = ?", parkId). Exec(*ctx) if err != nil { tx.Rollback() return false, nil } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { return rows >= 0, err } } func (g _GodModeService) RemoveSpecificMaintenance(parkId, maintenanceId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.deleteSpecificMaintenance(&tx, &ctx, parkId, maintenanceId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation(fmt.Sprintf("maintenance_fee:%s", maintenanceId)) return result, nil } func (g _GodModeService) RemoveAllMaintenance(parkId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.deleteAllMaintenance(&tx, &ctx, parkId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation("maintenance_fee") return result, nil } func (g _GodModeService) RemoveAllMeters(parkId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.deleteAllMeters(&tx, &ctx, parkId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation("meter_04kv") return result, nil } func (g _GodModeService) erasePark(tx *bun.Tx, ctx *context.Context, parkId string) (bool, error) { var reportIds = make([]string, 0) err := tx.NewSelect().Model((*model.Report)(nil)). Where("park_id = ?", parkId). Column("id"). Scan(*ctx, &reportIds) if err != nil { tx.Rollback() return false, err } var result = true for _, id := range reportIds { r, err := g.forceDeleteReport(tx, ctx, id) if err != nil { return false, err } result = result && r } r, err := g.deleteAllMaintenance(tx, ctx, parkId) if err != nil { return false, err } result = result && r r, err = g.deleteAllMeters(tx, ctx, parkId) if err != nil { return false, err } result = result && r r, err = g.deletePark(tx, ctx, parkId) if err != nil { return false, err } result = result && r return result, err } func (g _GodModeService) RemovePark(parkId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } result, err := g.erasePark(&tx, &ctx, parkId) if err != nil { return false, err } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation(fmt.Sprintf("park:%s", parkId)) return result, nil } // 从此处开始为删除用户相关的部分 func (g _GodModeService) DeleteUser(userId string) (bool, error) { ctx, cancel := global.TimeoutContext() defer cancel() tx, err := global.DB.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return false, err } var parkIds = make([]string, 0) err = tx.NewSelect().Model((*model.Park)(nil)). Where("user_id = ?", userId). WhereAllWithDeleted(). Column("id"). Scan(ctx, &parkIds) if err != nil { tx.Rollback() return false, err } var result = true for _, p := range parkIds { r, err := g.erasePark(&tx, &ctx, p) if err != nil { return false, err } result = result && r } // 删除用户服务计费数据。 res, err := tx.NewDelete().Model((*model.UserCharge)(nil)). Where("user_id = ?", userId). Exec(ctx) if err != nil { tx.Rollback() return false, err } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { result = result && (rows >= 0) } // 删除用户详细信息数据 res, err = tx.NewDelete().Model((*model.UserDetail)(nil)). Where("user_id = ?", userId). Exec(ctx) if err != nil { tx.Rollback() return false, err } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { result = result && (rows >= 0) } // 删除用户基本索引数据 res, err = tx.NewDelete().Model((*model.User)(nil)). Where("id = ?", userId). Exec(ctx) if err != nil { tx.Rollback() return false, err } if rows, err := res.RowsAffected(); err != nil { tx.Rollback() return false, err } else { result = result && (rows >= 0) } err = tx.Commit() if err != nil { tx.Rollback() return false, err } cache.AbolishRelation(fmt.Sprintf("user:%s", userId)) cache.AbolishRelation("user") cache.AbolishRelation("park") cache.AbolishRelation("report") cache.AbolishRelation("charge") return result, nil }