From 648fc0f370236aee50da98a127f1a0aca0ba38a6 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Tue, 18 Jul 2023 16:07:56 +0800 Subject: [PATCH 01/24] =?UTF-8?q?new=EF=BC=9A=E6=96=B0=E5=A2=9Ewithdraw?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=EF=BC=8C=E8=AF=A5=E6=9A=82=E6=97=A0=E7=9C=9F?= =?UTF-8?q?=E5=AE=9E=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dataSources.xml | 11 ++++ .idea/electricity_bill_calc_service.iml | 8 +++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/vcs.xml | 6 ++ controller/user.go | 27 ++++----- controller/withdraw.go | 74 +++++++++++++++++++++++++ doc/routerSetting.md | 13 +++++ global/db.go | 3 + global/redis.go | 7 ++- response/user_response.go | 2 +- router/router.go | 25 +++++---- service/user.go | 2 +- settings.yaml | 4 +- 14 files changed, 165 insertions(+), 31 deletions(-) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/electricity_bill_calc_service.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 controller/withdraw.go create mode 100644 doc/routerSetting.md diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..0973c28 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,11 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://39.105.39.8:9432/postgres + + + \ No newline at end of file diff --git a/.idea/electricity_bill_calc_service.iml b/.idea/electricity_bill_calc_service.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/electricity_bill_calc_service.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..95c0f54 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/controller/user.go b/controller/user.go index c79385e..7240728 100644 --- a/controller/user.go +++ b/controller/user.go @@ -42,34 +42,35 @@ type _LoginForm struct { } func doLogin(c *fiber.Ctx) error { - result := response.NewResult(c) - loginData := new(_LoginForm) - if err := c.BodyParser(loginData); err != nil { + result := response.NewResult(c) //创建一个相应结果对象 + loginData := new(_LoginForm) //创建一个解析登录表单数据的实体 + if err := c.BodyParser(loginData); err != nil { //解析请求体中的Json数据到loginData里,如果解析出错就返回错误 userLog.Error("表单解析失败!", zap.Error(err)) - return result.Error(http.StatusInternalServerError, "表单解析失败。") + return result.Error(http.StatusInternalServerError, "表单解析失败。") //返回一个内部服务器错误的相应结果 } var ( session *model.Session err error ) - userLog.Info("有用户请求登录。", zap.String("username", loginData.Username), zap.Int16("type", loginData.Type)) - if loginData.Type == model.USER_TYPE_ENT { - session, err = service.UserService.ProcessEnterpriseUserLogin(loginData.Username, loginData.Password) + userLog.Info("有用户请求登录。", zap.String("username", loginData.Username), zap.Int16("type", loginData.Type)) //记录日志相关信息 + if loginData.Type == model.USER_TYPE_ENT { //根据登录类型选择不同的处理方法 + session, err = service.UserService.ProcessEnterpriseUserLogin(loginData.Username, loginData.Password) //企业用户 } else { - session, err = service.UserService.ProcessManagementUserLogin(loginData.Username, loginData.Password) + userLog.Info("该用户是管理用户") + session, err = service.UserService.ProcessManagementUserLogin(loginData.Username, loginData.Password) //管理用户 } if err != nil { - if authError, ok := err.(*exceptions.AuthenticationError); ok { - if authError.NeedReset { + if authError, ok := err.(*exceptions.AuthenticationError); ok { //检查错误是否为身份验证错误 + if authError.NeedReset { //如果需要重置密码则返回对应结果 return result.LoginNeedReset() } - return result.Error(int(authError.Code), authError.Message) + return result.Error(int(authError.Code), authError.Message) //返回身份验证错误相应 } else { userLog.Error("用户登录请求处理失败!", zap.Error(err)) - return result.Error(http.StatusInternalServerError, err.Error()) + return result.Error(http.StatusInternalServerError, err.Error()) //返回内部服务器错误 } } - return result.LoginSuccess(session) + return result.LoginSuccess(session) //返回登录成功相应结果,包含会话信息 } func doLogout(c *fiber.Ctx) error { diff --git a/controller/withdraw.go b/controller/withdraw.go new file mode 100644 index 0000000..cc490ac --- /dev/null +++ b/controller/withdraw.go @@ -0,0 +1,74 @@ +package controller + +import ( + "electricity_bill_calc/logger" + "electricity_bill_calc/response" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +var withdrawLog = logger.Named("Handler", "Withdraw") + +func InitializeWithdrawHandlers(router *fiber.App) { + router.Get("/withdraw", withdraw) +} + +//用于检索用户的核算报表 +func withdraw(c *fiber.Ctx) error { + //记录日志 + withdrawLog.Info("带分页的待审核的核算撤回申请列表") + //获取请求参数 + result := response.NewResult(c) + keyword := c.Query("keyword", "") + page := c.QueryInt("page", 1) + withdrawLog.Info("参数为: ", zap.String("keyword", keyword), zap.Int("page", page)) + //中间数据库操作暂且省略。。。。 + //首先进行核算报表的分页查询 + + //TODO: 2023-07-18 此处的data需要经过上面数据库查询后进行数据返回,此处只是作于演示 + data := fiber.Map{ + "report": fiber.Map{ + "id": "string", + "parkId": "string", + "periodBegin": "string", + "periodEnd": "string", + "published": true, + "publishedAt": "string", + "withdraw": 0, + "lastWithdrawAppliedAt": "string", + "lastWithdrawAuditAt": "string", + "status": 0, + "message": "string", + }, + "park": fiber.Map{ + "id": "string", + "userId": "string", + "name": "string", + "tenement": "string", + "area": "string", + "capacity": "string", + "category": 0, + "meter04kvType": 0, + "region": "string", + "address": "string", + "contact": "string", + "phone": "string", + }, + "user": fiber.Map{ + "id": "string", + "name": "string", + "contact": "string", + "phone": "string", + "region": "string", + "address": "string", + }, + } + datas := make([]interface{}, 0) + datas = append(datas, data) + //TODO: 2023-07-18 此处返回值是个示例,具体返回值需要查询数据库 + return result.Success( + "withdraw请求成功", + response.NewPagedResponse(page, 20).ToMap(), + fiber.Map{"records": datas}, + ) +} diff --git a/doc/routerSetting.md b/doc/routerSetting.md new file mode 100644 index 0000000..6e9c627 --- /dev/null +++ b/doc/routerSetting.md @@ -0,0 +1,13 @@ +## fiber +#### fiber实例 +- app(是fiber创建的实例通常用app表示,其中有可选配置选项) + - BodyLimit 设置请求正文允许的最大大小(默认为4 * 1024 * 1024) + - EnablePrintRoutes 不打印框架自带日志(默认false) + - EnableTrustedProxyCheck 禁用受信代理(默认false) + - Prefork 预处理配置(默认false) + - ErrorHandler 全局错误处理 (默认false) + - JSONEncoder json编码 (默认json.Marshal) + - JSONDecoder json解码 (默认json.Unmarshal) + - 。。。。。。。。(还有很多配置) +- Use(中间件设置,一个或者多个) +- Group(类似于gin框架中的路由分组) \ No newline at end of file diff --git a/global/db.go b/global/db.go index 1acdc74..a19c5f4 100644 --- a/global/db.go +++ b/global/db.go @@ -53,6 +53,9 @@ func (ql QueryLogger) TraceQueryStart(ctx context.Context, conn *pgx.Conn, data ql.logger.Info("查询参数", lo.Map(data.Args, func(elem any, index int) zap.Field { return zap.Any(fmt.Sprintf("[Arg %d]: ", index), elem) })...) + // for index, arg := range data.Args { + // ql.logger.Info(fmt.Sprintf("[Arg %d]: %v", index, arg)) + // } return ctx } diff --git a/global/redis.go b/global/redis.go index e99c19f..8afb039 100644 --- a/global/redis.go +++ b/global/redis.go @@ -15,10 +15,13 @@ var ( func SetupRedisConnection() error { var err error + a := fmt.Sprintf("%s:%d", config.RedisSettings.Host, config.RedisSettings.Port) + fmt.Println(a) Rd, err = rueidis.NewClient(rueidis.ClientOption{ - InitAddress: []string{fmt.Sprintf("%s:%d", config.RedisSettings.Host, config.RedisSettings.Port)}, - Password: config.RedisSettings.Password, + InitAddress: []string{"127.0.0.1:6379"}, + Password: "", SelectDB: config.RedisSettings.DB, + DisableCache:true, }) if err != nil { return err diff --git a/response/user_response.go b/response/user_response.go index 9eaf458..a60086e 100644 --- a/response/user_response.go +++ b/response/user_response.go @@ -16,7 +16,7 @@ type LoginResponse struct { func (r Result) LoginSuccess(session *model.Session) error { res := &LoginResponse{} res.Code = http.StatusOK - res.Message = "用户已成功登录。" + res.Message = "用户已成功登录。"+ "👋!" res.NeedReset = false res.Session = session return r.Ctx.Status(fiber.StatusOK).JSON(res) diff --git a/router/router.go b/router/router.go index fe8c98f..908558d 100644 --- a/router/router.go +++ b/router/router.go @@ -25,24 +25,24 @@ func init() { } func App() *fiber.App { - app := fiber.New(fiber.Config{ - BodyLimit: 30 * 1024 * 1024, - EnablePrintRoutes: true, - EnableTrustedProxyCheck: false, - Prefork: false, - ErrorHandler: errorHandler, - JSONEncoder: json.Marshal, - JSONDecoder: json.Unmarshal, + app := fiber.New(fiber.Config{ //创建fiber实例的时候选择配置选项 + BodyLimit: 30 * 1024 * 1024, //设置请求正文允许的最大大小。 + EnablePrintRoutes: true, //自定义方案,用于启动消息 + EnableTrustedProxyCheck: false, //禁用受信代理 + Prefork: false, //禁止预处理(如果要启用预处理则需要通过shell脚本运行) + ErrorHandler: errorHandler, //相应全局处理错误 + JSONEncoder: json.Marshal, //json编码 + JSONDecoder: json.Unmarshal, //json解码 }) - app.Use(compress.New()) + app.Use(compress.New()) //压缩中间件 app.Use(recover.New(recover.Config{ EnableStackTrace: true, StackTraceHandler: stackTraceHandler, - })) + })) //恢复中间件 app.Use(logger.NewLogMiddleware(logger.LogMiddlewareConfig{ Logger: logger.Named("App"), - })) - app.Use(security.SessionRecovery) + })) //日志中间件 + app.Use(security.SessionRecovery) //会话恢复中间件 controller.InitializeUserHandlers(app) controller.InitializeRegionHandlers(app) @@ -53,6 +53,7 @@ func App() *fiber.App { controller.InitializeInvoiceHandler(app) controller.InitializeTopUpHandlers(app) controller.InitializeReportHandlers(app) + controller.InitializeWithdrawHandlers(app) return app } diff --git a/service/user.go b/service/user.go index a81dc3f..2474921 100644 --- a/service/user.go +++ b/service/user.go @@ -80,7 +80,7 @@ func (us _UserService) ProcessEnterpriseUserLogin(username, password string) (*m us.log.Error("处理企业用户登录失败。", zap.String("username", username), zap.Error(err)) return nil, err } - token, _ := uuid.NewRandom() + token, _ := uuid.NewRandom() //生成uuid作为会话的token使用 userSession := &model.Session{ Uid: user.Id, Name: user.Username, diff --git a/settings.yaml b/settings.yaml index 4a0e548..0c4d01c 100644 --- a/settings.yaml +++ b/settings.yaml @@ -1,8 +1,8 @@ Database: User: electricity Pass: nLgxPO5s8gK2tR0OL0Q - Host: postgres - Port: 5432 + Host: 39.105.39.8 + Port: 9432 DB: electricity MaxIdleConns: 0 MaxOpenConns: 20 From 61edef5c92b5bbb8c433f923c5be6547d417d796 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Thu, 20 Jul 2023 16:13:19 +0800 Subject: [PATCH 02/24] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=AE=8C?= =?UTF-8?q?=E5=96=84withdraw=E7=9A=84=E8=BF=94=E5=9B=9E=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/report.go | 3 +- controller/tenement.go | 2 + controller/withdraw.go | 50 ++--------- model/park.go | 5 ++ model/withdraw.go | 77 +++++++++++++++++ repository/withdraw.go | 184 +++++++++++++++++++++++++++++++++++++++++ router/router.go | 2 + tools/utils.go | 14 ++++ 8 files changed, 294 insertions(+), 43 deletions(-) create mode 100644 model/withdraw.go create mode 100644 repository/withdraw.go diff --git a/controller/report.go b/controller/report.go index a99cabe..b79efe5 100644 --- a/controller/report.go +++ b/controller/report.go @@ -23,7 +23,8 @@ 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) diff --git a/controller/tenement.go b/controller/tenement.go index 04dab4c..0e1c98b 100644 --- a/controller/tenement.go +++ b/controller/tenement.go @@ -25,9 +25,11 @@ func InitializeTenementHandler(router *fiber.App) { router.Put("/tenement/:pid/:tid", security.EnterpriseAuthorize, updateTenement) router.Get("/tenement/:pid/:tid", security.EnterpriseAuthorize, getTenementDetail) router.Get("/tenement/:pid/:tid/meter", security.EnterpriseAuthorize, listMeters) + //TODO: 2023-07-19再apiFox上该请求是个PUT请求,后端接收是个POST请求,不知道是否有误或是缺少对应请求(apiFox测试请求返回值为405) router.Post("/tenement/:pid/:tid/move/out", security.EnterpriseAuthorize, moveOutTenement) router.Post("/tenement/:pid", security.EnterpriseAuthorize, addTenement) router.Post("/tenement/:pid/:tid/binding", security.EnterpriseAuthorize, bindMeterToTenement) + //TODO: 2023-07-19再apiFox上该请求是个PUT请求,后端接收是个POST请求,不知道是否有误或是缺少对应请求(apiFox测试请求返回值为405) router.Post("/tenement/:pid/:tid/binding/:code/unbind", security.EnterpriseAuthorize, unbindMeterFromTenement) } diff --git a/controller/withdraw.go b/controller/withdraw.go index cc490ac..e19d613 100644 --- a/controller/withdraw.go +++ b/controller/withdraw.go @@ -2,9 +2,11 @@ package controller import ( "electricity_bill_calc/logger" + "electricity_bill_calc/repository" "electricity_bill_calc/response" "github.com/gofiber/fiber/v2" "go.uber.org/zap" + "net/http" ) var withdrawLog = logger.Named("Handler", "Withdraw") @@ -24,51 +26,15 @@ func withdraw(c *fiber.Ctx) error { withdrawLog.Info("参数为: ", zap.String("keyword", keyword), zap.Int("page", page)) //中间数据库操作暂且省略。。。。 //首先进行核算报表的分页查询 - - //TODO: 2023-07-18 此处的data需要经过上面数据库查询后进行数据返回,此处只是作于演示 - data := fiber.Map{ - "report": fiber.Map{ - "id": "string", - "parkId": "string", - "periodBegin": "string", - "periodEnd": "string", - "published": true, - "publishedAt": "string", - "withdraw": 0, - "lastWithdrawAppliedAt": "string", - "lastWithdrawAuditAt": "string", - "status": 0, - "message": "string", - }, - "park": fiber.Map{ - "id": "string", - "userId": "string", - "name": "string", - "tenement": "string", - "area": "string", - "capacity": "string", - "category": 0, - "meter04kvType": 0, - "region": "string", - "address": "string", - "contact": "string", - "phone": "string", - }, - "user": fiber.Map{ - "id": "string", - "name": "string", - "contact": "string", - "phone": "string", - "region": "string", - "address": "string", - }, + withdraws, total, err := repository.WithdrawRepository.FindWithdraw(page, &keyword) + if err != nil { + withdrawLog.Error("检索用户核算报表失败。", zap.Error(err)) + return result.Error(http.StatusInternalServerError, err.Error()) } - datas := make([]interface{}, 0) - datas = append(datas, data) //TODO: 2023-07-18 此处返回值是个示例,具体返回值需要查询数据库 return result.Success( "withdraw请求成功", - response.NewPagedResponse(page, 20).ToMap(), - fiber.Map{"records": datas}, + response.NewPagedResponse(page, total).ToMap(), + fiber.Map{"records": withdraws}, ) } diff --git a/model/park.go b/model/park.go index 9dfd190..c00df57 100644 --- a/model/park.go +++ b/model/park.go @@ -31,3 +31,8 @@ type Park struct { LastModifiedAt time.Time `json:"lastModifiedAt"` DeletedAt *time.Time `json:"deletedAt"` } + +type Parks struct { + Park + NormAuthorizedLossRate float64 `json:"norm_authorized_loss_rate"` +} diff --git a/model/withdraw.go b/model/withdraw.go new file mode 100644 index 0000000..6b5b032 --- /dev/null +++ b/model/withdraw.go @@ -0,0 +1,77 @@ +package model + +import ( + "database/sql" + "electricity_bill_calc/types" + "time" +) + +type Withdraw struct { + Park SimplifiedPark `json:"park"` + Report SimplifiedReport `json:"report"` + User UserInfos `json:"user"` // 简易用户详细信息 +} + +// 简易园区信息 +type SimplifiedPark struct { + Address *string `json:"address"` // 园区地址 + Area *string `json:"area"` // 园区面积 + Capacity *string `json:"capacity"` // 供电容量 + Category int16 `json:"category"` // 用电分类,0:两部制,1:单一峰谷,2:单一单一 + Contact *string `json:"contact"` // 园区联系人 + ID string `json:"id"` // 园区ID + Meter04KvType int16 `json:"meter04kvType"` // 户表计量类型,0:非峰谷,1:峰谷 + Name string `json:"name"` // 园区名称 + Phone *string `json:"phone"` // 园区联系人电话 + Region *string `json:"region"` // 园区所在行政区划 + Tenement *string `json:"tenement"` // 园区住户数量 + UserID string `json:"userId"` // 园区所属用户ID +} + +// 简易核算报表信息 +type SimplifiedReport struct { + ID string `json:"id"` // 报表ID + LastWithdrawAppliedAt *string `json:"lastWithdrawAppliedAt"` // 最后一次申请撤回的时间,格式为 yyyy-MM-dd HH:mm:ss + LastWithdrawAuditAt *string `json:"lastWithdrawAuditAt"` // 最后一次申请审核的时间,格式为 yyyy-MM-dd HH:mm:ss + Message *string `json:"message"` // 当前状态的错误提示 + ParkID string `json:"parkId"` // 所属园区ID + PeriodBegin string `json:"periodBegin"` // 核算起始日期,格式为 yyyy-MM-dd + PeriodEnd string `json:"periodEnd"` // 核算结束日期,格式为 yyyy-MM-dd + Published bool `json:"published"` // 是否已发布 + PublishedAt *string `json:"publishedAt"` // 发布时间 + Status float64 `json:"status,omitempty"` // 当前状态,0:计算任务已队列,1:计算任务已完成,2:计算数据不足 + Withdraw int16 `json:"withdraw"` // 报表撤回状态,0:未撤回,1:申请撤回中,2:申请拒绝,3:申请批准 +} + +// 简易用户信息 +type UserInfos struct { + Address *string `json:"address"` // 用户地址 + Contact *string `json:"contact"` // 用户联系人 + ID string `json:"id"` // 用户ID + Name *string `json:"name"` // 用户名称 + Phone *string `json:"phone"` // 用户联系人电话 + Region *string `json:"region"` // 用户所在行政区划 +} + +//用于映射数据库的报表结构体 +type Report struct { + CreatedAt time.Time `db:"created_at"` + LastModifiedAt sql.NullTime `db:"last_modified_at"` + ID string `db:"id"` + ParkID string `db:"park_id"` + Period types.DateRange `db:"period"` + Published bool `db:"published"` + PublishedAt sql.NullTime `db:"published_at"` + Withdraw int16 `db:"withdraw"` + LastWithdrawAppliedAt sql.NullTime `db:"last_withdraw_applied_at"` + LastWithdrawAuditAt sql.NullTime `db:"last_withdraw_audit_at"` + Category int16 `db:"category"` + Meter04KVType int16 `db:"meter_04kv_type"` + PricePolicy int16 `db:"price_policy"` + BasisPooled int16 `db:"basis_pooled"` + AdjustPooled int16 `db:"adjust_pooled"` + LossPooled int16 `db:"loss_pooled"` + PublicPooled int16 `db:"public_pooled"` + AuthorizedLossRate float64 `db:"authorized_loss_rate"` + AuthorizedLossRateIncr float64 `db:"authorized_loss_rate_increment"` +} diff --git a/repository/withdraw.go b/repository/withdraw.go new file mode 100644 index 0000000..f316d7f --- /dev/null +++ b/repository/withdraw.go @@ -0,0 +1,184 @@ +package repository + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/model" + "electricity_bill_calc/tools" + "fmt" + "github.com/doug-martin/goqu/v9" + "github.com/georgysavva/scany/v2/pgxscan" + "go.uber.org/zap" +) + +type _WithdrawRepository struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var WithdrawRepository = &_WithdrawRepository{ + log: logger.Named("Repository", "Withdraw"), + ds: goqu.Dialect("postgres"), +} + +/** + * @author: ZiHangQin + * 该方法用于分页查询核算报表 + * @param:page + * @param: keyword + * @return:[]object + * @return:total + * @return: error + */ +func (wd _WithdrawRepository) FindWithdraw(page int, keyword *string) ([]model.Withdraw, int64, error) { + wd.log.Info("查询用户的充值记录。", zap.Stringp("keyword", keyword), zap.Int("page", page)) + ctx, cancel := global.TimeoutContext() + defer cancel() + fmt.Println(ctx) + //TODO: 2023-07-18此处进行用户的核算报表分页查询的sql语句拼接逻辑。 + //1、SELECT * FROM report WHERE `withdraw` = 1(获取到所有的状态为申请撤回中的报表数据) + // + //2、循环遍历1中获取的数据{ + //查询需要的字段"id": "string", + // "parkId": "string", + // "periodBegin": "string", + // "periodEnd": "string", + // "published": true, + // "publishedAt": "string", + // "withdraw": 0, + // "lastWithdrawAppliedAt": "string", + // "lastWithdrawAuditAt": "string", + // "status": 0, + // "message": "string" + //----report简易核算报表信息获取完成 + // + //3、SELECT * FROM park WHERE `id` = report.park_id(获取园区信息) + //查询结果需要的字段 "id": "string", + // "userId": "string", + // "name": "string", + // "tenement": "string", + // "area": "string", + // "capacity": "string", + // "category": 0, + // "meter04kvType": 0, + // "region": "string", + // "address": "string", + // "contact": "string", + // "phone": "string" + //----park简易园区信息货物完成 + // + //4、SELECT * FROM user_detail WHERE `id` = park.user_id(获取用户信息) + //查询结果需要的字段 "id": "string", + // "name": "string", + // "contact": "string", + // "phone": "string", + // "region": "string", + // "address": "string" + //----user简易用户信息获取完成 + //} + + reportQuery, reportQueryArgs, _ := wd.ds. + From(goqu.T("report")). + Where(goqu.I("withdraw").Eq(1)). + Select("*").ToSQL() + + reports := make([]model.Report, 0) + + err := pgxscan.Select(ctx, global.DB, &reports, reportQuery, reportQueryArgs...) + if err != nil { + fmt.Println(err) + return []model.Withdraw{}, 0, err + } + fmt.Println("数据库中读取的指定数据:", reports) + + var withdrawReses []model.Withdraw + + for _, v := range reports { + lastWithdrawAppliedAtStr := tools.NullTime2PointerString(v.LastWithdrawAppliedAt) + lastWithdrawAuditAtStr := tools.NullTime2PointerString(v.LastWithdrawAuditAt) + publishAtStr := tools.NullTime2PointerString(v.PublishedAt) + + Begin := v.Period.SafeLower().Format("2006-01-02") + End := v.Period.SafeUpper().Format("2006-01-02") + var withdrawRes model.Withdraw + //构建简易报表信息 + simplifiedReport := model.SimplifiedReport{ + ID: v.ID, + LastWithdrawAppliedAt: lastWithdrawAppliedAtStr, + LastWithdrawAuditAt: lastWithdrawAuditAtStr, + Message: nil, + ParkID: v.ParkID, + PeriodBegin: Begin, + PeriodEnd: End, + Published: v.Published, + PublishedAt: publishAtStr, + Status: 0.00, + Withdraw: v.Withdraw, + } + + parkQuery, parkQueryArgs, _ := wd.ds. + From(goqu.T("park")). + Where(goqu.I("id").Eq(v.ParkID)). + Select("*").ToSQL() + + park := make([]model.Parks, 0) + err := pgxscan.Select(ctx, global.DB, &park, parkQuery, parkQueryArgs...) + fmt.Println("读到的园区数据:", park) + if err != nil { + fmt.Println(err) + return []model.Withdraw{}, 0, err + } + + areaStr := tools.NullDecimalToString(park[0].Area) + capacityStr := tools.NullDecimalToString(park[0].Capacity) + TenementQuantityStr := tools.NullDecimalToString(park[0].TenementQuantity) + //构建简易园区数据 + simplifiedPark := model.SimplifiedPark{ + Address: park[0].Address, + Area: areaStr, + Capacity: capacityStr, + Category: park[0].Category, + Contact: park[0].Contact, + ID: park[0].Id, + Meter04KvType: park[0].MeterType, + Name: park[0].Name, + Phone: park[0].Phone, + Region: park[0].Region, + Tenement: TenementQuantityStr, + UserID: park[0].UserId, + } + + userQuery, userQueryArgs, _ := wd.ds. + From(goqu.T("user_detail")). + Where(goqu.I("id").Eq(park[0].UserId)). + Select("*").ToSQL() + + userInfo := make([]model.UserDetail, 0) + + err = pgxscan.Select(ctx, global.DB, &userInfo, userQuery, userQueryArgs...) + fmt.Println("读到的用户数据:", userInfo) + if err != nil { + fmt.Println(err) + return []model.Withdraw{}, 0, err + } + + simplifiedUser := model.UserInfos{ + Address: userInfo[0].Address, + Contact: userInfo[0].Contact, + ID: userInfo[0].Id, + Name: userInfo[0].Name, + Phone: userInfo[0].Phone, + Region: userInfo[0].Region, + } + + withdrawRes.Report = simplifiedReport + withdrawRes.Park = simplifiedPark + withdrawRes.User = simplifiedUser + + withdrawReses = append(withdrawReses, withdrawRes) + } + + total := len(reports) + + return withdrawReses, int64(total), nil +} diff --git a/router/router.go b/router/router.go index 908558d..f1db451 100644 --- a/router/router.go +++ b/router/router.go @@ -53,6 +53,8 @@ func App() *fiber.App { controller.InitializeInvoiceHandler(app) controller.InitializeTopUpHandlers(app) controller.InitializeReportHandlers(app) + + controller.InitializeWithdrawHandlers(app) return app diff --git a/tools/utils.go b/tools/utils.go index 6312dd5..fceb81b 100644 --- a/tools/utils.go +++ b/tools/utils.go @@ -1,6 +1,7 @@ package tools import ( + "database/sql" "encoding/json" "fmt" "strings" @@ -144,3 +145,16 @@ func NullDecimalToString(d decimal.NullDecimal, precision ...int32) *string { } return lo.ToPtr(d.Decimal.StringFixedBank(precision[0])) } + +//将sql.NullTime转换为*string +func NullTime2PointerString(nullTime sql.NullTime) *string { + var strPtr *string + if nullTime.Valid { + str := nullTime.Time.String() + strPtr = &str + return strPtr + } else { + strPtr = nil + return strPtr + } +} From ab44ff5cc4a23bd54f99e579989b3f29f7d1fe09 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Tue, 25 Jul 2023 10:09:53 +0800 Subject: [PATCH 03/24] a --- .idea/codeStyles/Project.xml | 28 ++++++++++++++++++++++++++++ repository/withdraw.go | 1 - 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 .idea/codeStyles/Project.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..3cdc6ae --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/repository/withdraw.go b/repository/withdraw.go index f316d7f..5529731 100644 --- a/repository/withdraw.go +++ b/repository/withdraw.go @@ -89,7 +89,6 @@ func (wd _WithdrawRepository) FindWithdraw(page int, keyword *string) ([]model.W fmt.Println(err) return []model.Withdraw{}, 0, err } - fmt.Println("数据库中读取的指定数据:", reports) var withdrawReses []model.Withdraw From 6fece99e002268c8912a0bc59b1ba26849d2835a Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Tue, 25 Jul 2023 10:45:43 +0800 Subject: [PATCH 04/24] =?UTF-8?q?=E5=B8=A6=E5=88=86=E9=A1=B5=E7=9A=84?= =?UTF-8?q?=E5=BE=85=E5=AE=A1=E6=A0=B8=E7=9A=84=E6=A0=B8=E7=AE=97=E6=92=A4?= =?UTF-8?q?=E5=9B=9E=E7=94=B3=E8=AF=B7=E5=88=97=E8=A1=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/withdraw.go | 2 +- model/withdraw.go | 75 +++++++------ repository/withdraw.go | 243 ++++++++++++++++++++--------------------- tools/utils.go | 13 +++ 4 files changed, 173 insertions(+), 160 deletions(-) diff --git a/controller/withdraw.go b/controller/withdraw.go index e19d613..d6c7510 100644 --- a/controller/withdraw.go +++ b/controller/withdraw.go @@ -26,7 +26,7 @@ func withdraw(c *fiber.Ctx) error { withdrawLog.Info("参数为: ", zap.String("keyword", keyword), zap.Int("page", page)) //中间数据库操作暂且省略。。。。 //首先进行核算报表的分页查询 - withdraws, total, err := repository.WithdrawRepository.FindWithdraw(page, &keyword) + withdraws, total, err := repository.WithdrawRepository.FindWithdraw(uint(page), &keyword) if err != nil { withdrawLog.Error("检索用户核算报表失败。", zap.Error(err)) return result.Error(http.StatusInternalServerError, err.Error()) diff --git a/model/withdraw.go b/model/withdraw.go index 6b5b032..b1da5f1 100644 --- a/model/withdraw.go +++ b/model/withdraw.go @@ -1,8 +1,8 @@ package model import ( - "database/sql" "electricity_bill_calc/types" + "github.com/shopspring/decimal" "time" ) @@ -17,10 +17,10 @@ type SimplifiedPark struct { Address *string `json:"address"` // 园区地址 Area *string `json:"area"` // 园区面积 Capacity *string `json:"capacity"` // 供电容量 - Category int16 `json:"category"` // 用电分类,0:两部制,1:单一峰谷,2:单一单一 + Category int16 `json:"category"` // 用电分类,0:两部制,1:单一峰谷,2:单一单一 Contact *string `json:"contact"` // 园区联系人 ID string `json:"id"` // 园区ID - Meter04KvType int16 `json:"meter04kvType"` // 户表计量类型,0:非峰谷,1:峰谷 + Meter04KvType int16 `json:"meter04kvType"` // 户表计量类型,0:非峰谷,1:峰谷 Name string `json:"name"` // 园区名称 Phone *string `json:"phone"` // 园区联系人电话 Region *string `json:"region"` // 园区所在行政区划 @@ -30,17 +30,17 @@ type SimplifiedPark struct { // 简易核算报表信息 type SimplifiedReport struct { - ID string `json:"id"` // 报表ID - LastWithdrawAppliedAt *string `json:"lastWithdrawAppliedAt"` // 最后一次申请撤回的时间,格式为 yyyy-MM-dd HH:mm:ss - LastWithdrawAuditAt *string `json:"lastWithdrawAuditAt"` // 最后一次申请审核的时间,格式为 yyyy-MM-dd HH:mm:ss - Message *string `json:"message"` // 当前状态的错误提示 - ParkID string `json:"parkId"` // 所属园区ID - PeriodBegin string `json:"periodBegin"` // 核算起始日期,格式为 yyyy-MM-dd - PeriodEnd string `json:"periodEnd"` // 核算结束日期,格式为 yyyy-MM-dd - Published bool `json:"published"` // 是否已发布 - PublishedAt *string `json:"publishedAt"` // 发布时间 + ID string `json:"id"` // 报表ID + LastWithdrawAppliedAt *string `json:"lastWithdrawAppliedAt"` // 最后一次申请撤回的时间,格式为 yyyy-MM-dd HH:mm:ss + LastWithdrawAuditAt *string `json:"lastWithdrawAuditAt"` // 最后一次申请审核的时间,格式为 yyyy-MM-dd HH:mm:ss + Message *string `json:"message"` // 当前状态的错误提示 + ParkID string `json:"parkId"` // 所属园区ID + PeriodBegin string `json:"periodBegin"` // 核算起始日期,格式为 yyyy-MM-dd + PeriodEnd string `json:"periodEnd"` // 核算结束日期,格式为 yyyy-MM-dd + Published bool `json:"published"` // 是否已发布 + PublishedAt *string `json:"publishedAt"` // 发布时间 Status float64 `json:"status,omitempty"` // 当前状态,0:计算任务已队列,1:计算任务已完成,2:计算数据不足 - Withdraw int16 `json:"withdraw"` // 报表撤回状态,0:未撤回,1:申请撤回中,2:申请拒绝,3:申请批准 + Withdraw int16 `json:"withdraw"` // 报表撤回状态,0:未撤回,1:申请撤回中,2:申请拒绝,3:申请批准 } // 简易用户信息 @@ -48,30 +48,37 @@ type UserInfos struct { Address *string `json:"address"` // 用户地址 Contact *string `json:"contact"` // 用户联系人 ID string `json:"id"` // 用户ID - Name *string `json:"name"` // 用户名称 + Name *string `json:"name"` // 用户名称 Phone *string `json:"phone"` // 用户联系人电话 Region *string `json:"region"` // 用户所在行政区划 } //用于映射数据库的报表结构体 -type Report struct { - CreatedAt time.Time `db:"created_at"` - LastModifiedAt sql.NullTime `db:"last_modified_at"` - ID string `db:"id"` - ParkID string `db:"park_id"` - Period types.DateRange `db:"period"` - Published bool `db:"published"` - PublishedAt sql.NullTime `db:"published_at"` - Withdraw int16 `db:"withdraw"` - LastWithdrawAppliedAt sql.NullTime `db:"last_withdraw_applied_at"` - LastWithdrawAuditAt sql.NullTime `db:"last_withdraw_audit_at"` - Category int16 `db:"category"` - Meter04KVType int16 `db:"meter_04kv_type"` - PricePolicy int16 `db:"price_policy"` - BasisPooled int16 `db:"basis_pooled"` - AdjustPooled int16 `db:"adjust_pooled"` - LossPooled int16 `db:"loss_pooled"` - PublicPooled int16 `db:"public_pooled"` - AuthorizedLossRate float64 `db:"authorized_loss_rate"` - AuthorizedLossRateIncr float64 `db:"authorized_loss_rate_increment"` +type ReportRes struct { + ReportId string `db:"report_id"` + LastWithdrawAppliedAt *time.Time `db:"last_withdraw_applied_at"` + LastWithdrawAuditAt *time.Time `db:"last_withdraw_audit_at"` + ParkID string `db:"report_park_id"` + Period types.DateRange `db:"period"` + Published bool `db:"published"` + PublishedAt *time.Time `db: "published_at"` + Withdraw int16 `db:"withdraw"` + ParkAddress *string `db:"park_address"` + Area decimal.NullDecimal `db:"area"` + Capacity decimal.NullDecimal `db:"capacity"` + Category int16 + ParkContact *string `db:"park_contact"` + ParkId string `db:"park_id"` + Meter04KVType int16 `db:"meter_04kv_type"` + ParkName string `db:"park_name"` + ParkPhone *string `db:"park_phone"` + ParkRegion string `db:"park_region"` + TenementQuantity decimal.NullDecimal `db:"tenement_quantity"` + UserID string `db:"user_id"` + Address *string + Contact string `db:"user_detail_contact"` + ID string `db:"ud_id"` + Name *string `db:"user_detail_name"` + Phone string `db:"user_detail_phone"` + Region *string `db:"user_detail_region"` } diff --git a/repository/withdraw.go b/repository/withdraw.go index 5529731..4fe000c 100644 --- a/repository/withdraw.go +++ b/repository/withdraw.go @@ -1,6 +1,7 @@ package repository import ( + "electricity_bill_calc/config" "electricity_bill_calc/global" "electricity_bill_calc/logger" "electricity_bill_calc/model" @@ -30,154 +31,146 @@ var WithdrawRepository = &_WithdrawRepository{ * @return:total * @return: error */ -func (wd _WithdrawRepository) FindWithdraw(page int, keyword *string) ([]model.Withdraw, int64, error) { - wd.log.Info("查询用户的充值记录。", zap.Stringp("keyword", keyword), zap.Int("page", page)) +func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model.Withdraw, int64, error) { + wd.log.Info("查询用户的充值记录。", zap.Stringp("keyword", keyword), zap.Int("page", int(page))) ctx, cancel := global.TimeoutContext() defer cancel() - fmt.Println(ctx) - //TODO: 2023-07-18此处进行用户的核算报表分页查询的sql语句拼接逻辑。 - //1、SELECT * FROM report WHERE `withdraw` = 1(获取到所有的状态为申请撤回中的报表数据) - // - //2、循环遍历1中获取的数据{ - //查询需要的字段"id": "string", - // "parkId": "string", - // "periodBegin": "string", - // "periodEnd": "string", - // "published": true, - // "publishedAt": "string", - // "withdraw": 0, - // "lastWithdrawAppliedAt": "string", - // "lastWithdrawAuditAt": "string", - // "status": 0, - // "message": "string" - //----report简易核算报表信息获取完成 - // - //3、SELECT * FROM park WHERE `id` = report.park_id(获取园区信息) - //查询结果需要的字段 "id": "string", - // "userId": "string", - // "name": "string", - // "tenement": "string", - // "area": "string", - // "capacity": "string", - // "category": 0, - // "meter04kvType": 0, - // "region": "string", - // "address": "string", - // "contact": "string", - // "phone": "string" - //----park简易园区信息货物完成 - // - //4、SELECT * FROM user_detail WHERE `id` = park.user_id(获取用户信息) - //查询结果需要的字段 "id": "string", - // "name": "string", - // "contact": "string", - // "phone": "string", - // "region": "string", - // "address": "string" - //----user简易用户信息获取完成 - //} - reportQuery, reportQueryArgs, _ := wd.ds. - From(goqu.T("report")). + /** + 如果访问数据库次数过多出现时间过长的话可以用这个尝试优化,未测试的sql语句 + + wd.ds.From(goqu.T("report")). Where(goqu.I("withdraw").Eq(1)). - Select("*").ToSQL() + Select( + goqu.I("report.*"), + goqu.I("park.*"), + goqu.I("user_detail.*"), + ). + Join( + goqu.T("park"), goqu.On(goqu.I("report.park_id").Eq(goqu.I("park.id"))), + ). + Join( + goqu.T("user_detail"), goqu.On(goqu.I("park.user_id").Eq(goqu.I("user_detail.id"))), + ).ToSQL() - reports := make([]model.Report, 0) + SELECT report.*, park.*, user_detail.* + FROM report as r + JOIN park as p ON r.park_id = p.id + JOIN user_detail as ud ON p.user_id = ud.id + WHERE withdraw = 1 + AND p.name Like '%keyword%' + AND ud.name Like '%keyword%' + */ + reportQuery := wd.ds. + From(goqu.T("report").As("r")). + Where(goqu.I("withdraw").Eq(1)). + Join(goqu.T("park").As("p"), goqu.On(goqu.I("r.park_id").Eq(goqu.I("p.id")))). + Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("p.user_id").Eq(goqu.I("ud.id")))). + Select( + goqu.I("r.id").As("report_id"), goqu.I("r.last_withdraw_applied_at"), goqu.I("r.last_withdraw_audit_at"), + goqu.I("r.park_id").As("report_park_id"), goqu.I("r.period"), goqu.I("r.published"), goqu.I("r.published_at"), goqu.I("r.withdraw"), + goqu.I("p.address").As("park_address"), goqu.I("p.area"), goqu.I("p.capacity"), goqu.I("p.category"), goqu.I("p.contact").As("park_contact"), + goqu.I("p.id").As("park_id"), goqu.I("p.meter_04kv_type"), goqu.I("p.name").As("park_name"), goqu.I("p.phone").As("park_phone"), goqu.I("p.region").As("park_region"), + goqu.I("p.tenement_quantity"), goqu.I("p.user_id"), goqu.I("ud.address"), goqu.I("ud.contact").As("user_detail_contact"), + goqu.I("ud.id").As("ud_id"), goqu.I("ud.name").As("user_detail_name"), goqu.I("ud.phone").As("user_detail_phone"), goqu.I("ud.region").As("user_detail_region"), + ) - err := pgxscan.Select(ctx, global.DB, &reports, reportQuery, reportQueryArgs...) - if err != nil { - fmt.Println(err) - return []model.Withdraw{}, 0, err + countReportQuery := wd.ds. + From(goqu.T("report").As("r")). + Where(goqu.I("withdraw").Eq(1)). + Join(goqu.T("park").As("p"), goqu.On(goqu.I("r.park_id").Eq(goqu.I("p.id")))). + Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("p.user_id").Eq(goqu.I("ud.id")))). + Select(goqu.COUNT("*")) + + if keyword != nil && len(*keyword) > 0 { + pattern := fmt.Sprintf("%%%s%%", *keyword) + reportQuery = reportQuery.Where(goqu.Or( + goqu.I("p.name").ILike(pattern), + goqu.I("ud.name").ILike(pattern), + )) } + reportQuery = reportQuery.Order(goqu.I("r.created_at").Desc()) + + currentPostion := (page - 1) * config.ServiceSettings.ItemsPageSize + reportQuery = reportQuery.Offset(currentPostion).Limit(config.ServiceSettings.ItemsPageSize) + + reportSql, reportArgs, _ := reportQuery.Prepared(true).ToSQL() + + countReportQuerySql, countReportQueryArgs, _ := countReportQuery.Prepared(true).ToSQL() + + + var ( + reports []*model.ReportRes = make([]*model.ReportRes, 0) + total int64 + ) + var err error + + err = pgxscan.Select(ctx, global.DB, &reports, reportSql, reportArgs...) + if err != nil { + fmt.Println(err) + wd.log.Error("查询报表记录失败。", zap.Error(err)) + return make([]model.Withdraw, 0), 0, err + } + + if err = pgxscan.Get(ctx, global.DB, &total, countReportQuerySql, countReportQueryArgs...); err != nil { + wd.log.Error("查询报表记录总数失败。", zap.Error(err)) + return make([]model.Withdraw, 0), 0, err + } + + if len(reports) <= 0 { + return make([]model.Withdraw, 0), total, nil + } + + fmt.Println(&reports) var withdrawReses []model.Withdraw - + //TODO: 2023.07.24对查询到的数据进行拼接 for _, v := range reports { - lastWithdrawAppliedAtStr := tools.NullTime2PointerString(v.LastWithdrawAppliedAt) - lastWithdrawAuditAtStr := tools.NullTime2PointerString(v.LastWithdrawAuditAt) - publishAtStr := tools.NullTime2PointerString(v.PublishedAt) - Begin := v.Period.SafeLower().Format("2006-01-02") End := v.Period.SafeUpper().Format("2006-01-02") + var withdrawRes model.Withdraw - //构建简易报表信息 - simplifiedReport := model.SimplifiedReport{ - ID: v.ID, - LastWithdrawAppliedAt: lastWithdrawAppliedAtStr, - LastWithdrawAuditAt: lastWithdrawAuditAtStr, + report := model.SimplifiedReport{ + ID: v.ReportId, + LastWithdrawAppliedAt: tools.TimeToStringPtr(v.LastWithdrawAppliedAt), + LastWithdrawAuditAt: tools.TimeToStringPtr(v.LastWithdrawAuditAt), Message: nil, ParkID: v.ParkID, PeriodBegin: Begin, PeriodEnd: End, Published: v.Published, - PublishedAt: publishAtStr, - Status: 0.00, + PublishedAt: nil, + Status: 0., Withdraw: v.Withdraw, } - - parkQuery, parkQueryArgs, _ := wd.ds. - From(goqu.T("park")). - Where(goqu.I("id").Eq(v.ParkID)). - Select("*").ToSQL() - - park := make([]model.Parks, 0) - err := pgxscan.Select(ctx, global.DB, &park, parkQuery, parkQueryArgs...) - fmt.Println("读到的园区数据:", park) - if err != nil { - fmt.Println(err) - return []model.Withdraw{}, 0, err + park := model.SimplifiedPark{ + Address: v.ParkAddress, + Area: tools.NullDecimalToString(v.Area), + Capacity: tools.NullDecimalToString(v.Capacity), + Category: int16(v.Category), + Contact: v.ParkContact, + ID: v.ParkId, + Meter04KvType: v.Meter04KVType, + Name: v.ParkName, + Phone: v.ParkPhone, + Region: &v.ParkRegion, + Tenement: tools.NullDecimalToString(v.TenementQuantity), + UserID: v.UserID, + } + userInfo := model.UserInfos{ + Address: v.Address, + Contact: &v.Contact, + ID: v.ID, + Name: v.Name, + Phone: &v.Phone, + Region: v.Region, } - areaStr := tools.NullDecimalToString(park[0].Area) - capacityStr := tools.NullDecimalToString(park[0].Capacity) - TenementQuantityStr := tools.NullDecimalToString(park[0].TenementQuantity) - //构建简易园区数据 - simplifiedPark := model.SimplifiedPark{ - Address: park[0].Address, - Area: areaStr, - Capacity: capacityStr, - Category: park[0].Category, - Contact: park[0].Contact, - ID: park[0].Id, - Meter04KvType: park[0].MeterType, - Name: park[0].Name, - Phone: park[0].Phone, - Region: park[0].Region, - Tenement: TenementQuantityStr, - UserID: park[0].UserId, - } - - userQuery, userQueryArgs, _ := wd.ds. - From(goqu.T("user_detail")). - Where(goqu.I("id").Eq(park[0].UserId)). - Select("*").ToSQL() - - userInfo := make([]model.UserDetail, 0) - - err = pgxscan.Select(ctx, global.DB, &userInfo, userQuery, userQueryArgs...) - fmt.Println("读到的用户数据:", userInfo) - if err != nil { - fmt.Println(err) - return []model.Withdraw{}, 0, err - } - - simplifiedUser := model.UserInfos{ - Address: userInfo[0].Address, - Contact: userInfo[0].Contact, - ID: userInfo[0].Id, - Name: userInfo[0].Name, - Phone: userInfo[0].Phone, - Region: userInfo[0].Region, - } - - withdrawRes.Report = simplifiedReport - withdrawRes.Park = simplifiedPark - withdrawRes.User = simplifiedUser - + withdrawRes.Report = report + withdrawRes.Park = park + withdrawRes.User = userInfo withdrawReses = append(withdrawReses, withdrawRes) } - total := len(reports) - - return withdrawReses, int64(total), nil + return withdrawReses, total, nil } diff --git a/tools/utils.go b/tools/utils.go index fceb81b..af61a41 100644 --- a/tools/utils.go +++ b/tools/utils.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "strings" + "time" "github.com/mozillazg/go-pinyin" "github.com/samber/lo" @@ -158,3 +159,15 @@ func NullTime2PointerString(nullTime sql.NullTime) *string { return strPtr } } + + +//该方法用于将时间解析为字符串指针 +func TimeToStringPtr(t *time.Time) *string { + if t == nil { + return nil + } + + timeStr := t.Format("2006-01-02 15:04:05") + return &timeStr +} + From d8a29e7d17d3e54e7e2e7600318cab2449bab518 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Tue, 25 Jul 2023 15:31:35 +0800 Subject: [PATCH 05/24] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=A3=80=E7=B4=A2=E6=A0=B8=E7=AE=97=E6=8A=A5=E8=A1=A8=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E7=BB=86=E8=8A=82=EF=BC=8C=E5=AE=8C=E6=88=90=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8=E6=92=A4=E5=9B=9E=E6=8A=A5=E8=A1=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/withdraw.go | 56 +++++++++++++++++++++++--- repository/withdraw.go | 91 ++++++++++++++++++++++++++++++++++++------ vo/withdraw.go | 6 +++ 3 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 vo/withdraw.go diff --git a/controller/withdraw.go b/controller/withdraw.go index d6c7510..ed14265 100644 --- a/controller/withdraw.go +++ b/controller/withdraw.go @@ -4,6 +4,8 @@ import ( "electricity_bill_calc/logger" "electricity_bill_calc/repository" "electricity_bill_calc/response" + "electricity_bill_calc/security" + "electricity_bill_calc/vo" "github.com/gofiber/fiber/v2" "go.uber.org/zap" "net/http" @@ -12,10 +14,11 @@ import ( var withdrawLog = logger.Named("Handler", "Withdraw") func InitializeWithdrawHandlers(router *fiber.App) { - router.Get("/withdraw", withdraw) + router.Get("/withdraw", security.OPSAuthorize, withdraw) + router.Put("/withdraw/:rid", ReviewRequestWithdraw) } -//用于检索用户的核算报表 +//用于分页检索用户的核算报表 func withdraw(c *fiber.Ctx) error { //记录日志 withdrawLog.Info("带分页的待审核的核算撤回申请列表") @@ -27,14 +30,55 @@ func withdraw(c *fiber.Ctx) error { //中间数据库操作暂且省略。。。。 //首先进行核算报表的分页查询 withdraws, total, err := repository.WithdrawRepository.FindWithdraw(uint(page), &keyword) - if err != nil { - withdrawLog.Error("检索用户核算报表失败。", zap.Error(err)) - return result.Error(http.StatusInternalServerError, err.Error()) + if err != nil { + withdrawLog.Error("检索用户核算报表失败。", zap.Error(err)) + return result.Error(http.StatusInternalServerError, err.Error()) } - //TODO: 2023-07-18 此处返回值是个示例,具体返回值需要查询数据库 + //TODO: 2023-07-18 此处返回值是个示例,具体返回值需要查询数据库(完成) return result.Success( "withdraw请求成功", response.NewPagedResponse(page, total).ToMap(), fiber.Map{"records": withdraws}, ) } + +//用于审核撤回报表 +func ReviewRequestWithdraw(c *fiber.Ctx) error { + Rid := c.Params("rid", "") + Data := new(vo.ReviewWithdraw) + result := response.NewResult(c) + + if err := c.BodyParser(&Data); err != nil { + withdrawLog.Error("无法解析审核指定报表的请求数据", zap.Error(err)) + return result.BadRequest("无法解析审核指定报表的请求数据。") + } + + if Data.Audit == true { //审核通过 + ok, err := repository.WithdrawRepository.ReviewTrueReportWithdraw(Rid) + if err != nil { + withdrawLog.Error("审核同意撤回报表失败") + return result.Error(http.StatusInternalServerError, err.Error()) + } + + if !ok { + withdrawLog.Error("审核同意撤回报表失败") + return result.NotAccept("审核同意撤回报表失败") + } else { + return result.Success("审核同意撤回报表成功!") + } + } else { //审核不通过 + ok, err := repository.WithdrawRepository.ReviewFalseReportWithdraw(Rid) + if err != nil { + withdrawLog.Error("审核拒绝撤回报表失败") + return result.Error(http.StatusInternalServerError, err.Error()) + } + + if !ok { + withdrawLog.Error("审核拒绝撤回报表失败") + return result.NotAccept("审核拒绝撤回报表失败") + } else { + return result.Success("审核拒绝撤回报表成功!") + } + } + +} diff --git a/repository/withdraw.go b/repository/withdraw.go index 4fe000c..540c5a3 100644 --- a/repository/withdraw.go +++ b/repository/withdraw.go @@ -6,6 +6,7 @@ import ( "electricity_bill_calc/logger" "electricity_bill_calc/model" "electricity_bill_calc/tools" + "electricity_bill_calc/types" "fmt" "github.com/doug-martin/goqu/v9" "github.com/georgysavva/scany/v2/pgxscan" @@ -22,17 +23,9 @@ var WithdrawRepository = &_WithdrawRepository{ ds: goqu.Dialect("postgres"), } -/** - * @author: ZiHangQin - * 该方法用于分页查询核算报表 - * @param:page - * @param: keyword - * @return:[]object - * @return:total - * @return: error - */ +//该方法用于分页查询核算报表 func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model.Withdraw, int64, error) { - wd.log.Info("查询用户的充值记录。", zap.Stringp("keyword", keyword), zap.Int("page", int(page))) + wd.log.Info("查询核算报表", zap.Stringp("keyword", keyword), zap.Int("page", int(page))) ctx, cancel := global.TimeoutContext() defer cancel() @@ -66,6 +59,8 @@ func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model. Where(goqu.I("withdraw").Eq(1)). Join(goqu.T("park").As("p"), goqu.On(goqu.I("r.park_id").Eq(goqu.I("p.id")))). Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("p.user_id").Eq(goqu.I("ud.id")))). + Where(goqu.I("p.deleted_at").IsNull()). + Where(goqu.I("ud.deleted_at").IsNull()). Select( goqu.I("r.id").As("report_id"), goqu.I("r.last_withdraw_applied_at"), goqu.I("r.last_withdraw_audit_at"), goqu.I("r.park_id").As("report_park_id"), goqu.I("r.period"), goqu.I("r.published"), goqu.I("r.published_at"), goqu.I("r.withdraw"), @@ -99,7 +94,6 @@ func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model. countReportQuerySql, countReportQueryArgs, _ := countReportQuery.Prepared(true).ToSQL() - var ( reports []*model.ReportRes = make([]*model.ReportRes, 0) total int64 @@ -122,9 +116,8 @@ func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model. return make([]model.Withdraw, 0), total, nil } - fmt.Println(&reports) var withdrawReses []model.Withdraw - //TODO: 2023.07.24对查询到的数据进行拼接 + //TODO: 2023.07.24对查询到的数据进行拼接(完成) for _, v := range reports { Begin := v.Period.SafeLower().Format("2006-01-02") End := v.Period.SafeUpper().Format("2006-01-02") @@ -174,3 +167,75 @@ func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model. return withdrawReses, total, nil } + +//该方法用于审核同意报表撤回 +func (wd _WithdrawRepository) ReviewTrueReportWithdraw( rid string) (bool, error) { + wd.log.Info("审核指定的报表", zap.String("rid", rid)) + ctx, cancel := global.TimeoutContext() + defer cancel() + //update report set withdraw=$2, + //last_withdraw_audit_at=$3, published=false, + //published_at=null where id=$1 + + tx, err := global.DB.Begin(ctx) + if err != nil { + wd.log.Error("开启数据库事务失败", zap.Error(err)) + } + updateQuerySql, updateArgs, _ := wd.ds. + Update(goqu.T("report")). + Set(goqu.Record{ + "withdraw": 3, + "last_withdraw_audit_at": types.Now(), + "published": false, + "published_at": nil, + }). + Where(goqu.I("id").Eq(rid)). + Prepared(true).ToSQL() + + rs, err := tx.Exec(ctx, updateQuerySql, updateArgs...) + if err != nil { + wd.log.Error("审核报表失败", zap.Error(err)) + return false, err + } + err = tx.Commit(ctx) + if err != nil { + wd.log.Error("提交数据库事务失败", zap.Error(err)) + return false, err + } + + return rs.RowsAffected() > 0, nil +} + +func (wd _WithdrawRepository) ReviewFalseReportWithdraw( rid string) (bool, error) { + wd.log.Info("审核指定的报表", zap.String("rid", rid)) + ctx, cancel := global.TimeoutContext() + defer cancel() + + tx, err := global.DB.Begin(ctx) + if err != nil { + wd.log.Error("开启数据库事务失败", zap.Error(err)) + } + updateQuerySql, updateArgs, _ := wd.ds. + Update(goqu.T("report")). + Set(goqu.Record{ + "withdraw": 2, + "last_withdraw_audit_at": types.Now(), + "published": false, + "published_at": nil, + }). + Where(goqu.I("id").Eq(rid)). + Prepared(true).ToSQL() + + rs, err := tx.Exec(ctx, updateQuerySql, updateArgs...) + if err != nil { + wd.log.Error("审核报表失败", zap.Error(err)) + return false, err + } + err = tx.Commit(ctx) + if err != nil { + wd.log.Error("提交数据库事务失败", zap.Error(err)) + return false, err + } + + return rs.RowsAffected() > 0, nil +} \ No newline at end of file diff --git a/vo/withdraw.go b/vo/withdraw.go new file mode 100644 index 0000000..1aa6019 --- /dev/null +++ b/vo/withdraw.go @@ -0,0 +1,6 @@ +package vo + +//用于接收审核报表的参数 +type ReviewWithdraw struct { + Audit bool `json:"audit"` +} From b3032638fcddff72d95b8475a64af1186dc4dfa7 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Tue, 25 Jul 2023 15:34:30 +0800 Subject: [PATCH 06/24] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E6=92=A4=E5=9B=9E=E6=8A=A5=E8=A1=A8=E7=94=A8=E6=88=B7=E9=89=B4?= =?UTF-8?q?=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/withdraw.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/withdraw.go b/controller/withdraw.go index ed14265..868bc72 100644 --- a/controller/withdraw.go +++ b/controller/withdraw.go @@ -15,7 +15,7 @@ var withdrawLog = logger.Named("Handler", "Withdraw") func InitializeWithdrawHandlers(router *fiber.App) { router.Get("/withdraw", security.OPSAuthorize, withdraw) - router.Put("/withdraw/:rid", ReviewRequestWithdraw) + router.Put("/withdraw/:rid",security.OPSAuthorize, ReviewRequestWithdraw) } //用于分页检索用户的核算报表 From 251c44049a3c52225e941397ba057a0fdebc804b Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Wed, 26 Jul 2023 08:52:24 +0800 Subject: [PATCH 07/24] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E6=92=A4=E5=9B=9E=E6=8A=A5=E8=A1=A8=E8=AF=B7=E6=B1=82=E7=BB=86?= =?UTF-8?q?=E8=8A=82=EF=BC=8C=E5=AE=8C=E6=88=90=E6=92=A4=E5=9B=9E=E7=94=B5?= =?UTF-8?q?=E8=B4=B9=E6=A0=B8=E7=AE=97=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/withdraw.go | 54 ++++++++++++++++++++++++++++++++++++++++-- repository/report.go | 2 +- repository/withdraw.go | 5 ++-- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/controller/withdraw.go b/controller/withdraw.go index 868bc72..f9d6695 100644 --- a/controller/withdraw.go +++ b/controller/withdraw.go @@ -15,7 +15,8 @@ var withdrawLog = logger.Named("Handler", "Withdraw") func InitializeWithdrawHandlers(router *fiber.App) { router.Get("/withdraw", security.OPSAuthorize, withdraw) - router.Put("/withdraw/:rid",security.OPSAuthorize, ReviewRequestWithdraw) + router.Put("/withdraw/:rid", security.OPSAuthorize, reviewRequestWithdraw) + router.Delete("/withdraw/:rid", security.EnterpriseAuthorize, recallReport) } //用于分页检索用户的核算报表 @@ -43,7 +44,7 @@ func withdraw(c *fiber.Ctx) error { } //用于审核撤回报表 -func ReviewRequestWithdraw(c *fiber.Ctx) error { +func reviewRequestWithdraw(c *fiber.Ctx) error { Rid := c.Params("rid", "") Data := new(vo.ReviewWithdraw) result := response.NewResult(c) @@ -82,3 +83,52 @@ func ReviewRequestWithdraw(c *fiber.Ctx) error { } } + +//用于撤回电费核算 +func recallReport(c *fiber.Ctx) error { + // 获取用户会话信息和参数 + rid := c.Params("rid", "") + result := response.NewResult(c) + session, err := _retreiveSession(c) + if err != nil { + withdrawLog.Error("无法获取当前用户的会话。") + return result.Unauthorized(err.Error()) + } + // 检查指定报表的所属情况 + isBelongsTo, err := repository.ReportRepository.IsBelongsTo(rid, session.Uid) + if err != nil { + withdrawLog.Error("检查报表所属情况出现错误。", zap.Error(err)) + return result.Error(http.StatusInternalServerError, err.Error()) + } + + if err == nil && isBelongsTo == true { + // 判断指定报表是否是当前园区的最后一张报表 + isLastReport, err := repository.ReportRepository.IsLastReport(rid) + if err != nil { + withdrawLog.Error("判断指定报表是否为当前园区的最后一张报表时出错", zap.Error(err)) + return result.Error(http.StatusInternalServerError, err.Error()) + } + + if err == nil && isLastReport == true { + // 申请撤回指定的核算报表 + //TODO: 2023.07.25 申请撤回指定核算报表,正确状态未处理(完成) + ok, err := repository.ReportRepository.ApplyWithdrawReport(rid) + if err != nil { + withdrawLog.Error("申请撤回指定核算报表出错", zap.Error(err)) + return result.Error(http.StatusInternalServerError, err.Error()) + } + if ok { + withdrawLog.Info("申请撤回指定核算报表成功") + return result.Success("申请撤回指定核算报表成功") + } + } else { + withdrawLog.Info("当前报表不是当前园区的最后一张报表") + return result.Error(http.StatusForbidden, "当前报表不是当前园区的最后一张报表") + } + } else { + withdrawLog.Info("指定的核算报表不属于当前用户。") + return result.Error(http.StatusForbidden, "指定的核算报表不属于当前用户") + } + + return result.Error(http.StatusInternalServerError, "其他错误") +} diff --git a/repository/report.go b/repository/report.go index a881c97..b8a4478 100644 --- a/repository/report.go +++ b/repository/report.go @@ -678,7 +678,7 @@ func (rr _ReportRepository) IsLastReport(rid string) (bool, error) { defer cancel() checkSql, checkArgs, _ := rr.ds. - From(goqu.T("report")). + From(goqu.T("report").As("r")). Select(goqu.COUNT("*")). Where( goqu.I("r.id").Eq(rid), diff --git a/repository/withdraw.go b/repository/withdraw.go index 540c5a3..a83b43a 100644 --- a/repository/withdraw.go +++ b/repository/withdraw.go @@ -184,7 +184,7 @@ func (wd _WithdrawRepository) ReviewTrueReportWithdraw( rid string) (bool, error updateQuerySql, updateArgs, _ := wd.ds. Update(goqu.T("report")). Set(goqu.Record{ - "withdraw": 3, + "withdraw": model.REPORT_WITHDRAW_GRANTED, "last_withdraw_audit_at": types.Now(), "published": false, "published_at": nil, @@ -206,6 +206,7 @@ func (wd _WithdrawRepository) ReviewTrueReportWithdraw( rid string) (bool, error return rs.RowsAffected() > 0, nil } +//该方法用于审核拒绝报表撤回 func (wd _WithdrawRepository) ReviewFalseReportWithdraw( rid string) (bool, error) { wd.log.Info("审核指定的报表", zap.String("rid", rid)) ctx, cancel := global.TimeoutContext() @@ -218,7 +219,7 @@ func (wd _WithdrawRepository) ReviewFalseReportWithdraw( rid string) (bool, erro updateQuerySql, updateArgs, _ := wd.ds. Update(goqu.T("report")). Set(goqu.Record{ - "withdraw": 2, + "withdraw": model.REPORT_WITHDRAW_DENIED, "last_withdraw_audit_at": types.Now(), "published": false, "published_at": nil, From 39e404451edc2491516f04e4b9385c30c30617f0 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Wed, 26 Jul 2023 10:03:01 +0800 Subject: [PATCH 08/24] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E5=9F=BA=E5=87=86=E7=BA=BF=E6=8D=9F=E7=8E=87?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/settings.go | 11 +++++++++++ controller/foundation.go | 24 ++++++++++++++++++++++++ router/router.go | 1 + settings.yaml | 2 ++ 4 files changed, 38 insertions(+) create mode 100644 controller/foundation.go diff --git a/config/settings.go b/config/settings.go index b8403ec..b009064 100644 --- a/config/settings.go +++ b/config/settings.go @@ -36,12 +36,18 @@ type ServiceSetting struct { HostSerial int64 } +//读取基准线损率 +type BaseLossSetting struct { + Base string +} + // 定义全局变量 var ( ServerSettings *ServerSetting DatabaseSettings *DatabaseSetting RedisSettings *RedisSetting ServiceSettings *ServiceSetting + BaseLoss *BaseLossSetting ) // 读取配置到全局变量 @@ -69,5 +75,10 @@ func SetupSetting() error { if err != nil { return err } + + err = s.ReadSection("BaselineLineLossRatio", &BaseLoss) + if err != nil { + return err + } return nil } diff --git a/controller/foundation.go b/controller/foundation.go new file mode 100644 index 0000000..65cab6b --- /dev/null +++ b/controller/foundation.go @@ -0,0 +1,24 @@ +package controller + +import ( + "electricity_bill_calc/config" + "electricity_bill_calc/logger" + "electricity_bill_calc/response" + "electricity_bill_calc/security" + "github.com/gofiber/fiber/v2" +) + +var foundLog = logger.Named("Handler", "Foundation") + +func InitializeFoundationHandlers(router *fiber.App) { + router.Get("/norm/authorized/loss/rate", security.MustAuthenticated, getNormAuthorizedLossRate) +} + +func getNormAuthorizedLossRate(c *fiber.Ctx) error { + foundLog.Info("获取系统中定义的基准核定线损率") + result := response.NewResult(c) + BaseLoss := config.BaseLoss + return result.Success("已经获取到系统设置的基准核定线损率。", + fiber.Map{"normAuthorizedLossRate": BaseLoss}, + ) +} diff --git a/router/router.go b/router/router.go index f1db451..38af715 100644 --- a/router/router.go +++ b/router/router.go @@ -56,6 +56,7 @@ func App() *fiber.App { controller.InitializeWithdrawHandlers(app) + controller.InitializeFoundationHandlers(app) return app } diff --git a/settings.yaml b/settings.yaml index 0c4d01c..9968ebe 100644 --- a/settings.yaml +++ b/settings.yaml @@ -21,3 +21,5 @@ Service: ItemsPageSize: 20 CacheLifeTime: 5m HostSerial: 5 +BaselineLineLossRatio: + Base: 基准线损率 \ No newline at end of file From 9ad3415cdb3e8c559cf335894707767eb8c404eb Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Wed, 26 Jul 2023 13:43:30 +0800 Subject: [PATCH 09/24] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E7=B3=BB=E7=BB=9F=E4=B8=AD=E5=BE=85=E5=AE=A1?= =?UTF-8?q?=E6=A0=B8=E7=9A=84=E5=86=85=E5=AE=B9=E6=95=B0=E9=87=8F=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/statistics.go | 34 ++++++++++++++++++++++++++++++++++ router/router.go | 14 +++++++------- service/withdraw.go | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 controller/statistics.go create mode 100644 service/withdraw.go diff --git a/controller/statistics.go b/controller/statistics.go new file mode 100644 index 0000000..fb9ab37 --- /dev/null +++ b/controller/statistics.go @@ -0,0 +1,34 @@ +package controller + +import ( + "electricity_bill_calc/logger" + "electricity_bill_calc/response" + "electricity_bill_calc/security" + "electricity_bill_calc/service" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "net/http" +) + +var StatisticsWithdrawLog = logger.Named("Handler", "StatisticsWithdraw") + +func InitializeStatisticsController(router *fiber.App) { + router.Get("/audits", security.OPSAuthorize, currentAuditAmount) + +} + +//获取当前系统中待审核的内容数量 +func currentAuditAmount(c *fiber.Ctx) error { + StatisticsWithdrawLog.Info("开始获取当前系统中待审核的内容数量") + result := response.NewResult(c) + amount, err := service.WithdrawService.AuditWaits() + if err != nil { + StatisticsWithdrawLog.Error("获取当前系统中待审核的内容数量出错", zap.Error(err)) + return result.Error(http.StatusInternalServerError, err.Error()) + } + + return result.Success("已经获取到指定的统计信息", + fiber.Map{"withdraw": amount}) +} + + diff --git a/router/router.go b/router/router.go index 38af715..df7c003 100644 --- a/router/router.go +++ b/router/router.go @@ -34,15 +34,15 @@ func App() *fiber.App { JSONEncoder: json.Marshal, //json编码 JSONDecoder: json.Unmarshal, //json解码 }) - app.Use(compress.New()) //压缩中间件 + app.Use(compress.New()) //压缩中间件 app.Use(recover.New(recover.Config{ EnableStackTrace: true, StackTraceHandler: stackTraceHandler, - })) //恢复中间件 + })) //恢复中间件 app.Use(logger.NewLogMiddleware(logger.LogMiddlewareConfig{ Logger: logger.Named("App"), - })) //日志中间件 - app.Use(security.SessionRecovery) //会话恢复中间件 + })) //日志中间件 + app.Use(security.SessionRecovery) //会话恢复中间件 controller.InitializeUserHandlers(app) controller.InitializeRegionHandlers(app) @@ -54,9 +54,9 @@ func App() *fiber.App { controller.InitializeTopUpHandlers(app) controller.InitializeReportHandlers(app) - - controller.InitializeWithdrawHandlers(app) - controller.InitializeFoundationHandlers(app) + controller.InitializeWithdrawHandlers(app) // 公示撤回 + controller.InitializeFoundationHandlers(app) // 基础数据 + controller.InitializeStatisticsController(app) // 首页信息 return app } diff --git a/service/withdraw.go b/service/withdraw.go new file mode 100644 index 0000000..caa3f09 --- /dev/null +++ b/service/withdraw.go @@ -0,0 +1,39 @@ +package service + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/model" + "github.com/doug-martin/goqu/v9" + "github.com/georgysavva/scany/v2/pgxscan" + "go.uber.org/zap" +) + +type _WithdrawService struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var WithdrawService = _WithdrawService{ + logger.Named("Service", "Withdraw"), + goqu.Dialect("postgres"), +} + +func (wd _WithdrawService) AuditWaits() (int64, error) { + wd.log.Info("获取当前系统中待审核的内容数量。") + ctx, cancel := global.TimeoutContext() + defer cancel() + + CountWithdrawQuery, CountWithdrawQueryArgs, _ := wd.ds. + From(goqu.T("report")). + Where(goqu.I("withdraw").Eq(model.REPORT_WITHDRAW_APPLYING)). + Select(goqu.COUNT("*")).ToSQL() + + var total int64 + err := pgxscan.Get(ctx, global.DB, &total, CountWithdrawQuery,CountWithdrawQueryArgs...) + if err != nil { + wd.log.Error("获取当前系统中待审核的内容数量出错。") + return 0,err + } + return total,nil +} From 5866882c2d1f4488fa1c88c0a6844e6719275ec1 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Wed, 26 Jul 2023 15:11:16 +0800 Subject: [PATCH 10/24] =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E4=B8=AD=E7=9A=84=E6=8A=A5=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/statistics.go | 51 +++++++++++++++++++++++++++ model/park.go | 9 ++++- service/statistics.go | 74 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 service/statistics.go diff --git a/controller/statistics.go b/controller/statistics.go index fb9ab37..2d2c07e 100644 --- a/controller/statistics.go +++ b/controller/statistics.go @@ -2,6 +2,7 @@ package controller import ( "electricity_bill_calc/logger" + "electricity_bill_calc/model" "electricity_bill_calc/response" "electricity_bill_calc/security" "electricity_bill_calc/service" @@ -14,6 +15,7 @@ var StatisticsWithdrawLog = logger.Named("Handler", "StatisticsWithdraw") func InitializeStatisticsController(router *fiber.App) { router.Get("/audits", security.OPSAuthorize, currentAuditAmount) + router.Get("/stat/reports", statReports) } @@ -31,4 +33,53 @@ func currentAuditAmount(c *fiber.Ctx) error { fiber.Map{"withdraw": amount}) } +func statReports(c *fiber.Ctx) error { + result := response.NewResult(c) + session, err := _retreiveSession(c) + if err != nil { + return result.Unauthorized(err.Error()) + } + var ( + enterprises int64 = 0 + parks int64 = 0 + reports []model.ParkPeriodStatistics + ) + if session.Type != 0 { + enterprises, err = service.StatisticsService.EnabledEnterprises() + if err != nil { + StatisticsWithdrawLog.Error(err.Error()) + return result.Error(http.StatusInternalServerError, err.Error()) + } + parks, err = service.StatisticsService.EnabledParks() + if err != nil { + StatisticsWithdrawLog.Error(err.Error()) + return result.Error(http.StatusInternalServerError, err.Error()) + } + //TODO: 2023.07.26 报表数据库结构改变,此处逻辑复杂放在最后处理 + reports, err = service.StatisticsService.ParkNewestState() + if err != nil { + StatisticsWithdrawLog.Error(err.Error()) + return result.Error(http.StatusInternalServerError, err.Error()) + } + } else { + parks, err = service.StatisticsService.EnabledParks(session.Uid) + if err != nil { + StatisticsWithdrawLog.Error(err.Error()) + return result.Error(http.StatusInternalServerError, err.Error()) + } + //TODO: 2023.07.26 报表数据库结构改变,此处逻辑复杂放在最后处理 + reports, err = service.StatisticsService.ParkNewestState(session.Uid) + if err != nil { + StatisticsWithdrawLog.Error(err.Error()) + return result.Error(http.StatusInternalServerError, err.Error()) + } + } + return result.Success("已经完成园区报告的统计。", fiber.Map{ + "statistics": fiber.Map{ + "enterprises": enterprises, + "parks": parks, + "reports": reports, + }, + }) +} diff --git a/model/park.go b/model/park.go index c00df57..b4e3435 100644 --- a/model/park.go +++ b/model/park.go @@ -1,6 +1,7 @@ package model import ( + "electricity_bill_calc/types" "time" "github.com/shopspring/decimal" @@ -35,4 +36,10 @@ type Park struct { type Parks struct { Park NormAuthorizedLossRate float64 `json:"norm_authorized_loss_rate"` -} +} + +type ParkPeriodStatistics struct { + Id string `json:"id"` + Name string `json:"name"` + Period *types.DateRange +} diff --git a/service/statistics.go b/service/statistics.go new file mode 100644 index 0000000..7284984 --- /dev/null +++ b/service/statistics.go @@ -0,0 +1,74 @@ +package service + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/model" + "github.com/doug-martin/goqu/v9" + "github.com/georgysavva/scany/v2/pgxscan" + "go.uber.org/zap" +) + +type _StatisticsService struct { + l *zap.Logger + ss goqu.DialectWrapper +} + +var StatisticsService = _StatisticsService{ + logger.Named("Service", "Stat"), + goqu.Dialect("postgres"), +} + +//用于统计企业用户数量 +func (ss _StatisticsService) EnabledEnterprises() (int64, error) { + ss.l.Info("开始统计企业数量。") + ctx, cancel := global.TimeoutContext() + defer cancel() + + UserCountQuery, UserCountQueryArgs, _ := ss.ss. + From(goqu.T("user")). + Where(goqu.I("type").Eq(model.USER_TYPE_ENT)). + Where(goqu.I("enabled").Eq(true)). + Select(goqu.COUNT("*")).ToSQL() + + var c int64 + err := pgxscan.Get(ctx, global.DB, &c, UserCountQuery, UserCountQueryArgs...) + if err != nil { + ss.l.Error("统计企业数量出错", zap.Error(err)) + return 0, err + } + return c, nil +} + +//用于统计园区数量 +func (ss _StatisticsService) EnabledParks(userIds ...string) (int64, error) { + ss.l.Info("开始统计园区数量", zap.Strings("userId", userIds)) + ctx, cancel := global.TimeoutContext() + defer cancel() + + ParkCountQuery := ss.ss. + From(goqu.T("park")). + Where(goqu.I("enabled").Eq(true)) + + if len(userIds) > 0 { + ParkCountQuery = ParkCountQuery.Where(goqu.I("user_id").In(userIds)) + } + + ParkCountQuerySql, ParkCountQueryArgs, _ := ParkCountQuery.Select(goqu.COUNT("*")).ToSQL() + + var c int64 + err := pgxscan.Get(ctx, global.DB, &c, ParkCountQuerySql, ParkCountQueryArgs...) + if err != nil { + ss.l.Error("园区数量统计错误", zap.Error(err)) + return 0, err + } + + return c, nil +} + +//用户统计报表 +func (ss _StatisticsService) ParkNewestState(userIds ...string) ([]model.ParkPeriodStatistics, error) { + //TODO: 2023.07.26 报表数据库结构改变,此处逻辑复杂放在最后处理 + //return nil,errors.New("还未处理逻辑") + return []model.ParkPeriodStatistics{}, nil +} From 1099a7c335a57248356c3d5621a4df910d7cf8e3 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Thu, 27 Jul 2023 14:01:45 +0800 Subject: [PATCH 11/24] =?UTF-8?q?[=E5=A4=A9=E7=A5=9E=E6=A8=A1=E5=BC=8F]?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8C=87=E5=AE=9A=E5=95=86=E6=88=B7=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 40 ++++++++++++++++++++++++ repository/god_mode.go | 70 ++++++++++++++++++++++++++++++++++++++++++ router/router.go | 1 + service/god_mode.go | 46 +++++++++++++++++++++++++++ 4 files changed, 157 insertions(+) create mode 100644 controller/god_mode.go create mode 100644 repository/god_mode.go create mode 100644 service/god_mode.go diff --git a/controller/god_mode.go b/controller/god_mode.go new file mode 100644 index 0000000..134dc14 --- /dev/null +++ b/controller/god_mode.go @@ -0,0 +1,40 @@ +package controller + +import ( + "electricity_bill_calc/logger" + "electricity_bill_calc/response" + "electricity_bill_calc/service" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +var GmLog = logger.Named("Handler", "GM") + +func InitializeGmController(router *fiber.App) { + router.Delete("/gm/tenement", DeleteTenement) +} + +//用于将参数转化为切片 +func getQueryValues(c *fiber.Ctx, paramName string) []string { + values := c.Request().URI().QueryArgs().PeekMulti(paramName) + result := make([]string, len(values)) + for i, v := range values { + result[i] = string(v) + } + return result +} + +func DeleteTenement(c *fiber.Ctx) error { + park := c.Query("park", "") + tenements := getQueryValues(c, "tenements") + result := response.NewResult(c) + GmLog.Info("[天神模式]删除指定园区中的商户", zap.String("park", park), zap.Strings("tenements", tenements)) + + err := service.GMService.DeleteTenements(park, tenements) + if err != nil { + GmLog.Error("[天神模式]删除指定园区中的商户失败", zap.Error(err)) + return result.Error(500, err.Error()) + } + + return result.Success("指定商户已经删除。") +} diff --git a/repository/god_mode.go b/repository/god_mode.go new file mode 100644 index 0000000..38f5040 --- /dev/null +++ b/repository/god_mode.go @@ -0,0 +1,70 @@ +package repository + +import ( + "context" + "electricity_bill_calc/logger" + "fmt" + "github.com/doug-martin/goqu/v9" + "github.com/jackc/pgx/v5" + "go.uber.org/zap" +) + +type _GMRepository struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var GMRepository = &_GMRepository{ + log: logger.Named("Repository", "GM"), + ds: goqu.Dialect("postgres"), +} + +func (gm _GMRepository) DeleteMeterBinding(ctx context.Context, tx pgx.Tx, pid string, tenements []string, meterCodes ...[]string) error { + DeleteQuery := gm.ds.From(goqu.T("tenement_meter")). + Where(goqu.I("park_id").Eq(pid)). + Delete() + + if len(tenements) > 0 { + DeleteQuery = DeleteQuery. + Where(goqu.I("tenement_id").In(tenements)) + } + + if len(meterCodes) > 0 { + DeleteQuery = DeleteQuery. + Where(goqu.I("meter_id").In(meterCodes)) + } + + DeleteQuerySql, DeleteQueryArgs, _ := DeleteQuery.ToSQL() + + + _, err := tx.Exec(ctx, DeleteQuerySql, DeleteQueryArgs...) + if err != nil { + gm.log.Error("数据库在删除tenement_meter表数据中出错", zap.Error(err)) + tx.Rollback(ctx) + return err + } + return nil +} + +func (gm _GMRepository) DeleteTenements(ctx context.Context, tx pgx.Tx, pid string, tenements []string) error { + DeleteTenements := gm.ds. + From("tenement"). + Where(goqu.I("park_id").Eq(pid)). + Delete() + + fmt.Println(len(tenements)) + if len(tenements) > 0 { + DeleteTenements = DeleteTenements. + Where(goqu.I("id").In(tenements)) + } + + DeleteTenementsSql, DeleteTenementsArgs, _ := DeleteTenements.ToSQL() + + _, err := tx.Exec(ctx, DeleteTenementsSql, DeleteTenementsArgs...) + if err != nil { + tx.Rollback(ctx) + gm.log.Error("删除商户信息出错",zap.Error(err)) + return err + } + return nil +} diff --git a/router/router.go b/router/router.go index df7c003..e09f7b7 100644 --- a/router/router.go +++ b/router/router.go @@ -57,6 +57,7 @@ func App() *fiber.App { controller.InitializeWithdrawHandlers(app) // 公示撤回 controller.InitializeFoundationHandlers(app) // 基础数据 controller.InitializeStatisticsController(app) // 首页信息 + controller.InitializeGmController(app) // 天神模式 return app } diff --git a/service/god_mode.go b/service/god_mode.go new file mode 100644 index 0000000..462cf9c --- /dev/null +++ b/service/god_mode.go @@ -0,0 +1,46 @@ +package service + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/repository" + "fmt" + "github.com/doug-martin/goqu/v9" + "go.uber.org/zap" +) + +type _GMService struct { + l *zap.Logger + gm goqu.DialectWrapper +} + +var GMService = _GMService{ + logger.Named("Service", "GM"), + goqu.Dialect("postgres"), +} + +func (gm _GMService) DeleteTenements(pid string, tenements []string) error { + var err error + ctx, cancel := global.TimeoutContext() + defer cancel() + + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("未能启动数据库事务", zap.Error(err)) + return fmt.Errorf("未能启动数据库事务,%w", err) + } + + err = repository.GMRepository.DeleteMeterBinding(ctx, tx, pid, tenements) + if err != nil { + tx.Rollback(ctx) + return err + } + + err = repository.GMRepository.DeleteTenements(ctx, tx, pid, tenements) + if err != nil { + tx.Rollback(ctx) + return err + } + tx.Commit(ctx) + return nil +} From b64929c10a06cc3243dd431c4d9715af55b23e54 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Thu, 27 Jul 2023 14:15:34 +0800 Subject: [PATCH 12/24] =?UTF-8?q?=E7=BB=99[=E5=A4=A9=E7=A5=9E=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F]=E5=88=A0=E9=99=A4=E6=8C=87=E5=AE=9A=E5=95=86?= =?UTF-8?q?=E6=88=B7=E5=8A=9F=E8=83=BD=E6=B7=BB=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E8=AE=A4=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 3 ++- controller/statistics.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index 134dc14..eb8fcfd 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -3,6 +3,7 @@ package controller import ( "electricity_bill_calc/logger" "electricity_bill_calc/response" + "electricity_bill_calc/security" "electricity_bill_calc/service" "github.com/gofiber/fiber/v2" "go.uber.org/zap" @@ -11,7 +12,7 @@ import ( var GmLog = logger.Named("Handler", "GM") func InitializeGmController(router *fiber.App) { - router.Delete("/gm/tenement", DeleteTenement) + router.Delete("/gm/tenement", security.SingularityAuthorize, DeleteTenement) } //用于将参数转化为切片 diff --git a/controller/statistics.go b/controller/statistics.go index 2d2c07e..fd0555c 100644 --- a/controller/statistics.go +++ b/controller/statistics.go @@ -15,7 +15,7 @@ var StatisticsWithdrawLog = logger.Named("Handler", "StatisticsWithdraw") func InitializeStatisticsController(router *fiber.App) { router.Get("/audits", security.OPSAuthorize, currentAuditAmount) - router.Get("/stat/reports", statReports) + router.Get("/stat/reports", security.OPSAuthorize, statReports) } From 8ab89bca3409279d6ed03638cb955bfacadff501 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 28 Jul 2023 16:25:49 +0800 Subject: [PATCH 13/24] =?UTF-8?q?[=E5=A4=A9=E7=A5=9E=E6=A8=A1=E5=BC=8F]?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8C=87=E5=AE=9A=E7=9A=84=E5=9B=AD=E5=8C=BA?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 21 +++ repository/god_mode.go | 328 ++++++++++++++++++++++++++++++++++++++++- service/god_mode.go | 41 ++++++ 3 files changed, 387 insertions(+), 3 deletions(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index eb8fcfd..b401838 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -5,14 +5,17 @@ import ( "electricity_bill_calc/response" "electricity_bill_calc/security" "electricity_bill_calc/service" + "errors" "github.com/gofiber/fiber/v2" "go.uber.org/zap" + "net/http" ) var GmLog = logger.Named("Handler", "GM") func InitializeGmController(router *fiber.App) { router.Delete("/gm/tenement", security.SingularityAuthorize, DeleteTenement) + router.Delete("/gm/park", security.SingularityAuthorize, DeletePark) } //用于将参数转化为切片 @@ -39,3 +42,21 @@ func DeleteTenement(c *fiber.Ctx) error { return result.Success("指定商户已经删除。") } + +func DeletePark(c *fiber.Ctx) error { + parks := getQueryValues(c, "parks") + result := response.NewResult(c) + GmLog.Info("[天神模式]删除指定园区", zap.Strings("parks", parks)) + + if len(parks) < 0 { + GmLog.Info("[天神模式]用户未指派园区参数或者未指定需要删除的园区。") + return result.Error(http.StatusBadRequest, error.Error(errors.New("必须至少指定一个需要删除的园区!"))) + } + + err := service.GMService.DeleteParks(parks) + if err != nil { + GmLog.Error("[天神模式]删除指定园区失败",zap.Error(err)) + return result.Error(500,err.Error()) + } + return result.Success("指定园区已经删除。") +} diff --git a/repository/god_mode.go b/repository/god_mode.go index 38f5040..5537efb 100644 --- a/repository/god_mode.go +++ b/repository/god_mode.go @@ -36,7 +36,6 @@ func (gm _GMRepository) DeleteMeterBinding(ctx context.Context, tx pgx.Tx, pid s DeleteQuerySql, DeleteQueryArgs, _ := DeleteQuery.ToSQL() - _, err := tx.Exec(ctx, DeleteQuerySql, DeleteQueryArgs...) if err != nil { gm.log.Error("数据库在删除tenement_meter表数据中出错", zap.Error(err)) @@ -46,7 +45,7 @@ func (gm _GMRepository) DeleteMeterBinding(ctx context.Context, tx pgx.Tx, pid s return nil } -func (gm _GMRepository) DeleteTenements(ctx context.Context, tx pgx.Tx, pid string, tenements []string) error { +func (gm _GMRepository) DeleteTenements(ctx context.Context, tx pgx.Tx, pid string, tenements ...[]string) error { DeleteTenements := gm.ds. From("tenement"). Where(goqu.I("park_id").Eq(pid)). @@ -63,7 +62,330 @@ func (gm _GMRepository) DeleteTenements(ctx context.Context, tx pgx.Tx, pid stri _, err := tx.Exec(ctx, DeleteTenementsSql, DeleteTenementsArgs...) if err != nil { tx.Rollback(ctx) - gm.log.Error("删除商户信息出错",zap.Error(err)) + gm.log.Error("删除商户信息出错", zap.Error(err)) + return err + } + return nil +} + +func (gm _GMRepository) DeleteInvoices(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { + if len(val) > 0 { + updateQuery, updateQueryArgs, _ := gm.ds. + Update(goqu.T("report_tenement")). + Set(goqu.Record{"invoice": nil}). + Where(goqu.I("invoice").In(val)). + Where( + goqu.I("report_id"). + Eq( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + ), + ).ToSQL() + _, err := tx.Exec(ctx, updateQuery, updateQueryArgs...) + if err != nil { + tx.Rollback(ctx) + gm.log.Error("更新发票记录出错", zap.Error(err)) + return err + } + } else { + updateQuery, updateQueryArgs, _ := gm.ds. + Update(goqu.T("report_tenement")). + Set(goqu.Record{"invoice": nil}). + Where( + goqu.I("report_id"). + Eq(gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + )).ToSQL() + _, err := tx.Exec(ctx, updateQuery, updateQueryArgs...) + if err != nil { + tx.Rollback(ctx) + gm.log.Error("更新发票记录出错", zap.Error(err)) + return err + } + } + + deleteQuery := gm.ds. + From(goqu.T("invoices")). + Where(goqu.I("park_id").Eq(parks)). + Delete() + if len(val) > 0 { + deleteQuery.Where(goqu.I("invoice_code").In(val)) + } + deleteQuerySql, deleteQueryArgs, _ := deleteQuery.ToSQL() + + _, err := tx.Exec(ctx, deleteQuerySql, deleteQueryArgs...) + if err != nil { + tx.Rollback(ctx) + gm.log.Error("删除指定园区发票记录出错", zap.Error(err)) + return err + } + return nil + +} + +func (gm _GMRepository) DeleteMeterPookings(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { + deleteQuery := gm.ds. + Delete(goqu.T("meter_relations")). + Where(goqu.I("park_id").Eq(parks)) + + if len(val) > 0 { + deleteQuery = deleteQuery. + Where( + goqu.I("master_meter_id").In(val), + goqu.Or(goqu.I("slave_meter_id").In(val)), + ) + } + deleteQuerySql, deleteQueryArgs, _ := deleteQuery.ToSQL() + _, err := tx.Exec(ctx, deleteQuerySql, deleteQueryArgs...) + if err != nil { + tx.Rollback(ctx) + gm.log.Error("删除指定园区中的表计分摊关系失败", zap.Error(err)) + return err + } + return nil +} + +func (gm _GMRepository) DeleteMeters(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { + deleteQuery := gm.ds. + Delete(goqu.T("meter_04kv")). + Where(goqu.I("park_id").Eq(parks)) + + if len(val) > 0 { + deleteQuery = deleteQuery.Where(goqu.I("code").In(val)) + } + + deleteQuerySql, deleteQueryArgs, _ := deleteQuery.ToSQL() + + _, err := tx.Exec(ctx, deleteQuerySql, deleteQueryArgs...) + if err != nil { + tx.Rollback(ctx) + gm.log.Error("删除指定园区的符合条件的标记出错", zap.Error(err)) + return err + } + return nil +} + +func (gm _GMRepository) DeleteReports(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { + var err error + + if len(val) > 0 { + deleteReportTenementQuerySql, deleteReportTenementQueryArgs, _ := gm.ds. + Delete(goqu.T("report_tenement")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportTenementQuerySql, deleteReportTenementQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportPooledConsumptionQuerySql, deleteReportPooledConsumptionQueryArgs, _ := gm.ds. + Delete(goqu.T("report_pooled_consumption")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportPooledConsumptionQuerySql, deleteReportPooledConsumptionQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportPublicConsumptionQuerySql, deleteReportPublicConsumptionQueryArgs, _ := gm.ds. + Delete(goqu.T("report_public_consumption")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportPublicConsumptionQuerySql, deleteReportPublicConsumptionQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportSummaryQuerySql, deleteReportSummaryQueryArgs, _ := gm.ds. + Delete(goqu.T("report_summary")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportSummaryQuerySql, deleteReportSummaryQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportTaskQuerySql, deleteReportTaskQueryArgs, _ := gm.ds. + Delete(goqu.T("report_task")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportTaskQuerySql, deleteReportTaskQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportQuerySql, deleteReportQueryArgs, _ := gm.ds. + Delete(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)).ToSQL() + _, err = tx.Exec(ctx, deleteReportQuerySql, deleteReportQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + } else { + deleteReportTenementQuerySql, deleteReportTenementQueryArgs, _ := gm.ds. + Delete(goqu.T("report_tenement")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportTenementQuerySql, deleteReportTenementQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportPooledConsumptionQuerySql, deleteReportPooledConsumptionQueryArgs, _ := gm.ds. + Delete(goqu.T("report_pooled_consumption")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportPooledConsumptionQuerySql, deleteReportPooledConsumptionQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportPublicConsumptionQuerySql, deleteReportPublicConsumptionQueryArgs, _ := gm.ds. + Delete(goqu.T("report_public_consumption")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportPublicConsumptionQuerySql, deleteReportPublicConsumptionQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportSummaryQuerySql, deleteReportSummaryQueryArgs, _ := gm.ds. + Delete(goqu.T("report_summary")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportSummaryQuerySql, deleteReportSummaryQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportTaskQuerySql, deleteReportTaskQueryArgs, _ := gm.ds. + Delete(goqu.T("report_task")). + Where(goqu.I("report_id").In( + gm.ds. + From(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)), + )).ToSQL() + _, err = tx.Exec(ctx, deleteReportTaskQuerySql, deleteReportTaskQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + + deleteReportQuerySql, deleteReportQueryArgs, _ := gm.ds. + Delete(goqu.T("report")). + Where(goqu.I("park_id").Eq(parks)).ToSQL() + _, err = tx.Exec(ctx, deleteReportQuerySql, deleteReportQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + } + + return nil +} + +func (gm _GMRepository) DeleteBuildings(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { + if len(val) > 0 { + updateBulidingSql, updateBlidingArgs, _ := gm.ds. + Update(goqu.T("tenement")). + Set(goqu.Record{"building": nil}). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("building").In( + gm.ds. + From(goqu.I("park_building")). + Where(goqu.I("park_id").Eq(parks)). + Where(goqu.I("id").In(val)). + Select(goqu.I("id")), + )).ToSQL() + _, err := tx.Exec(ctx, updateBulidingSql, updateBlidingArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + } else { + updateBulidingSql, updateBlidingArgs, _ := gm.ds. + Update(goqu.T("tenement")). + Set(goqu.Record{"building": nil}). + Where(goqu.I("park_id").Eq(parks)).ToSQL() + _, err := tx.Exec(ctx, updateBulidingSql, updateBlidingArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + } + + deleteQuery := gm.ds. + Delete(goqu.I("park_building")). + Where(goqu.I("park_id").Eq(parks)) + + if len(val) > 0 { + deleteQuery = deleteQuery. + Where(goqu.I("id").In(val)) + } + + deleteQuerySql, deleteQueryArgs, _ := deleteQuery.ToSQL() + _, err := tx.Exec(ctx, deleteQuerySql, deleteQueryArgs...) + if err != nil { + tx.Rollback(ctx) + return err + } + return nil +} + +func (gm _GMRepository) DeleteParks(ctx context.Context, tx pgx.Tx, park []string) error { + deleteParksSql, deleteParksArgs, _ := gm.ds. + Delete(goqu.T("park")). + Where(goqu.I("id").In(park)).ToSQL() + + _, err := tx.Exec(ctx, deleteParksSql, deleteParksArgs...) + if err != nil { + tx.Rollback(ctx) return err } return nil diff --git a/service/god_mode.go b/service/god_mode.go index 462cf9c..7623465 100644 --- a/service/god_mode.go +++ b/service/god_mode.go @@ -44,3 +44,44 @@ func (gm _GMService) DeleteTenements(pid string, tenements []string) error { tx.Commit(ctx) return nil } + +func (gm _GMService) DeleteParks(parks []string) error { + + var err error + ctx, cancel := global.TimeoutContext() + defer cancel() + + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("未能启动数据库事务", zap.Error(err)) + return fmt.Errorf("未能启动数据库事务,%w", err) + } + for _, pid := range parks { + //删除invoices + err = repository.GMRepository.DeleteInvoices(ctx, tx, pid) + //删除meter_binding + err = repository.GMRepository.DeleteMeterBinding(ctx, tx, pid, []string{}) + //删除meter_pookings + err = repository.GMRepository.DeleteMeterPookings(ctx, tx, pid) + //删除tenements + err = repository.GMRepository.DeleteTenements(ctx, tx, pid, []string{}) + //删除meters + err = repository.GMRepository.DeleteMeters(ctx, tx, pid) + //删除reports + err = repository.GMRepository.DeleteReports(ctx, tx, pid) + //删除buildings + err = repository.GMRepository.DeleteBuildings(ctx, tx, pid) + if err != nil { + gm.l.Error("删除关联表出错。", zap.Error(err)) + break + return err + } + } + err = repository.GMRepository.DeleteParks(ctx, tx, parks) + if err != nil { + gm.l.Error("指定园区删除失败。", zap.Error(err)) + return err + } + tx.Commit(ctx) + return nil +} From 18d48c7fea0a85f0207155b053c6fceba97bc5a7 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 28 Jul 2023 16:46:52 +0800 Subject: [PATCH 14/24] =?UTF-8?q?[=E5=A4=A9=E7=A5=9E=E6=A8=A1=E5=BC=8F]?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=AC=A6=E5=90=88=E6=9D=A1=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E6=8A=A5=E8=A1=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 19 +++++++++++++++++-- service/god_mode.go | 19 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index b401838..26d5906 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -16,6 +16,7 @@ var GmLog = logger.Named("Handler", "GM") func InitializeGmController(router *fiber.App) { router.Delete("/gm/tenement", security.SingularityAuthorize, DeleteTenement) router.Delete("/gm/park", security.SingularityAuthorize, DeletePark) + router.Delete("/gm/report", security.SingularityAuthorize, DeleteReports) } //用于将参数转化为切片 @@ -55,8 +56,22 @@ func DeletePark(c *fiber.Ctx) error { err := service.GMService.DeleteParks(parks) if err != nil { - GmLog.Error("[天神模式]删除指定园区失败",zap.Error(err)) - return result.Error(500,err.Error()) + GmLog.Error("[天神模式]删除指定园区失败", zap.Error(err)) + return result.Error(500, err.Error()) } return result.Success("指定园区已经删除。") } + +func DeleteReports(c *fiber.Ctx) error { + pid := c.Query("park") + reports := getQueryValues(c, "reports") + result := response.NewResult(c) + GmLog.Info("[天神模式]删除符合条件的报表。", zap.Strings("reports", reports)) + + err := service.GMService.DeleteReports(pid, reports) + if err != nil { + GmLog.Error("[天神模式]删除指定园区中的报表失败。", zap.Error(err)) + return result.Error(500, err.Error()) + } + return result.Success("指定报表已经删除。") +} diff --git a/service/god_mode.go b/service/god_mode.go index 7623465..a5cd395 100644 --- a/service/god_mode.go +++ b/service/god_mode.go @@ -85,3 +85,22 @@ func (gm _GMService) DeleteParks(parks []string) error { tx.Commit(ctx) return nil } + +func (gm _GMService) DeleteReports(pid string, reports []string) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("未能启动数据库事务", zap.Error(err)) + return fmt.Errorf("未能启动数据库事务,%w", err) + } + + err = repository.GMRepository.DeleteReports(ctx, tx, pid, reports) + if err != nil { + tx.Rollback(ctx) + return err + } + tx.Commit(ctx) + return nil +} From 1dd5f1049d438d55b3efcbe461beed3f636d721e Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 28 Jul 2023 17:29:41 +0800 Subject: [PATCH 15/24] =?UTF-8?q?[=E5=A4=A9=E7=A5=9E=E6=A8=A1=E5=BC=8F]?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=AC=A6=E5=90=88=E6=9D=A1=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E5=95=86=E6=88=B7=E7=BB=91=E5=AE=9A=E7=9A=84=E8=A1=A8=E8=AE=A1?= =?UTF-8?q?=E5=85=B3=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 32 ++++++++++++++++++++++++++------ service/god_mode.go | 24 ++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index 26d5906..9088b23 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -14,9 +14,10 @@ import ( var GmLog = logger.Named("Handler", "GM") func InitializeGmController(router *fiber.App) { - router.Delete("/gm/tenement", security.SingularityAuthorize, DeleteTenement) - router.Delete("/gm/park", security.SingularityAuthorize, DeletePark) - router.Delete("/gm/report", security.SingularityAuthorize, DeleteReports) + router.Delete("/gm/tenement", security.SingularityAuthorize, deleteTenement) + router.Delete("/gm/park", security.SingularityAuthorize, deletePark) + router.Delete("/gm/report", security.SingularityAuthorize, DeleteEnterprise) + router.Delete("/gm/tenement/meter",security.SingularityAuthorize, deleteTenementMeterRelations) } //用于将参数转化为切片 @@ -29,7 +30,7 @@ func getQueryValues(c *fiber.Ctx, paramName string) []string { return result } -func DeleteTenement(c *fiber.Ctx) error { +func deleteTenement(c *fiber.Ctx) error { park := c.Query("park", "") tenements := getQueryValues(c, "tenements") result := response.NewResult(c) @@ -44,7 +45,7 @@ func DeleteTenement(c *fiber.Ctx) error { return result.Success("指定商户已经删除。") } -func DeletePark(c *fiber.Ctx) error { +func deletePark(c *fiber.Ctx) error { parks := getQueryValues(c, "parks") result := response.NewResult(c) GmLog.Info("[天神模式]删除指定园区", zap.Strings("parks", parks)) @@ -62,7 +63,7 @@ func DeletePark(c *fiber.Ctx) error { return result.Success("指定园区已经删除。") } -func DeleteReports(c *fiber.Ctx) error { +func deleteReports(c *fiber.Ctx) error { pid := c.Query("park") reports := getQueryValues(c, "reports") result := response.NewResult(c) @@ -75,3 +76,22 @@ func DeleteReports(c *fiber.Ctx) error { } return result.Success("指定报表已经删除。") } + +func DeleteEnterprise(c *fiber.Ctx) error { + + return nil +} + + +func deleteTenementMeterRelations(c *fiber.Ctx) error { + result := response.NewResult(c) + parkId := c.Query("park") + tId := getQueryValues(c,"tenements") + metersId := getQueryValues(c, "meters") + GmLog.Info("删除指定园区中的商户与表计的关联关系", zap.String("park id", parkId)) + if err := service.GMService.DeleteTenementMeterRelations(parkId, tId, metersId); err != nil { + meterLog.Error("无法删除指定园区中的商户与表计的关联关系", zap.Error(err)) + return result.NotAccept(err.Error()) + } + return result.Success("删除成功") +} \ No newline at end of file diff --git a/service/god_mode.go b/service/god_mode.go index a5cd395..7025c06 100644 --- a/service/god_mode.go +++ b/service/god_mode.go @@ -104,3 +104,27 @@ func (gm _GMService) DeleteReports(pid string, reports []string) error { tx.Commit(ctx) return nil } + +func (gm _GMService) DeleteTenementMeterRelations(pId string, tId []string, mId []string) error { + gm.l.Info("删除商户表记关系", zap.String("tenement", pId)) + ctx, cancel := global.TimeoutContext(10) + defer cancel() + + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("开启数据库事务失败。", zap.Error(err)) + return err + } + if err := repository.GMRepository.DeleteMeterBinding(ctx, tx, pId, tId, mId); err != nil { + gm.l.Error("无法删除商户与表记关系。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + err = tx.Commit(ctx) + if err != nil { + gm.l.Error("未能成功提交数据库事务。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + return nil +} From b84c51b18efdcea1e380011cd3c563603de28561 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 28 Jul 2023 17:33:36 +0800 Subject: [PATCH 16/24] =?UTF-8?q?=E4=BF=AE=E6=AD=A3router=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index 9088b23..1a3537d 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -16,7 +16,7 @@ var GmLog = logger.Named("Handler", "GM") func InitializeGmController(router *fiber.App) { router.Delete("/gm/tenement", security.SingularityAuthorize, deleteTenement) router.Delete("/gm/park", security.SingularityAuthorize, deletePark) - router.Delete("/gm/report", security.SingularityAuthorize, DeleteEnterprise) + router.Delete("/gm/report", security.SingularityAuthorize, deleteReports) router.Delete("/gm/tenement/meter",security.SingularityAuthorize, deleteTenementMeterRelations) } @@ -77,7 +77,7 @@ func deleteReports(c *fiber.Ctx) error { return result.Success("指定报表已经删除。") } -func DeleteEnterprise(c *fiber.Ctx) error { +func deleteEnterprise(c *fiber.Ctx) error { return nil } From c36bfff05a2553a203c66ec553e2f526abc0c72b Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Mon, 31 Jul 2023 09:41:45 +0800 Subject: [PATCH 17/24] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8C=87=E5=AE=9A?= =?UTF-8?q?=E7=9A=84=E4=BC=81=E4=B8=9A=E7=94=A8=E6=88=B7=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 18 +++++++++---- repository/god_mode.go | 59 +++++++++++++++++++++++++++++++++++++++++- service/god_mode.go | 51 ++++++++++++++++++++++++++++++++++-- 3 files changed, 120 insertions(+), 8 deletions(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index 1a3537d..b7b4242 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -17,7 +17,8 @@ func InitializeGmController(router *fiber.App) { router.Delete("/gm/tenement", security.SingularityAuthorize, deleteTenement) router.Delete("/gm/park", security.SingularityAuthorize, deletePark) router.Delete("/gm/report", security.SingularityAuthorize, deleteReports) - router.Delete("/gm/tenement/meter",security.SingularityAuthorize, deleteTenementMeterRelations) + router.Delete("/gm/tenement/meter", security.SingularityAuthorize, deleteTenementMeterRelations) + router.Delete("/gm/enterprise", security.SingularityAuthorize, deleteEnterprise) } //用于将参数转化为切片 @@ -78,15 +79,22 @@ func deleteReports(c *fiber.Ctx) error { } func deleteEnterprise(c *fiber.Ctx) error { + uid := c.Query("uid") + result := response.NewResult(c) + GmLog.Info("[天神模式]删除指定企业用户", zap.String("uid", uid)) - return nil + err := service.GMService.DeleteEnterprises(uid) + if err != nil { + GmLog.Error("[天神模式]删除指定企业用户失败", zap.Error(err)) + return result.Error(500, "删除指定企业用户失败。") + } + return result.Success("指定企业用户已经删除。") } - func deleteTenementMeterRelations(c *fiber.Ctx) error { result := response.NewResult(c) parkId := c.Query("park") - tId := getQueryValues(c,"tenements") + tId := getQueryValues(c, "tenements") metersId := getQueryValues(c, "meters") GmLog.Info("删除指定园区中的商户与表计的关联关系", zap.String("park id", parkId)) if err := service.GMService.DeleteTenementMeterRelations(parkId, tId, metersId); err != nil { @@ -94,4 +102,4 @@ func deleteTenementMeterRelations(c *fiber.Ctx) error { return result.NotAccept(err.Error()) } return result.Success("删除成功") -} \ No newline at end of file +} diff --git a/repository/god_mode.go b/repository/god_mode.go index 5537efb..fed5fc8 100644 --- a/repository/god_mode.go +++ b/repository/god_mode.go @@ -2,9 +2,11 @@ package repository import ( "context" + "electricity_bill_calc/global" "electricity_bill_calc/logger" "fmt" "github.com/doug-martin/goqu/v9" + "github.com/georgysavva/scany/v2/pgxscan" "github.com/jackc/pgx/v5" "go.uber.org/zap" ) @@ -125,7 +127,7 @@ func (gm _GMRepository) DeleteInvoices(ctx context.Context, tx pgx.Tx, parks str } -func (gm _GMRepository) DeleteMeterPookings(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { +func (gm _GMRepository) DeleteMeterPoolings(ctx context.Context, tx pgx.Tx, parks string, val ...[]string) error { deleteQuery := gm.ds. Delete(goqu.T("meter_relations")). Where(goqu.I("park_id").Eq(parks)) @@ -390,3 +392,58 @@ func (gm _GMRepository) DeleteParks(ctx context.Context, tx pgx.Tx, park []strin } return nil } + +func (gm _GMRepository) ListAllParkIdsInUser(ctx context.Context, tx pgx.Tx, uid string) ([]string, error) { + SearchParkIdsSql, SearchParkIdsArgs, _ := gm.ds. + From(goqu.T("park")). + Where(goqu.I("user_id").Eq(uid)). + Select(goqu.I("id")).ToSQL() + var pids []string + err := pgxscan.Select(ctx, global.DB, &pids, SearchParkIdsSql, SearchParkIdsArgs...) + if err != nil { + gm.log.Error("查询["+uid+"]用户下的所有园区失败", zap.Error(err)) + tx.Rollback(ctx) + return nil, err + } + + return pids, nil +} + +func (gm _GMRepository) DeleteUsers(ctx context.Context, tx pgx.Tx, uid string) error { + var err error + //删除用户关联 + DeleteUserChargeSql, DeleteUserChargeArgs, _ := gm.ds. + Delete(goqu.T("user_charge")). + Where(goqu.I("id").Eq(uid)).ToSQL() + + _, err = tx.Exec(ctx,DeleteUserChargeSql,DeleteUserChargeArgs...) + if err != nil { + gm.log.Error("user_charge表关联出错",zap.Error(err)) + tx.Rollback(ctx) + return err + } + + //删除用户详细信息 + DeleteUserDetailSql, DeleteUserDetailArgs,_ := gm.ds. + Delete(goqu.T("user_detail")). + Where(goqu.I("id").Eq(uid)).ToSQL() + _, err = tx.Exec(ctx,DeleteUserDetailSql,DeleteUserDetailArgs...) + if err != nil { + gm.log.Error("user_detail表详细信息出错",zap.Error(err)) + tx.Rollback(ctx) + return err + } + + //删除用户基础信息 + DeleteUserSql, DeleteUserArgs,_ := gm.ds. + Delete(goqu.T("users")). + Where(goqu.I("id").Eq(uid)).ToSQL() + _, err = tx.Exec(ctx,DeleteUserSql,DeleteUserArgs...) + if err != nil { + gm.log.Error("user表基础信息出错",zap.Error(err)) + tx.Rollback(ctx) + return err + } + + return nil +} diff --git a/service/god_mode.go b/service/god_mode.go index 7025c06..6c66439 100644 --- a/service/god_mode.go +++ b/service/god_mode.go @@ -61,8 +61,8 @@ func (gm _GMService) DeleteParks(parks []string) error { err = repository.GMRepository.DeleteInvoices(ctx, tx, pid) //删除meter_binding err = repository.GMRepository.DeleteMeterBinding(ctx, tx, pid, []string{}) - //删除meter_pookings - err = repository.GMRepository.DeleteMeterPookings(ctx, tx, pid) + //删除meter_poolings + err = repository.GMRepository.DeleteMeterPoolings(ctx, tx, pid) //删除tenements err = repository.GMRepository.DeleteTenements(ctx, tx, pid, []string{}) //删除meters @@ -128,3 +128,50 @@ func (gm _GMService) DeleteTenementMeterRelations(pId string, tId []string, mId } return nil } + +func (gm _GMService) DeleteEnterprises(uid string) error { + var err error + ctx, cancel := global.TimeoutContext() + defer cancel() + + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("未能启动数据库事务", zap.Error(err)) + return fmt.Errorf("未能启动数据库事务,%w", err) + } + parks, err := repository.GMRepository.ListAllParkIdsInUser(ctx, tx, uid) + if err != nil { + gm.l.Error("查询园区错误", zap.Error(err)) + tx.Rollback(ctx) + return err + } + + for _, pid := range parks { + err = repository.GMRepository.DeleteInvoices(ctx, tx, pid) + err = repository.GMRepository.DeleteMeterBinding(ctx, tx, pid, []string{}) + err = repository.GMRepository.DeleteMeterPookings(ctx, tx, pid) + err = repository.GMRepository.DeleteTenements(ctx, tx, pid) + err = repository.GMRepository.DeleteMeters(ctx, tx, pid) + err = repository.GMRepository.DeleteReports(ctx, tx, pid) + err = repository.GMRepository.DeleteBuildings(ctx, tx, pid) + + if err != nil { + gm.l.Error("删除用户下关联出错", zap.Error(err)) + return err + } + } + + err = repository.GMRepository.DeleteParks(ctx, tx, parks) + if err != nil { + gm.l.Error("删除用户关联园区错误", zap.Error(err)) + tx.Rollback(ctx) + return err + } + err = repository.GMRepository.DeleteUsers(ctx, tx, uid) + if err != nil { + gm.l.Error("删除用户信息出错", zap.Error(err)) + tx.Rollback(ctx) + return err + } + return nil +} From 9b899be33d199865c60c6864730435cd2ab7ed68 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Mon, 31 Jul 2023 09:50:41 +0800 Subject: [PATCH 18/24] =?UTF-8?q?[=E5=A4=A9=E7=A5=9E=E6=A8=A1=E5=BC=8F]?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=AC=A6=E5=90=88=E6=9D=A1=E4=BB=B6=E8=A1=A8?= =?UTF-8?q?=E8=AE=A1=E5=85=AC=E6=91=8A=E5=85=B3=E7=B3=BB=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 14 ++++++++++++++ service/god_mode.go | 22 ++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/controller/god_mode.go b/controller/god_mode.go index b7b4242..40099cf 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -19,6 +19,7 @@ func InitializeGmController(router *fiber.App) { router.Delete("/gm/report", security.SingularityAuthorize, deleteReports) router.Delete("/gm/tenement/meter", security.SingularityAuthorize, deleteTenementMeterRelations) router.Delete("/gm/enterprise", security.SingularityAuthorize, deleteEnterprise) + router.Delete("/gm/meter/pooling", security.SingularityAuthorize, deleteMeterPoolingRelations) } //用于将参数转化为切片 @@ -103,3 +104,16 @@ func deleteTenementMeterRelations(c *fiber.Ctx) error { } return result.Success("删除成功") } + +func deleteMeterPoolingRelations(c *fiber.Ctx) error { + result := response.NewResult(c) + parkId := c.Query("park") + mId := getQueryValues(c, "meters") + GmLog.Info("[天神模式]删除指定园区中的表计公摊关系", zap.String("park id", parkId)) + if err := service.GMService.DeleteMeterPooling(parkId, mId); err != nil { + meterLog.Error("[天神模式]删除指定园区中的表计公摊关系失败", zap.Error(err)) + return result.Error(500, "删除指定园区中的表计公摊关系失败。") + } + return result.Success("指定表计公摊关系已经删除。") + +} diff --git a/service/god_mode.go b/service/god_mode.go index 6c66439..8001b08 100644 --- a/service/god_mode.go +++ b/service/god_mode.go @@ -175,3 +175,25 @@ func (gm _GMService) DeleteEnterprises(uid string) error { } return nil } + +func (gm _GMService) DeleteMeterPooling(pId string, mId []string) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("开启数据库事务失败。", zap.Error(err)) + return err + } + if err := repository.GMRepository.DeleteMeterPoolings(ctx, tx, pId, mId); err != nil { + gm.l.Error("无法删除指定表记公摊关系。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + err = tx.Commit(ctx) + if err != nil { + gm.l.Error("未能成功提交数据库事务。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + return nil +} \ No newline at end of file From f254ec1f3a703523e0f52257993c1e09e3425f63 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Mon, 31 Jul 2023 10:15:14 +0800 Subject: [PATCH 19/24] =?UTF-8?q?[=E5=A4=A9=E7=A5=9E=E6=A8=A1=E5=BC=8F]?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=AC=A6=E5=90=88=E6=9D=A1=E4=BB=B6=E8=A1=A8?= =?UTF-8?q?=E8=AE=A1=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller/god_mode.go | 13 +++++++++++++ service/god_mode.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/controller/god_mode.go b/controller/god_mode.go index 40099cf..db1a426 100644 --- a/controller/god_mode.go +++ b/controller/god_mode.go @@ -20,6 +20,7 @@ func InitializeGmController(router *fiber.App) { router.Delete("/gm/tenement/meter", security.SingularityAuthorize, deleteTenementMeterRelations) router.Delete("/gm/enterprise", security.SingularityAuthorize, deleteEnterprise) router.Delete("/gm/meter/pooling", security.SingularityAuthorize, deleteMeterPoolingRelations) + router.Delete("gm/meter", security.SingularityAuthorize, deleteMeters) } //用于将参数转化为切片 @@ -117,3 +118,15 @@ func deleteMeterPoolingRelations(c *fiber.Ctx) error { return result.Success("指定表计公摊关系已经删除。") } + +func deleteMeters(c *fiber.Ctx) error { + result := response.NewResult(c) + parkId := c.Query("park") + mId := getQueryValues(c, "meters") + GmLog.Info("[天神模式]删除指定园区中的表计", zap.String("park id", parkId)) + if err := service.GMService.DeleteMeters(parkId, mId); err != nil { + meterLog.Error("[天神模式]删除指定园区中的表计失败", zap.Error(err)) + return result.Error(500, "删除指定园区中的表计失败。") + } + return result.Success("指定表计已经删除。") +} diff --git a/service/god_mode.go b/service/god_mode.go index 8001b08..a493def 100644 --- a/service/god_mode.go +++ b/service/god_mode.go @@ -149,7 +149,7 @@ func (gm _GMService) DeleteEnterprises(uid string) error { for _, pid := range parks { err = repository.GMRepository.DeleteInvoices(ctx, tx, pid) err = repository.GMRepository.DeleteMeterBinding(ctx, tx, pid, []string{}) - err = repository.GMRepository.DeleteMeterPookings(ctx, tx, pid) + err = repository.GMRepository.DeleteMeterPoolings(ctx, tx, pid) err = repository.GMRepository.DeleteTenements(ctx, tx, pid) err = repository.GMRepository.DeleteMeters(ctx, tx, pid) err = repository.GMRepository.DeleteReports(ctx, tx, pid) @@ -189,6 +189,39 @@ func (gm _GMService) DeleteMeterPooling(pId string, mId []string) error { tx.Rollback(ctx) return err } + err = tx.Commit(ctx) + if err != nil { + gm.l.Error("未能成功提交数据库事务。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + return nil +} + +func (gm _GMService) DeleteMeters(pId string, mId []string) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + tx, err := global.DB.Begin(ctx) + if err != nil { + gm.l.Error("开启数据库事务失败。", zap.Error(err)) + return err + } + if err := repository.GMRepository.DeleteMeterBinding(ctx, tx, pId, []string{}, mId); err != nil { + gm.l.Error("删除指定园区中的表计和商户的绑定关系", zap.Error(err)) + tx.Rollback(ctx) + return err + } + if err := repository.GMRepository.DeleteMeterPoolings(ctx, tx, pId, mId); err != nil { + gm.l.Error("无法删除指定表记公摊关系。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + if err := repository.GMRepository.DeleteMeters(ctx, tx, pId, mId); err != nil { + gm.l.Error("删除指定园区中符合条件的表计。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + err = tx.Commit(ctx) if err != nil { gm.l.Error("未能成功提交数据库事务。", zap.Error(err)) From f688f50ecbd7fb058e92bea2da997ebbf6e8a605 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Thu, 3 Aug 2023 16:59:58 +0800 Subject: [PATCH 20/24] =?UTF-8?q?[=E8=AE=A1=E7=AE=97=E7=9B=B8=E5=85=B3]?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=89=80=E6=9C=89=E7=9A=84=E7=89=A9=E4=B8=9A?= =?UTF-8?q?=E8=A1=A8=E8=AE=A1=EF=BC=8C=E7=84=B6=E5=90=8E=E5=AF=B9=E6=89=80?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E7=89=A9=E4=B8=9A=E8=A1=A8=E8=AE=A1=E7=94=B5?= =?UTF-8?q?=E9=87=8F=E8=BF=9B=E8=A1=8C=E8=AE=A1=E7=AE=97=E3=80=82(?= =?UTF-8?q?=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/routerSetting.md | 13 -- model/calculate/calculate.go | 121 ++++++++++++++ model/tenement.go | 10 ++ repository/calculate.go | 171 ++++++++++++++++++++ repository/withdraw.go | 2 +- service/calculate/checking.go | 32 ++++ service/calculate/park.go | 37 +++++ service/calculate/pooled.go | 111 +++++++++++++ service/calculate/shared.go | 105 +++++++++++++ service/calculate/summary.go | 1 + service/calculate/tenement.go | 288 ++++++++++++++++++++++++++++++++++ service/calculate/utils.go | 141 +++++++++++++++++ service/calculate/wattCost.go | 66 ++++++++ tools/utils.go | 1 - 14 files changed, 1084 insertions(+), 15 deletions(-) delete mode 100644 doc/routerSetting.md create mode 100644 service/calculate/checking.go create mode 100644 service/calculate/park.go create mode 100644 service/calculate/pooled.go create mode 100644 service/calculate/shared.go create mode 100644 service/calculate/summary.go create mode 100644 service/calculate/tenement.go create mode 100644 service/calculate/utils.go create mode 100644 service/calculate/wattCost.go diff --git a/doc/routerSetting.md b/doc/routerSetting.md deleted file mode 100644 index 6e9c627..0000000 --- a/doc/routerSetting.md +++ /dev/null @@ -1,13 +0,0 @@ -## fiber -#### fiber实例 -- app(是fiber创建的实例通常用app表示,其中有可选配置选项) - - BodyLimit 设置请求正文允许的最大大小(默认为4 * 1024 * 1024) - - EnablePrintRoutes 不打印框架自带日志(默认false) - - EnableTrustedProxyCheck 禁用受信代理(默认false) - - Prefork 预处理配置(默认false) - - ErrorHandler 全局错误处理 (默认false) - - JSONEncoder json编码 (默认json.Marshal) - - JSONDecoder json解码 (默认json.Unmarshal) - - 。。。。。。。。(还有很多配置) -- Use(中间件设置,一个或者多个) -- Group(类似于gin框架中的路由分组) \ No newline at end of file diff --git a/model/calculate/calculate.go b/model/calculate/calculate.go index da5177c..ff5ebb7 100644 --- a/model/calculate/calculate.go +++ b/model/calculate/calculate.go @@ -3,6 +3,7 @@ package calculate import ( "electricity_bill_calc/model" "electricity_bill_calc/types" + "fmt" "github.com/shopspring/decimal" ) @@ -42,6 +43,11 @@ type Meter struct { Poolings []*Pooling } +type PrimaryTenementStatistics struct { + Tenement model.Tenement + Meters []Meter +} + type TenementCharge struct { Tenement string Overall model.ConsumptionUnit @@ -90,3 +96,118 @@ type PoolingSummary struct { OverallAmount decimal.Decimal PoolingProportion decimal.Decimal } + +func FromReportSummary(summary *model.ReportSummary, pricingMode *model.ReportIndex) Summary { + var parkPrice float64 + switch pricingMode.PricePolicy { + case model.PRICING_POLICY_CONSUMPTION: + parkPrice = summary.ConsumptionFee.Decimal.InexactFloat64() / summary.Overall.Amount.InexactFloat64() + case model.PRICING_POLICY_ALL: + parkPrice = summary.Overall.Fee.InexactFloat64() / summary.Overall.Amount.InexactFloat64() + default: + fmt.Println("无法识别类型") + } + + flatAmount := summary.Overall.Amount.InexactFloat64() - + summary.Critical.Amount.InexactFloat64() - + summary.Peak.Amount.InexactFloat64() - + summary.Valley.Amount.InexactFloat64() + + flatFee := summary.Overall.Amount.InexactFloat64() - + summary.Critical.Fee.InexactFloat64() - + summary.Peak.Fee.InexactFloat64() - + summary.Valley.Fee.InexactFloat64() + + var OverallPrice float64 + if summary.Overall.Amount.GreaterThan(decimal.Zero) { + OverallPrice = parkPrice + } else { + OverallPrice = decimal.Zero.InexactFloat64() + } + + var CriticalPrice float64 + if summary.Critical.Amount.GreaterThan(decimal.Zero) { + CriticalPrice = summary.Critical.Fee.InexactFloat64() / summary.Critical.Amount.InexactFloat64() + } else { + CriticalPrice = decimal.Zero.InexactFloat64() + } + + var PeakPrice float64 + if summary.Peak.Amount.GreaterThan(decimal.Zero) { + PeakPrice = summary.Peak.Fee.InexactFloat64() / summary.Peak.Amount.InexactFloat64() + } else { + PeakPrice = decimal.Zero.InexactFloat64() + } + + var FlatPrice float64 + if decimal.NewFromFloat(flatAmount).GreaterThan(decimal.Zero) { + FlatPrice = flatFee / flatAmount + } else { + FlatPrice = decimal.Zero.InexactFloat64() + } + + var ValleyPrice float64 + if summary.Valley.Amount.GreaterThan(decimal.Zero) { + ValleyPrice = summary.Valley.Fee.InexactFloat64() / summary.Valley.Amount.InexactFloat64() + } else { + ValleyPrice = decimal.Zero.InexactFloat64() + } + + var LossDilutedPrice float64 + if summary.Overall.Amount.GreaterThan(decimal.Zero) { + LossDilutedPrice = parkPrice + } else { + LossDilutedPrice = decimal.Zero.InexactFloat64() + } + + _ = parkPrice + + return Summary{ + ReportId: summary.ReportId, + OverallArea: decimal.Zero, + Overall: model.ConsumptionUnit{ + Amount: summary.Overall.Amount, + Fee: summary.Overall.Fee, + Price: decimal.NewFromFloat(OverallPrice), + Proportion: decimal.NewFromFloat(1.0), + }, + ConsumptionFee: summary.ConsumptionFee.Decimal, + Critical: model.ConsumptionUnit{ + Amount: summary.Critical.Amount, + Fee: summary.Critical.Fee, + Price: decimal.NewFromFloat(CriticalPrice), + Proportion: decimal.NewFromFloat(summary.Critical.Amount.InexactFloat64() / summary.Overall.Amount.InexactFloat64()), + }, + Peak: model.ConsumptionUnit{ + Amount: summary.Peak.Amount, + Fee: summary.Peak.Fee, + Price: decimal.NewFromFloat(PeakPrice), + Proportion: decimal.NewFromFloat(summary.Peak.Amount.InexactFloat64() / summary.Overall.Amount.InexactFloat64()), + }, + Flat: model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(flatAmount), + Fee: decimal.NewFromFloat(flatFee), + Price: decimal.NewFromFloat(FlatPrice), + Proportion: decimal.NewFromFloat(flatAmount / summary.Overall.Amount.InexactFloat64()), + }, + Valley: model.ConsumptionUnit{ + Amount: summary.Valley.Amount, + Fee: summary.Valley.Fee, + Price: decimal.NewFromFloat(ValleyPrice), + Proportion: decimal.NewFromFloat(summary.Valley.Amount.InexactFloat64() / summary.Overall.Amount.InexactFloat64()), + }, + Loss: decimal.Zero, + LossFee: decimal.Zero, + LossProportion: decimal.Zero, + AuthoizeLoss: model.ConsumptionUnit{}, + BasicFee: summary.BasicFee, + BasicPooledPriceConsumption: decimal.Zero, + BasicPooledPriceArea: decimal.Zero, + AdjustFee: summary.AdjustFee, + AdjustPooledPriceConsumption: decimal.Zero, + AdjustPooledPriceArea: decimal.Zero, + LossDilutedPrice: decimal.NewFromFloat(LossDilutedPrice), + TotalConsumption: decimal.Zero, + FinalDilutedOverall: decimal.Zero, + } +} diff --git a/model/tenement.go b/model/tenement.go index eda08f0..c5c0282 100644 --- a/model/tenement.go +++ b/model/tenement.go @@ -21,3 +21,13 @@ type Tenement struct { LastModifiedAt types.DateTime `json:"lastModifiedAt" db:"last_modified_at"` DeletedAt *types.DateTime `json:"deletedAt" db:"deleted_at"` } + +type TenementMeter struct { + ParkId string `db:"park_id"` + TenementId string `db:"tenement_id"` + MeterId string `db:"meter_id"` + ForeignRelation bool `db:"foreign_relation"` + AssociatedAt types.DateTime `db:"associated_at"` + DisassociatedAt types.DateTime `db:"disassociated_at"` + SynchronizedAt types.DateTime `db:"synchronized_at"` +} diff --git a/repository/calculate.go b/repository/calculate.go index 440d9ef..5f04d4c 100644 --- a/repository/calculate.go +++ b/repository/calculate.go @@ -5,6 +5,7 @@ import ( "electricity_bill_calc/logger" "electricity_bill_calc/model" "electricity_bill_calc/types" + "time" "github.com/doug-martin/goqu/v9" _ "github.com/doug-martin/goqu/v9/dialect/postgres" @@ -68,3 +69,173 @@ func (cr _CalculateRepository) UpdateReportTaskStatus(rid string, status int16, } return res.RowsAffected() > 0, nil } + +//获取当前园区中所有公摊表计与商户表计之间的关联关系,包括已经解除的 +func (cr _CalculateRepository) GetAllPoolingMeterRelations(pid string, revokedAfter time.Time) ([]model.MeterRelation, error) { + cr.log.Info("获取当前园区中所有公摊表计与商户表计之间的关联关系,包括已经解除的", zap.String("pid", pid), zap.Time("revokedAfter", revokedAfter)) + + ctx, cancel := global.TimeoutContext() + defer cancel() + relationsSql, relationsArgs, _ := cr.ds. + From(goqu.T("meter_relations")). + Where(goqu.I("park_id").Eq(pid)). + Where(goqu.Or( + goqu.I("revoked_at").IsNull(), + goqu.I("revoked_at").Gte(revokedAfter), + )).ToSQL() + + var meterRelation []model.MeterRelation + + err := pgxscan.Select(ctx, global.DB, meterRelation, relationsSql, relationsArgs...) + if err != nil { + cr.log.Error("获取当前园区中所有公摊表计与商户表计之间的关联关系,包括已经解除的出错", zap.Error(err)) + return nil, err + } + return meterRelation, nil +} + +//获取当前园区中所有的商户与表计的关联关系,包括已经解除的 +func (cr _CalculateRepository) GetAllTenementMeterRelations(pid string, associatedBefore time.Time, disassociatedAfter time.Time) ([]model.TenementMeter, error) { + cr.log.Info("获取当前园区中所有的商户与表计的关联关系,包括已经解除的", zap.String("pid", pid), zap.Time("associatedBefore", associatedBefore), zap.Time("disassociatedAfter", disassociatedAfter)) + ctx, cancel := global.TimeoutContext() + defer cancel() + + relationsQuerySql, relationsQueryArgs, _ := cr.ds. + From(goqu.T("tenement_meter")). + Where(goqu.I("park_id").Eq(pid)). + Where(goqu.And( + goqu.I("associated_at").IsNull(), + goqu.I("associated_at").Lte(associatedBefore), + )). + Where(goqu.And( + goqu.I("associated_at").IsNull(), + goqu.I("associated_at").Gte(disassociatedAfter), + )).ToSQL() + + var tenementMeter []model.TenementMeter + + err := pgxscan.Select(ctx, global.DB, tenementMeter, relationsQuerySql, relationsQueryArgs...) + if err != nil { + cr.log.Error("获取当前园区中所有的商户与表计的关联关系,包括已经解除的", zap.Error(err)) + return nil, err + } + return tenementMeter, nil + +} + +//获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据 +func (cr _CalculateRepository) GetMeterReadings(rid string, meterType int16) ([]model.MeterReading, error) { + cr.log.Info("获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据", zap.String("rid", rid), zap.Int16("meterType", meterType)) + + ctx, cancel := global.TimeoutContext() + defer cancel() + + readingsQuerySql, readingsQueryArgs, _ := cr.ds. + From(goqu.T("meter_reading").As(goqu.I("mr"))). + Join( + goqu.T("report").As("r"), + goqu.On(goqu.I("r.park_id").Eq(goqu.I("mr.park_id"))), + ). + Where( + goqu.I("r.id").Eq(rid), + goqu.I("mr.meter_type").Eq(meterType), + // TODO:2023.08.02 此方法出错优先查看是否这里出问题 + goqu.I("mr.read_at::date <@ r.period"), + ). + Order(goqu.I("mr.read_at").Asc()).Select(goqu.I("mr.*")).ToSQL() + + var readings []model.MeterReading + + err := pgxscan.Select(ctx, global.DB, readings, readingsQuerySql, readingsQueryArgs...) + if err != nil { + cr.log.Error("获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据出错", zap.Error(err)) + return nil, err + } + return readings, nil +} + +// 获取指定报表中所有涉及到的表计在核算起始日期前的最后一次读数 +func (cr _CalculateRepository) GetLastPeriodReadings(rid string, meterType int16) ([]model.MeterReading, error) { + cr.log.Info("获取指定报表中所有涉及到的表计在核算起始日期前的最后一次读数", zap.String("rid", rid), zap.Int16("meterType", meterType)) + + ctx, cancel := global.TimeoutContext() + defer cancel() + + readingsSql, readingsArgs, _ := cr.ds.From(goqu.T("meter_reading").As("mr")). + Select( + goqu.MAX("mr.read_at").As("read_at"), + goqu.I("mr.park_id"), + goqu.I("mr.meter_id"), + goqu.I("mr.meter_type"), + goqu.I("mr.ratio"), + goqu.I("mr.overall"), + goqu.I("mr.critical"), + goqu.I("mr.peak"), + goqu.I("mr.flat"), + goqu.I("mr.valley"), + ). + Join( + goqu.T("report").As("r"), + goqu.On(goqu.I("r.park_id").Eq(goqu.I("mr.park_id"))), + ). + Where( + goqu.I("r.id").Eq(rid), + goqu.I("mr.meter_type").Eq(meterType), + goqu.I(" mr.read_at::date <= lower(r.period)"), + ). + GroupBy( + goqu.I("mr.park_id"), + goqu.I("mr.meter_id"), + goqu.I("mr.meter_type"), + goqu.I("mr.ratio"), + goqu.I("mr.overall"), + goqu.I("mr.critical"), + goqu.I("mr.peak"), + goqu.I("mr.flat"), + goqu.I("mr.valley"), + goqu.I("r.period"), + ).ToSQL() + + var readings []model.MeterReading + err := pgxscan.Select(ctx, global.DB, readings, readingsSql, readingsArgs...) + if err != nil { + cr.log.Error("获取指定报表中所有涉及到的表计在核算起始日期前的最后一次读数出错", zap.Error(err)) + return nil, err + } + return readings, nil +} + +// 取得指定报表所涉及的所有商户信息 +func (cr _CalculateRepository) GetAllTenements(rid string) ([]model.Tenement, error) { + cr.log.Info("取得指定报表所涉及的所有商户信息", zap.String("rid", rid)) + + ctx, cancel := global.TimeoutContext() + defer cancel() + + tenementQuerySql, tenementQueryArgs, _ := cr.ds. + From(goqu.T("tenement").As("t")). + LeftJoin( + goqu.T("park_building").As("b"), + goqu.On(goqu.I("b.id").Eq(goqu.I("t.building"))), + ). + Join( + goqu.T("report").As("r"), + goqu.On(goqu.I("r.park_id").Eq(goqu.I("t.park_id"))), + ). + Select( + goqu.I("t.*"), + goqu.I("b.name").As("building_name"), + ). + Where( + goqu.I("r.id").Eq(rid), + goqu.I("t.moved_in_at <= upper(r.period)"), + ).ToSQL() + + var tenements []model.Tenement + err := pgxscan.Select(ctx, global.DB, tenements, tenementQuerySql, tenementQueryArgs...) + if err != nil { + cr.log.Error("取得指定报表所涉及的所有商户信息出错", zap.Error(err)) + return nil, err + } + return tenements, nil +} diff --git a/repository/withdraw.go b/repository/withdraw.go index a83b43a..c30bd19 100644 --- a/repository/withdraw.go +++ b/repository/withdraw.go @@ -132,7 +132,7 @@ func (wd _WithdrawRepository) FindWithdraw(page uint, keyword *string) ([]model. PeriodBegin: Begin, PeriodEnd: End, Published: v.Published, - PublishedAt: nil, + PublishedAt: tools.TimeToStringPtr(v.LastWithdrawAuditAt), Status: 0., Withdraw: v.Withdraw, } diff --git a/service/calculate/checking.go b/service/calculate/checking.go new file mode 100644 index 0000000..7169626 --- /dev/null +++ b/service/calculate/checking.go @@ -0,0 +1,32 @@ +package calculate +import ( + "electricity_bill_calc/model" + "fmt" + "sync/atomic" +) + +func CheckMeterArea(report *model.ReportIndex, meters []*model.MeterDetail) (bool, error) { + anyAreaOptions := report.BasisPooled == model.POOLING_MODE_AREA || + report.AdjustPooled == model.POOLING_MODE_AREA || + report.PublicPooled == model.POOLING_MODE_AREA || + report.LossPooled == model.POOLING_MODE_AREA + + if anyAreaOptions { + var meterWithoutArea int32 + + for _, m := range meters { + if (m.MeterType == model.METER_INSTALLATION_TENEMENT || m.MeterType == model.METER_INSTALLATION_POOLING) && + m.Area == nil { + atomic.AddInt32(&meterWithoutArea, 1) + } + } + + if meterWithoutArea != 0 { + return false, fmt.Errorf("园区中有 %d 个表计没有设置面积,无法进行按面积摊薄。", meterWithoutArea) + } + + return true, nil + } + + return false, nil +} diff --git a/service/calculate/park.go b/service/calculate/park.go new file mode 100644 index 0000000..1af4ee2 --- /dev/null +++ b/service/calculate/park.go @@ -0,0 +1,37 @@ +package calculate + +import ( + "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" + "electricity_bill_calc/repository" + "time" +) + +func MetersParkCalculate(report model.ReportIndex, periodStart time.Time, + periodEnd time.Time, meterDetail []*model.MeterDetail, + summary calculate.Summary) ([]calculate.Meter, error) { + parkMeterReadings, err := repository.CalculateRepository.GetMeterReadings(report.Id, model.METER_INSTALLATION_PARK) + if err != nil { + return nil, err + } + + lastTermParkMeterReadings, err := repository.CalculateRepository.GetLastPeriodReadings(report.Id, model.METER_INSTALLATION_PARK) + if err != nil { + return nil, err + } + + parkMeterReadings = append(parkMeterReadings, lastTermParkMeterReadings...) + + var parkMetersReports []calculate.Meter + for _, meter := range meterDetail { + if meter.MeterType == model.METER_INSTALLATION_PARK { + parkMetersReport, err := determinePublicMeterConsumptions(meter.Code, periodStart, periodEnd, parkMeterReadings, *meter, summary) + if err != nil { + return nil, err + } + parkMetersReports = append(parkMetersReports, parkMetersReport) + } + + } + return parkMetersReports, nil +} diff --git a/service/calculate/pooled.go b/service/calculate/pooled.go new file mode 100644 index 0000000..12ddc91 --- /dev/null +++ b/service/calculate/pooled.go @@ -0,0 +1,111 @@ +package calculate + +import ( + "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" + "electricity_bill_calc/repository" + "github.com/shopspring/decimal" + "time" + "unsafe" +) + +//核算园区中的全部公摊表计的电量用量 +func PooledMetersCalculate(report *model.ReportIndex, periodStart time.Time, + periodEnd time.Time, meterDetails []*model.MeterDetail, + summary calculate.Summary) ([]calculate.Meter, error) { + poolingMeterReadings, err := repository.CalculateRepository.GetMeterReadings(report.Id, model.METER_INSTALLATION_POOLING) + if err != nil { + return nil, err + } + + lastTermPoolingMeterReadings, err := repository.CalculateRepository.GetLastPeriodReadings(report.Id, model.METER_INSTALLATION_POOLING) + if err != nil { + return nil, err + } + + poolingMeterReadings = append(poolingMeterReadings, lastTermPoolingMeterReadings...) + + var poolingMetersReports []calculate.Meter + for _, meter := range meterDetails { + poolingMetersReport, err := determinePublicMeterConsumptions(meter.Code, periodStart, periodEnd, poolingMeterReadings, *meter, summary) + if err != nil { + return nil, err + } + poolingMetersReports = append(poolingMetersReports, poolingMetersReport) + } + return poolingMetersReports, nil +} + +// 确定指定非商户表计在指定时间段内的全部电量 +func determinePublicMeterConsumptions(meterId string, periodStart time.Time, + periodEnd time.Time, readings []model.MeterReading, + meterDetail model.MeterDetail, summary calculate.Summary) (calculate.Meter, error) { + startReading, err := DeterminePublicMeterStartReading(meterId, periodStart, meterDetail.DetachedAt.Time, readings) + if err != nil { + return calculate.Meter{}, err + } + + endReading, err := DeterminePublicMeterEndReading(meterId, periodEnd, meterDetail.DetachedAt.Time, readings) + if err != nil { + return calculate.Meter{}, err + } + + overall, err := ComputeOverall(*startReading, *endReading, summary) + if err != nil { + return calculate.Meter{}, err + } + + critical, err := ComputeCritical(*startReading, *endReading, summary) + if err != nil { + return calculate.Meter{}, err + } + + peak, err := ComputePeak(*startReading, *endReading, summary) + if err != nil { + return calculate.Meter{}, err + } + + flat, err := ComputeFlat(*startReading, *endReading, summary) + if err != nil { + return calculate.Meter{}, err + } + + valley, err := ComputeValley(*startReading, *endReading, summary) + if err != nil { + return calculate.Meter{}, err + } + + return calculate.Meter{ + Code: meterId, + Detail: meterDetail, + CoveredArea: meterDetail.Area.Decimal, + LastTermReading: (*calculate.Reading)(unsafe.Pointer(&model.Reading{ + Ratio: startReading.Ratio, + Overall: startReading.Overall, + Critical: startReading.Critical, + Peak: startReading.Peak, + Flat: startReading.Flat, + Valley: startReading.Valley, + })), + CurrentTermReading: (*calculate.Reading)(unsafe.Pointer(&model.Reading{ + Ratio: endReading.Ratio, + Overall: endReading.Overall, + Critical: endReading.Critical, + Peak: endReading.Peak, + Flat: endReading.Flat, + Valley: endReading.Valley, + })), + Overall: overall, + Critical: critical, + Peak: peak, + Flat: flat, + Valley: valley, + AdjustLoss: model.ConsumptionUnit{}, + PooledBasic: model.ConsumptionUnit{}, + PooledAdjust: model.ConsumptionUnit{}, + PooledLoss: model.ConsumptionUnit{}, + PooledPublic: model.ConsumptionUnit{}, + SharedPoolingProportion: decimal.Decimal{}, + Poolings: nil, + }, nil +} diff --git a/service/calculate/shared.go b/service/calculate/shared.go new file mode 100644 index 0000000..528d1fc --- /dev/null +++ b/service/calculate/shared.go @@ -0,0 +1,105 @@ +package calculate + +import ( + "electricity_bill_calc/model" + "electricity_bill_calc/types" + "errors" + "fmt" + "time" +) + +// 确定指定非商户表计的起始读数 +func DeterminePublicMeterStartReading(meterId string, periodStart time.Time, + attachedAt time.Time, meterReadings []model.MeterReading) (*model.MeterReading, error) { + periodBeginning := types.Date{Time: periodStart}.ToBeginningOfDate() + + if len(meterReadings) <= 0 { + return nil, errors.New(fmt.Sprintf("表计的抄表记录数据不足%s", meterId)) + } + + var minReading types.DateTime + for _, reading := range meterReadings { + if reading.ReadAt.Before(minReading.Time) { + minReading = reading.ReadAt + } + } + startTimes := []time.Time{ + minReading.Time, + periodBeginning.Time, + ShiftToAsiaShanghai(attachedAt), + } + if len(startTimes) < 0 { + return nil, errors.New(fmt.Sprintf("无法确定表计 {%s} 的计量的起始时间", meterId)) + } + + var startReading []model.MeterReading + for _, reading := range meterReadings { + readingAt := ShiftToAsiaShanghai(reading.ReadAt.UTC()) + for _, startTime := range startTimes { + if reading.Meter == meterId && readingAt.After(startTime) || readingAt.Equal(startTime) { + startReading = append(startReading, reading) + break + } + } + } + + if len(startReading) <= 0 { + return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的起始读数", meterId)) + } + + var startReadings *model.MeterReading + for _, readings := range startReading { + if startReadings == nil || readings.ReadAt.Before(startReadings.ReadAt.Time) { + startReadings = &readings + } + } + return startReadings, nil +} + +// 确定指定非商户表计的结束读数 +func DeterminePublicMeterEndReading(meterId string, periodEnd time.Time, + detachedAt time.Time, meterReadings []model.MeterReading) (*model.MeterReading, error) { + periodEnding := types.Date{Time: periodEnd}.ToEndingOfDate() + + if len(meterReadings) <= 0 { + return nil, errors.New(fmt.Sprintf("表计的抄表记录数据不足%s", meterId)) + } + + var minReading types.DateTime + for _, reading := range meterReadings { + if reading.ReadAt.Before(minReading.Time) { + minReading = reading.ReadAt + } + } + startTimes := []time.Time{ + minReading.Time, + periodEnding.Time, + ShiftToAsiaShanghai(detachedAt), + } + if len(startTimes) < 0 { + return nil, errors.New(fmt.Sprintf("无法确定表计 {%s} 的计量的终止时间", meterId)) + } + + var startReading []model.MeterReading + for _, reading := range meterReadings { + readingAt := ShiftToAsiaShanghai(reading.ReadAt.UTC()) + for _, startTime := range startTimes { + if reading.Meter == meterId && readingAt.After(startTime) || readingAt.Equal(startTime) { + startReading = append(startReading, reading) + break + } + } + } + + if len(startReading) <= 0 { + return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的终止读数", meterId)) + } + + var startReadings *model.MeterReading + for _, readings := range startReading { + if startReadings == nil || readings.ReadAt.Before(startReadings.ReadAt.Time) { + startReadings = &readings + } + } + return startReadings, nil +} diff --git a/service/calculate/summary.go b/service/calculate/summary.go new file mode 100644 index 0000000..8b0bbf7 --- /dev/null +++ b/service/calculate/summary.go @@ -0,0 +1 @@ +package calculate diff --git a/service/calculate/tenement.go b/service/calculate/tenement.go new file mode 100644 index 0000000..ca82dad --- /dev/null +++ b/service/calculate/tenement.go @@ -0,0 +1,288 @@ +package calculate + +import ( + "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" + "electricity_bill_calc/repository" + "errors" + "fmt" + "github.com/shopspring/decimal" + "strings" + "time" + "unsafe" +) + +// 核算园区中的全部商户表计电量用电 +func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, + PeriodEnd time.Time, meterDetails []*model.MeterDetail, + summary calculate.Summary) ([]model.TenementMeter, error) { + tenements, err := repository.CalculateRepository.GetAllTenements(report.Id) + if err != nil { + fmt.Println("tenement 0", err) + return nil, err + } + + tenementMeterRelations, err := repository.CalculateRepository.GetAllTenementMeterRelations(report.Park, PeriodEnd, PeriodStart) + if err != nil { + fmt.Println("tenement 1", err) + return nil, err + } + + tenementMeterReadings, err := repository.CalculateRepository.GetMeterReadings(report.Id, model.METER_INSTALLATION_TENEMENT) + if err != nil { + fmt.Println("tenement 2", err) + return nil, err + } + + lastPeriodReadings, err := repository.CalculateRepository.GetLastPeriodReadings(report.Id, model.METER_INSTALLATION_TENEMENT) + if err != nil { + fmt.Println("tenement 3", err) + return nil, err + } + + var tenementReports []model.Tenement + + for _, tenement := range tenements { + var meters []model.TenementMeter + + for _, relation := range tenementMeterRelations { + if strings.EqualFold(relation.TenementId, tenement.Id) { + meters = append(meters, relation) + } + } + + pt, err := determineTenementConsumptions( + tenement, + meters, + PeriodStart, + PeriodEnd, + tenementMeterReadings, + lastPeriodReadings, + meterDetails, + summary, + ) + if err != nil { + return nil, err + } + + report := model.Tenement{ + Id: pt.Tenement.Id, + Park: pt.Tenement.Park, + FullName: pt.Tenement.FullName, + ShortName: pt.Tenement.ShortName, + Abbr: pt.Tenement.Abbr, + Address: pt.Tenement.Address, + ContactName: pt.Tenement.ContactName, + ContactPhone: pt.Tenement.ContactPhone, + Building: pt.Tenement.Building, + BuildingName: pt.Tenement.BuildingName, + OnFloor: pt.Tenement.OnFloor, + InvoiceInfo: pt.Tenement.InvoiceInfo, + MovedInAt: pt.Tenement.MovedInAt, + MovedOutAt: pt.Tenement.MovedOutAt, + CreatedAt: pt.Tenement.CreatedAt, + LastModifiedAt: pt.Tenement.LastModifiedAt, + DeletedAt: pt.Tenement.DeletedAt, + } + + tenementReports = append(tenementReports, report) + } + + return tenementMeterRelations, nil +} + +//TODO: 2023.08.02 此方法未完成此方法主要用于。确定指定商户在指定时间段内的所有表计读数(完成) +func determineTenementConsumptions(tenement model.Tenement, + relatedMeters []model.TenementMeter, periodStart time.Time, + periodEnd time.Time, currentTermReadings []model.MeterReading, lastPeriodReadings []model.MeterReading, + meterDetails []*model.MeterDetail, summary calculate.Summary) (calculate.PrimaryTenementStatistics, error) { + var meters []calculate.Meter + for _, meter := range relatedMeters { + startReading, err := determineTenementMeterStartReading(meter.MeterId, periodStart, ShiftToAsiaShanghai(tenement.MovedInAt.Time), meter, currentTermReadings, lastPeriodReadings) + if err != nil { + fmt.Println(err) + return calculate.PrimaryTenementStatistics{}, err + } + + endReading, err := determineTenementMeterEndReading(meter.MeterId, periodEnd, ShiftToAsiaShanghai(tenement.MovedOutAt.Time), meter, currentTermReadings) + if err != nil { + fmt.Println(err) + return calculate.PrimaryTenementStatistics{}, err + } + + detail, err := getMeterDetail(meterDetails, meter.MeterId) + if err != nil { + return calculate.PrimaryTenementStatistics{}, err + } + + overall, err := ComputeOverall(*startReading, *endReading, summary) + if err != nil { + return calculate.PrimaryTenementStatistics{}, err + } + + critical, err := ComputeCritical(*startReading, *endReading, summary) + if err != nil { + return calculate.PrimaryTenementStatistics{}, err + } + + peak, err := ComputePeak(*startReading, *endReading, summary) + if err != nil { + return calculate.PrimaryTenementStatistics{}, err + } + + flat, err := ComputeFlat(*startReading, *endReading, summary) + if err != nil { + return calculate.PrimaryTenementStatistics{}, err + } + + valley, err := ComputeValley(*startReading, *endReading, summary) + if err != nil { + return calculate.PrimaryTenementStatistics{}, err + } + + lastTermReading := model.Reading{ + Ratio: startReading.Ratio, + Overall: startReading.Overall, + Critical: startReading.Critical, + Peak: startReading.Peak, + Flat: startReading.Flat, + Valley: startReading.Valley, + } + + lastTermReadingPtr := &lastTermReading + + currentTermReading := model.Reading{ + Ratio: endReading.Ratio, + Overall: endReading.Overall, + Critical: endReading.Critical, + Peak: endReading.Peak, + Flat: endReading.Flat, + Valley: endReading.Valley, + } + + currentTermReadingPtr := ¤tTermReading + meter := calculate.Meter{ + Code: meter.MeterId, + Detail: detail, + CoveredArea: decimal.NewFromFloat(detail.Area.Decimal.InexactFloat64()), + + LastTermReading: (*calculate.Reading)(unsafe.Pointer(lastTermReadingPtr)), + CurrentTermReading: (*calculate.Reading)(unsafe.Pointer(currentTermReadingPtr)), + + Overall: overall, + Critical: critical, + Peak: peak, + Flat: flat, + Valley: valley, + + AdjustLoss: model.ConsumptionUnit{}, + PooledBasic: model.ConsumptionUnit{}, + PooledAdjust: model.ConsumptionUnit{}, + PooledLoss: model.ConsumptionUnit{}, + PooledPublic: model.ConsumptionUnit{}, + SharedPoolingProportion: decimal.Decimal{}, + Poolings: nil, + } + + meters = append(meters, meter) + } + + return calculate.PrimaryTenementStatistics{ + Tenement: tenement, + Meters: meters, + }, nil +} + +func getMeterDetail(meterDetails []*model.MeterDetail, code string) (model.MeterDetail, error) { + for _, detail := range meterDetails { + if detail.Code == code { + return *detail, nil + } + } + return model.MeterDetail{}, errors.New(fmt.Sprintf("表计 %s 的详细信息不存在", code)) +} + +//确定指定表计的起始读数 +func determineTenementMeterStartReading(meterId string, periodStart time.Time, tenementMovedInAt time.Time, + meterRelation model.TenementMeter, currentTermReadings []model.MeterReading, + lastPeriodReadings []model.MeterReading) (*model.MeterReading, error) { + var startTime time.Time + timeList := []time.Time{ + periodStart, + tenementMovedInAt, + meterRelation.AssociatedAt.Time, + } + + for _, t := range timeList { + if t.After(startTime) { + startTime = t + } + } + if startTime.IsZero() { + return nil, fmt.Errorf("无法确定表计 %s 的计量的起始时间", meterId) + } + + var startReading *model.MeterReading + if startTime.Equal(periodStart) { + for _, reading := range lastPeriodReadings { + if reading.Meter == meterId { + if startReading == nil || reading.ReadAt.After(startReading.ReadAt.Time) { + startReading = &reading + } + } + } + } else { + for _, reading := range currentTermReadings { + readingAt := ShiftToAsiaShanghai(reading.ReadAt.Time) + if reading.Meter == meterId && readingAt.After(startTime) { + if startReading == nil || readingAt.Before(startReading.ReadAt.Time) { + startReading = &reading + } + } + } + } + if startReading == nil { + return nil, errors.New("无法确定表计 " + meterId + " 的计量的起始读数") + } + return startReading, nil +} + +// 确定指定表计的终止读书 +func determineTenementMeterEndReading(meterId string, periodEnd time.Time, + TenementMovedOutAt time.Time, meterRelation model.TenementMeter, + currentTermReadings []model.MeterReading) (*model.MeterReading, error) { + var endTime time.Time + timeList := []time.Time{ + periodEnd, + TenementMovedOutAt, + ShiftToAsiaShanghai(meterRelation.DisassociatedAt.Time), + } + for _, t := range timeList { + if t.After(endTime) { + endTime = t + } + } + if endTime.IsZero() { + return nil, fmt.Errorf("无法确定表计 %s 的计量的结束时间", meterId) + } + + var endReading *model.MeterReading + + for _, reading := range currentTermReadings { + readingAt := ShiftToAsiaShanghai(reading.ReadAt.Time) + if reading.Meter == meterId && readingAt.Before(endTime) { + if endReading == nil || readingAt.After(ShiftToAsiaShanghai(endReading.ReadAt.Time)) { + endReading = &reading + } + } + } + if endReading == nil { + return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的结束读数", meterId)) + } + return endReading, nil +} + +func ShiftToAsiaShanghai(t time.Time) time.Time { + location, _ := time.LoadLocation("Asia/Shanghai") + return t.In(location) +} diff --git a/service/calculate/utils.go b/service/calculate/utils.go new file mode 100644 index 0000000..801a5c7 --- /dev/null +++ b/service/calculate/utils.go @@ -0,0 +1,141 @@ +package calculate + +import ( + "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" + "errors" + "fmt" + "github.com/shopspring/decimal" +) + +// 计算两个读书之间的有功(总)电量 +func ComputeOverall(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) { + start := startReading.Overall.InexactFloat64() * startReading.Ratio.InexactFloat64() + end := endReading.Overall.InexactFloat64() * endReading.Ratio.InexactFloat64() + + if start > end { + return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("表计 {%s} 有功(总)开始读数 {%x} 大于结束读数 {%x}", startReading.Meter, start, end)) + } + + amount := end - start + + var summaryAmount float64 + if summary.Overall.Amount == decimal.Zero { + summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64() + } else { + summaryAmount = summary.Overall.Amount.InexactFloat64() + } + + return model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(amount), + Fee: decimal.NewFromFloat(amount * summary.Overall.Price.InexactFloat64()), + Price: decimal.NewFromFloat(summary.Overall.Price.InexactFloat64()), + Proportion: decimal.NewFromFloat(amount / summaryAmount), + }, nil +} + +//计算两个读书之间的尖峰电量 +func ComputeCritical(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) { + start := startReading.Critical.InexactFloat64() * startReading.Ratio.InexactFloat64() + end := endReading.Critical.InexactFloat64() * endReading.Ratio.InexactFloat64() + + if start > end { + return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("尖峰开始读数 {%x} 大于结束读数 {%x}", start, end)) + } + + amount := end - start + var summaryAmount float64 + + if summary.Critical.Amount.Equal(decimal.Zero) { + summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64() + } else { + summaryAmount = summary.Critical.Amount.InexactFloat64() + } + + return model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(amount), + Fee: decimal.NewFromFloat(amount * summary.Critical.Amount.InexactFloat64()), + Price: decimal.NewFromFloat(summary.Critical.Price.InexactFloat64()), + Proportion: decimal.NewFromFloat(amount / summaryAmount), + }, nil +} + +// 计算两个读数之间的峰电量 +func ComputePeak(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) { + start := startReading.Peak.InexactFloat64() * startReading.Ratio.InexactFloat64() + end := startReading.Peak.InexactFloat64() * endReading.Ratio.InexactFloat64() + + if start > end { + return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("峰开始读数 {%x} 大于结束读数 {%x}", start, end)) + } + + amount := end - start + var summaryAmount float64 + + if summary.Peak.Amount.Equal(decimal.Zero) { + summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64() + } else { + summaryAmount = summary.Peak.Amount.InexactFloat64() + } + + return model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(amount), + Fee: decimal.NewFromFloat(amount * summary.Peak.Price.InexactFloat64()), + Price: decimal.NewFromFloat(summary.Peak.Price.InexactFloat64()), + Proportion: decimal.NewFromFloat(amount / summaryAmount), + }, nil + +} + +//计算两个读数之间的平电量 +func ComputeFlat(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) { + start := startReading.Flat.InexactFloat64() * startReading.Ratio.InexactFloat64() + end := endReading.Flat.InexactFloat64() * endReading.Ratio.InexactFloat64() + + if start > end { + return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("平开始读数 {%x} 大于结束读数 {%x}", start, end)) + } + + amount := end - start + var summaryAmount float64 + + if summary.Flat.Amount.Equal(decimal.Zero) { + summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64() + } else { + summaryAmount = summary.Flat.Amount.InexactFloat64() + } + + return model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(amount), + Fee: decimal.NewFromFloat(amount * summary.Flat.Price.InexactFloat64()), + Price: decimal.NewFromFloat(summary.Flat.Price.InexactFloat64()), + Proportion: decimal.NewFromFloat(amount / summaryAmount), + }, nil +} + +//计算两个读数之间的谷电量 +func ComputeValley(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) { + start := startReading.Valley.InexactFloat64() * startReading.Ratio.InexactFloat64() + end := endReading.Valley.InexactFloat64() * endReading.Ratio.InexactFloat64() + + if start > end { + return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("谷开始读数 {%x} 大于结束读数 {%x}", start, end)) + } + + amount := end - start + + var summaryAmount float64 + + if summary.Valley.Amount.Equal(decimal.Zero) { + summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64() + } else { + summaryAmount = summary.Valley.Amount.InexactFloat64() + } + + return model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(amount), + Fee: decimal.NewFromFloat(amount * summary.Valley.Price.InexactFloat64()), + Price: decimal.NewFromFloat(summary.Valley.Price.InexactFloat64()), + Proportion: decimal.NewFromFloat(amount / summaryAmount), + }, nil +} diff --git a/service/calculate/wattCost.go b/service/calculate/wattCost.go new file mode 100644 index 0000000..5d2956e --- /dev/null +++ b/service/calculate/wattCost.go @@ -0,0 +1,66 @@ +package calculate + +import ( + "electricity_bill_calc/model/calculate" + "electricity_bill_calc/repository" + "fmt" +) + +func MainCalculateProcess(rid string) { + report, err := repository.ReportRepository.GetReportIndex(rid) + if err != nil { + fmt.Println("1", err.Error()+"指定报表不存在") + return + } + + reportSummary, err := repository.ReportRepository.RetrieveReportSummary(rid) + if err != nil { + fmt.Println("2", err.Error()+"指定报表的基本电量电费数据不存在") + return + } + + summary := calculate.FromReportSummary(reportSummary, report) + + periodStart := report.Period.SafeLower() + periodEnd := report.Period.SafeUpper() + + meterDetails, err := repository.MeterRepository.AllUsedMetersInReport(report.Id) + if err != nil { + fmt.Println("3", err) + return + } + + meterRelations, err := repository.CalculateRepository.GetAllPoolingMeterRelations(report.Park, periodStart.Time) + if err != nil { + fmt.Println("4", err) + return + } + _, err = CheckMeterArea(report, meterDetails) + if err != nil { + fmt.Println("5", err) + return + } + + // 寻找每一个商户的所有表计读数,然后对分配到各个商户的表计读数进行初步的计算. + tenementReports, err := TenementMetersCalculate(report, periodStart.Time, periodEnd.Time, meterDetails, summary) + if err != nil { + fmt.Println("6", err) + return + } + + //取得所有公摊表计的读数,以及公摊表计对应的分摊表计 + poolingMetersReports, err := PooledMetersCalculate(report, periodStart.Time, periodEnd.Time, meterDetails, summary) + if err != nil { + fmt.Println("7", err) + return + } + + parkMetersReports, err := MetersParkCalculate(*report, periodStart.Time, periodEnd.Time, meterDetails, summary) + if err != nil { + fmt.Println("8", err) + return + } + + fmt.Println(meterRelations, tenementReports, poolingMetersReports, parkMetersReports) + +} diff --git a/tools/utils.go b/tools/utils.go index af61a41..325453f 100644 --- a/tools/utils.go +++ b/tools/utils.go @@ -160,7 +160,6 @@ func NullTime2PointerString(nullTime sql.NullTime) *string { } } - //该方法用于将时间解析为字符串指针 func TimeToStringPtr(t *time.Time) *string { if t == nil { From 8fc463bd9d53487d314bb9f2a69eda18cbeb407f Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Thu, 3 Aug 2023 17:30:00 +0800 Subject: [PATCH 21/24] =?UTF-8?q?[=E8=AE=A1=E7=AE=97=E7=9B=B8=E5=85=B3]?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E6=89=80=E6=9C=89=E8=A1=A8=E8=AE=A1=E7=9A=84?= =?UTF-8?q?=E6=80=BB=E7=94=B5=E9=87=8F(=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/calculate/summary.go | 38 +++++++++++++++++++++++++++++++++++ service/calculate/tenement.go | 28 ++++---------------------- service/calculate/wattCost.go | 6 +++++- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/service/calculate/summary.go b/service/calculate/summary.go index 8b0bbf7..50bd708 100644 --- a/service/calculate/summary.go +++ b/service/calculate/summary.go @@ -1 +1,39 @@ package calculate + +import ( + "electricity_bill_calc/model/calculate" + "github.com/shopspring/decimal" +) + +// 计算已经启用的商铺面积和 +func TotalConsumptionCalculate(tenements []calculate.PrimaryTenementStatistics, + summary calculate.Summary) decimal.Decimal { + var areaMaters []calculate.Meter + for _, t := range tenements { + areaMaters = append(areaMaters, t.Meters...) + } + + areaMaters = removeDuplicates(areaMaters) + + var areaTotal float64 + for _, m := range areaMaters { + areaTotal += m.Detail.Area.Decimal.InexactFloat64() + } + + areaTotal += summary.OverallArea.InexactFloat64() + + return decimal.NewFromFloat(areaTotal) + +} + +func removeDuplicates(meters []calculate.Meter) []calculate.Meter { + result := make([]calculate.Meter, 0, len(meters)) + seen := make(map[string]bool) + for _, meter := range meters { + if !seen[meter.Code] { + seen[meter.Code] = true + result = append(result, meter) + } + } + return result +} diff --git a/service/calculate/tenement.go b/service/calculate/tenement.go index ca82dad..1749140 100644 --- a/service/calculate/tenement.go +++ b/service/calculate/tenement.go @@ -15,7 +15,7 @@ import ( // 核算园区中的全部商户表计电量用电 func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, PeriodEnd time.Time, meterDetails []*model.MeterDetail, - summary calculate.Summary) ([]model.TenementMeter, error) { + summary calculate.Summary) ([]calculate.PrimaryTenementStatistics, error) { tenements, err := repository.CalculateRepository.GetAllTenements(report.Id) if err != nil { fmt.Println("tenement 0", err) @@ -40,7 +40,7 @@ func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, return nil, err } - var tenementReports []model.Tenement + var tenementReports []calculate.PrimaryTenementStatistics for _, tenement := range tenements { var meters []model.TenementMeter @@ -65,30 +65,10 @@ func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, return nil, err } - report := model.Tenement{ - Id: pt.Tenement.Id, - Park: pt.Tenement.Park, - FullName: pt.Tenement.FullName, - ShortName: pt.Tenement.ShortName, - Abbr: pt.Tenement.Abbr, - Address: pt.Tenement.Address, - ContactName: pt.Tenement.ContactName, - ContactPhone: pt.Tenement.ContactPhone, - Building: pt.Tenement.Building, - BuildingName: pt.Tenement.BuildingName, - OnFloor: pt.Tenement.OnFloor, - InvoiceInfo: pt.Tenement.InvoiceInfo, - MovedInAt: pt.Tenement.MovedInAt, - MovedOutAt: pt.Tenement.MovedOutAt, - CreatedAt: pt.Tenement.CreatedAt, - LastModifiedAt: pt.Tenement.LastModifiedAt, - DeletedAt: pt.Tenement.DeletedAt, - } - - tenementReports = append(tenementReports, report) + tenementReports = append(tenementReports, pt) } - return tenementMeterRelations, nil + return tenementReports, nil } //TODO: 2023.08.02 此方法未完成此方法主要用于。确定指定商户在指定时间段内的所有表计读数(完成) diff --git a/service/calculate/wattCost.go b/service/calculate/wattCost.go index 5d2956e..f9556f1 100644 --- a/service/calculate/wattCost.go +++ b/service/calculate/wattCost.go @@ -55,12 +55,16 @@ func MainCalculateProcess(rid string) { return } + // 获取所有的物业表计,然后对所有的物业表计电量进行计算。 parkMetersReports, err := MetersParkCalculate(*report, periodStart.Time, periodEnd.Time, meterDetails, summary) if err != nil { fmt.Println("8", err) return } - fmt.Println(meterRelations, tenementReports, poolingMetersReports, parkMetersReports) + //计算所有表计的总电量 + parkTotal := TotalConsumptionCalculate(tenementReports, summary) + + fmt.Println(meterRelations, poolingMetersReports, parkMetersReports, parkTotal) } From 6b3d3dd93c249d2dcf8eda57430d2301d05503fe Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 4 Aug 2023 09:39:59 +0800 Subject: [PATCH 22/24] =?UTF-8?q?[=E8=AE=A1=E7=AE=97=E7=9B=B8=E5=85=B3]?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E7=BA=BF=E6=8D=9F=E4=BB=A5=E5=8F=8A=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E7=BA=BF=E6=8D=9F=EF=BC=88=E5=AE=8C=E6=88=90=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/report.go | 40 +++++++++++++++------------- service/calculate/summary.go | 50 +++++++++++++++++++++++++++++++++++ service/calculate/wattCost.go | 6 +++++ 3 files changed, 77 insertions(+), 19 deletions(-) diff --git a/model/report.go b/model/report.go index 2972647..1d7d207 100644 --- a/model/report.go +++ b/model/report.go @@ -7,25 +7,27 @@ import ( ) type ReportIndex struct { - Id string `json:"id"` - Park string `json:"parkId" db:"park_id"` - Period types.DateRange `json:"period"` - Category int16 `json:"category"` - MeterType int16 `json:"meter04kvType" db:"meter_04kv_type"` - PricePolicy int16 `json:"pricePolicy"` - BasisPooled int16 `json:"basisPooled"` - AdjustPooled int16 `json:"adjustPooled"` - LossPooled int16 `json:"lossPooled"` - PublicPooled int16 `json:"publicPooled"` - Published bool `json:"published"` - PublishedAt *types.DateTime `json:"publishedAt" db:"published_at"` - Withdraw int16 `json:"withdraw"` - LastWithdrawAppliedAt *types.DateTime `json:"lastWithdrawAppliedAt" db:"last_withdraw_applied_at"` - LastWithdrawAuditAt *types.DateTime `json:"lastWithdrawAuditAt" db:"last_withdraw_audit_at"` - Status *int16 `json:"status"` - Message *string `json:"message"` - CreatedAt types.DateTime `json:"createdAt" db:"created_at"` - LastModifiedAt types.DateTime `json:"lastModifiedAt" db:"last_modified_at"` + Id string `json:"id"` + Park string `json:"parkId" db:"park_id"` + Period types.DateRange `json:"period"` + Category int16 `json:"category"` + MeterType int16 `json:"meter04kvType" db:"meter_04kv_type"` + PricePolicy int16 `json:"pricePolicy"` + BasisPooled int16 `json:"basisPooled"` + AdjustPooled int16 `json:"adjustPooled"` + LossPooled int16 `json:"lossPooled"` + PublicPooled int16 `json:"publicPooled"` + Published bool `json:"published"` + PublishedAt *types.DateTime `json:"publishedAt" db:"published_at"` + Withdraw int16 `json:"withdraw"` + LastWithdrawAppliedAt *types.DateTime `json:"lastWithdrawAppliedAt" db:"last_withdraw_applied_at"` + LastWithdrawAuditAt *types.DateTime `json:"lastWithdrawAuditAt" db:"last_withdraw_audit_at"` + Status *int16 `json:"status"` + Message *string `json:"message"` + CreatedAt types.DateTime `json:"createdAt" db:"created_at"` + LastModifiedAt types.DateTime `json:"lastModifiedAt" db:"last_modified_at"` + AuthorizedLossRate float64 `json:"authorized_loss_rate" db:"authorized_loss_rate"` + AuthorizedLossRateIncrement float64 `json:"authorized_loss_rate_increment" db:"authorized_loss_rate_increment"` } type ReportSummary struct { diff --git a/service/calculate/summary.go b/service/calculate/summary.go index 50bd708..85f22ea 100644 --- a/service/calculate/summary.go +++ b/service/calculate/summary.go @@ -1,7 +1,10 @@ package calculate import ( + "electricity_bill_calc/model" "electricity_bill_calc/model/calculate" + "errors" + "fmt" "github.com/shopspring/decimal" ) @@ -37,3 +40,50 @@ func removeDuplicates(meters []calculate.Meter) []calculate.Meter { } return result } + +//计算线损以及调整线损 +func LossCalculate(report *model.ReportIndex, Public []calculate.Meter, + publicTotal decimal.Decimal, summary calculate.Summary) error { + summary.Loss = summary.Overall.Amount.Sub(summary.TotalConsumption) + + var summaryAmount decimal.Decimal + if summary.Overall.Amount == decimal.Zero { + summaryAmount = decimal.NewFromFloat(1.0) + } else { + summaryAmount = summary.Overall.Amount + } + + summary.LossProportion = summary.Loss.Div(summaryAmount) + + var authorizedLossRate decimal.Decimal + if summary.LossProportion.InexactFloat64() > report.AuthorizedLossRate { + authorizedLossRate = summary.LossProportion + } else { + return errors.New(fmt.Sprintf("经过核算园区的线损率为:{%.8f}, 核定线损率为:{%.8f}", summary.LossProportion.InexactFloat64(),authorizedLossRate.InexactFloat64())) + } + + summary.AuthoizeLoss = model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(summary.Overall.Amount.InexactFloat64() * authorizedLossRate.InexactFloat64()), + Fee: decimal.NewFromFloat((summary.Overall.Amount.InexactFloat64() * authorizedLossRate.InexactFloat64()) * summary.Overall.Price.InexactFloat64()), + Price: summary.Overall.Price, + Proportion: authorizedLossRate, + } + + differentialLoss := summary.LossDilutedPrice.Sub(summary.AuthoizeLoss.Amount) + + if publicTotal.InexactFloat64() <= decimal.Zero.InexactFloat64() { + return errors.New("园区公共表计的电量总和为非正值,或者园区未设置公共表计,无法计算核定线损") + } + + for _, meter := range Public { + amountProportion := meter.Overall.Amount.InexactFloat64() / publicTotal.InexactFloat64() + adjustAmount := differentialLoss.InexactFloat64() * decimal.NewFromFloat(-1.0).InexactFloat64() + meter.AdjustLoss = model.ConsumptionUnit{ + Amount: decimal.NewFromFloat(adjustAmount), + Fee: decimal.NewFromFloat(adjustAmount * summary.LossDilutedPrice.InexactFloat64()), + Price: summary.LossDilutedPrice, + Proportion: decimal.NewFromFloat(amountProportion), + } + } + return nil +} diff --git a/service/calculate/wattCost.go b/service/calculate/wattCost.go index f9556f1..f7ff373 100644 --- a/service/calculate/wattCost.go +++ b/service/calculate/wattCost.go @@ -65,6 +65,12 @@ func MainCalculateProcess(rid string) { //计算所有表计的总电量 parkTotal := TotalConsumptionCalculate(tenementReports, summary) + err = LossCalculate(report, parkMetersReports, parkTotal, summary) + if err != nil { + fmt.Println("9", err) + return + } + fmt.Println(meterRelations, poolingMetersReports, parkMetersReports, parkTotal) } From 5710a640e8bd0dd149134d96bd0e97401ae8d24c Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 4 Aug 2023 10:05:27 +0800 Subject: [PATCH 23/24] =?UTF-8?q?[=E8=AE=A1=E7=AE=97=E7=9B=B8=E5=85=B3]fix?= =?UTF-8?q?=20=E8=AE=A1=E7=AE=97=E7=BA=BF=E6=8D=9F=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E7=BA=BF=E6=8D=9F=E5=8F=82=E6=95=B0=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E3=80=82new=20=E8=AE=A1=E7=AE=97=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=B7=B2=E7=BB=8F=E5=90=AF=E7=94=A8=E7=9A=84=E5=95=86=E9=93=BA?= =?UTF-8?q?=E9=9D=A2=E7=A7=AF=E6=80=BB=E5=92=8C=EF=BC=8C=E4=BB=85=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E6=89=80=E6=9C=89=E6=9C=AA=E8=BF=81=E5=87=BA=E7=9A=84?= =?UTF-8?q?=E5=95=86=E6=88=B7=E7=9A=84=E6=89=80=E6=9C=89=E8=A1=A8=E8=AE=A1?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=9A=84=E5=95=86=E9=93=BA=E9=9D=A2=E7=A7=AF?= =?UTF-8?q?=E3=80=82(=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/calculate/summary.go | 32 ++++++++++++++++++++++++++++---- service/calculate/wattCost.go | 9 ++++++++- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/service/calculate/summary.go b/service/calculate/summary.go index 85f22ea..26d5620 100644 --- a/service/calculate/summary.go +++ b/service/calculate/summary.go @@ -42,8 +42,8 @@ func removeDuplicates(meters []calculate.Meter) []calculate.Meter { } //计算线损以及调整线损 -func LossCalculate(report *model.ReportIndex, Public []calculate.Meter, - publicTotal decimal.Decimal, summary calculate.Summary) error { +func LossCalculate(report *model.ReportIndex, Public *[]calculate.Meter, + publicTotal *decimal.Decimal, summary *calculate.Summary) error { summary.Loss = summary.Overall.Amount.Sub(summary.TotalConsumption) var summaryAmount decimal.Decimal @@ -56,10 +56,11 @@ func LossCalculate(report *model.ReportIndex, Public []calculate.Meter, summary.LossProportion = summary.Loss.Div(summaryAmount) var authorizedLossRate decimal.Decimal + //TODO: 2023.08.04 在此发现reportIndex结构体与数据库中的report表字段不对应缺少两个相应字段,在此添加的,如在其他地方有错误优先查找这里 if summary.LossProportion.InexactFloat64() > report.AuthorizedLossRate { authorizedLossRate = summary.LossProportion } else { - return errors.New(fmt.Sprintf("经过核算园区的线损率为:{%.8f}, 核定线损率为:{%.8f}", summary.LossProportion.InexactFloat64(),authorizedLossRate.InexactFloat64())) + return errors.New(fmt.Sprintf("经过核算园区的线损率为:{%.8f}, 核定线损率为:{%.8f}", summary.LossProportion.InexactFloat64(), authorizedLossRate.InexactFloat64())) } summary.AuthoizeLoss = model.ConsumptionUnit{ @@ -75,7 +76,7 @@ func LossCalculate(report *model.ReportIndex, Public []calculate.Meter, return errors.New("园区公共表计的电量总和为非正值,或者园区未设置公共表计,无法计算核定线损") } - for _, meter := range Public { + for _, meter := range *Public { amountProportion := meter.Overall.Amount.InexactFloat64() / publicTotal.InexactFloat64() adjustAmount := differentialLoss.InexactFloat64() * decimal.NewFromFloat(-1.0).InexactFloat64() meter.AdjustLoss = model.ConsumptionUnit{ @@ -87,3 +88,26 @@ func LossCalculate(report *model.ReportIndex, Public []calculate.Meter, } return nil } + +// 计算已经启用的商铺面积和 +func EnabledAreaCalculate(tenements *[]calculate.PrimaryTenementStatistics, summary *calculate.Summary) error { + var areaMeters []calculate.Meter + for _, t := range *tenements { + areaMeters = append(areaMeters, t.Meters...) + } + // 去重 + uniqueAreaMeters := make(map[string]calculate.Meter) + for _, meter := range areaMeters { + uniqueAreaMeters[meter.Code] = meter + } + var areaTotal decimal.Decimal + for _, meter := range uniqueAreaMeters { + areaTotal = areaTotal.Add(meter.Detail.Area.Decimal) + } + if summary != nil { + summary.OverallArea = areaTotal + } else { + return errors.New("summary is nil") + } + return nil +} diff --git a/service/calculate/wattCost.go b/service/calculate/wattCost.go index f7ff373..6fe261b 100644 --- a/service/calculate/wattCost.go +++ b/service/calculate/wattCost.go @@ -65,12 +65,19 @@ func MainCalculateProcess(rid string) { //计算所有表计的总电量 parkTotal := TotalConsumptionCalculate(tenementReports, summary) - err = LossCalculate(report, parkMetersReports, parkTotal, summary) + // 计算线损以及调整线损 + err = LossCalculate(report, &parkMetersReports, &parkTotal, &summary) if err != nil { fmt.Println("9", err) return } + err = EnabledAreaCalculate(&tenementReports, &summary) + if err != nil{ + fmt.Println("10",err) + return + } + fmt.Println(meterRelations, poolingMetersReports, parkMetersReports, parkTotal) } From c916301f6bb7d6ffe0b002b064ce7c2c027bb7d0 Mon Sep 17 00:00:00 2001 From: ZiHangQin <1420014281@qq.com> Date: Fri, 4 Aug 2023 10:24:09 +0800 Subject: [PATCH 24/24] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/calculate/wattCost.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service/calculate/wattCost.go b/service/calculate/wattCost.go index 6fe261b..fe14ba6 100644 --- a/service/calculate/wattCost.go +++ b/service/calculate/wattCost.go @@ -48,7 +48,7 @@ func MainCalculateProcess(rid string) { return } - //取得所有公摊表计的读数,以及公摊表计对应的分摊表计 + // 取得所有公摊表计的读数,以及公摊表计对应的分摊表计 poolingMetersReports, err := PooledMetersCalculate(report, periodStart.Time, periodEnd.Time, meterDetails, summary) if err != nil { fmt.Println("7", err) @@ -62,7 +62,7 @@ func MainCalculateProcess(rid string) { return } - //计算所有表计的总电量 + // 计算所有表计的总电量 parkTotal := TotalConsumptionCalculate(tenementReports, summary) // 计算线损以及调整线损 @@ -72,6 +72,7 @@ func MainCalculateProcess(rid string) { return } + // 计算所有已经启用的商铺面积总和,仅计算所有未迁出的商户的所有表计对应的商铺面积。 err = EnabledAreaCalculate(&tenementReports, &summary) if err != nil{ fmt.Println("10",err)