diff --git a/.idea/0.2.iml b/.idea/0.2.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/0.2.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 95c0f54..92189f3 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/_1.gitignore b/_1.gitignore new file mode 100644 index 0000000..45e75ee --- /dev/null +++ b/_1.gitignore @@ -0,0 +1,183 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +# Block sensitive configuration files +settings.local.yaml +log/ +__debug_bin diff --git a/config/settings.go b/config/settings.go index b009064..db3566c 100644 --- a/config/settings.go +++ b/config/settings.go @@ -36,7 +36,7 @@ type ServiceSetting struct { HostSerial int64 } -//读取基准线损率 +// 读取基准线损率 type BaseLossSetting struct { Base string } diff --git a/controller/report.go b/controller/report.go index b79efe5..6d70c44 100644 --- a/controller/report.go +++ b/controller/report.go @@ -23,6 +23,7 @@ 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) diff --git a/controller/sync.go b/controller/sync.go new file mode 100644 index 0000000..dd95206 --- /dev/null +++ b/controller/sync.go @@ -0,0 +1,121 @@ +package controller + +import ( + "electricity_bill_calc/logger" + "electricity_bill_calc/model" + "electricity_bill_calc/repository" + "electricity_bill_calc/response" + "electricity_bill_calc/security" + "electricity_bill_calc/service" + "electricity_bill_calc/tools" + "electricity_bill_calc/vo" + "fmt" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" +) + +var synchronizeLog = logger.Named("Handler", "Synchronize") + +func InitializeSynchronizeHandlers(router *fiber.App) { + router.Get("/synchronize/task", security.EnterpriseAuthorize, searchSynchronizeSchedules) + router.Get("/synchronize/configuration", security.EnterpriseAuthorize, getSynchronizeConfiguration) + router.Post("/synchronize/configuration", security.EnterpriseAuthorize, recordsynchronizeConfiguration) +} + +// 查询当前平台中符合查询条件的同步任务,企业用户无论传入什么用户ID条件,都仅能看到自己的同步任务 +func searchSynchronizeSchedules(c *fiber.Ctx) error { + result := response.NewResult(c) + session, err := _retreiveSession(c) + if err != nil { + synchronizeLog.Error("查询同步任务失败,未能获取当前用户会话信息", zap.Error(err)) + return result.Unauthorized("未能获取当前用户会话信息。") + } + parkId := tools.EmptyToNil(c.Params("park")) + if parkId != nil && len(*parkId) > 0 { + if pass, err := checkParkBelongs(*parkId, reportLog, c, &result); !pass { + return err + } + } + userId := tools.EmptyToNil(c.Params("user")) + keyword := tools.EmptyToNil(c.Query("keyword")) + page := c.QueryInt("page", 1) + synchronizeLog.Info("查询当前平台中符合查询条件的同步任务。", zap.String("Ent", session.Uid), zap.Stringp("Park", parkId)) + schedules, total, err := repository.SynchronizeRepository.SearchSynchronizeSchedules(userId, parkId, uint(page), keyword) + if err != nil { + reportLog.Error("无法获取同步任务", zap.Error(err)) + return result.Error(fiber.StatusInternalServerError, "无法获取同步任务") + } + return result.Success( + " ", + response.NewPagedResponse(page, total).ToMap(), + fiber.Map{"tasks": schedules}, + ) +} + +// 获取指定的同步任务配置 +func getSynchronizeConfiguration(c *fiber.Ctx) error { + result := response.NewResult(c) + parkId := c.Query("park") + userId := c.Query("user") + session, err := _retreiveSession(c) + if err != nil { + reportLog.Error("无法获取当前用户的会话信息", zap.Error(err)) + return result.Unauthorized("无法获取当前用户的会话信息。") + } + var user_id string + if session.Type == model.USER_TYPE_ENT { + user_id = session.Uid + } else { + if userId != "" { + user_id = userId + } else { + return result.NotAccept(fmt.Sprintf("必须指定要记录同步任务的用户,%s", err.Error())) + } + } + fmt.Println("pppppppppppppppppppppppppppp", parkId, len(parkId)) + if parkId == "" { + return result.NotAccept("必须指定要获取同步任务的园区。") + } + + fmt.Printf(user_id) + configurations, err := repository.SynchronizeRepository.RetrieveSynchronizeConfiguration(user_id, parkId) + if err != nil { + reportLog.Error("无法获取同步任务", zap.Error(err)) + return result.Error(fiber.StatusInternalServerError, "无法获取同步任务") + } + return result.Success( + " 123", + fiber.Map{"setup": configurations}, + ) +} +func recordsynchronizeConfiguration(c *fiber.Ctx) error { + userId := c.Query("user") + synchronizeLog.Info("记录一个新的同步任务配置", zap.String("user id", userId)) + session, err := _retreiveSession(c) + result := response.NewResult(c) + if err != nil { + reportLog.Error("无法获取当前用户的会话信息", zap.Error(err)) + return result.Unauthorized("无法获取当前用户的会话信息。") + } + var Form vo.SynchronizeConfigurationCreateForm + if err := c.BodyParser(&Form); err != nil { + meterLog.Error("无法更新同步配置,无法解析表计更新表单", zap.Error(err)) + return result.NotAccept(err.Error()) + } + var user_id string + if session.Type == model.USER_TYPE_ENT { + user_id = session.Uid + } else { + if userId != "" { + user_id = userId + } else { + return result.NotAccept(fmt.Sprintf("必须指定更新同步任务的用户,%s", err.Error())) + } + } + //configurations, err := repository.SynchronizeRepository.CreateSynchronizeConfiguration + if err := service.SynchronizeService.CreateSynchronizeConfiguration(user_id, &Form); err != nil { + synchronizeLog.Error("无法更新同步配置", zap.Error(err)) + return result.NotAccept(err.Error()) + } + return result.Success("更新完成。") +} diff --git a/controller/tenement.go b/controller/tenement.go index 0e1c98b..077cf53 100644 --- a/controller/tenement.go +++ b/controller/tenement.go @@ -25,6 +25,9 @@ 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) + 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/move/out", security.EnterpriseAuthorize, moveOutTenement) router.Post("/tenement/:pid", security.EnterpriseAuthorize, addTenement) diff --git a/controller/user.go b/controller/user.go index 7240728..e3bd2c3 100644 --- a/controller/user.go +++ b/controller/user.go @@ -18,8 +18,6 @@ import ( "go.uber.org/zap" ) -var userLog = logger.Named("Handler", "User") - func InitializeUserHandlers(router *fiber.App) { router.Delete("/login", security.MustAuthenticated, doLogout) router.Post("/login", doLogin) @@ -35,6 +33,8 @@ func InitializeUserHandlers(router *fiber.App) { router.Delete("/password/:uid", security.OPSAuthorize, invalidUserPassword) } +var userLog = logger.Named("Handler", "User") + type _LoginForm struct { Username string `json:"uname"` Password string `json:"upass"` @@ -42,37 +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 { //解析请求体中的Json数据到loginData里,如果解析出错就返回错误 + result := response.NewResult(c) + loginData := new(_LoginForm) + if err := c.BodyParser(loginData); err != nil { 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 { - userLog.Info("该用户是管理用户") - session, err = service.UserService.ProcessManagementUserLogin(loginData.Username, loginData.Password) //管理用户 + 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 { result := response.NewResult(c) session, err := _retreiveSession(c) diff --git a/controller/withdraw.go b/controller/withdraw.go index f9d6695..6a41d72 100644 --- a/controller/withdraw.go +++ b/controller/withdraw.go @@ -2,6 +2,7 @@ package controller import ( "electricity_bill_calc/logger" + "electricity_bill_calc/repository" "electricity_bill_calc/response" "electricity_bill_calc/security" @@ -19,7 +20,7 @@ func InitializeWithdrawHandlers(router *fiber.App) { router.Delete("/withdraw/:rid", security.EnterpriseAuthorize, recallReport) } -//用于分页检索用户的核算报表 +// 用于分页检索用户的核算报表 func withdraw(c *fiber.Ctx) error { //记录日志 withdrawLog.Info("带分页的待审核的核算撤回申请列表") @@ -43,7 +44,7 @@ func withdraw(c *fiber.Ctx) error { ) } -//用于审核撤回报表 +// 用于审核撤回报表 func reviewRequestWithdraw(c *fiber.Ctx) error { Rid := c.Params("rid", "") Data := new(vo.ReviewWithdraw) @@ -84,7 +85,7 @@ func reviewRequestWithdraw(c *fiber.Ctx) error { } -//用于撤回电费核算 +// 用于撤回电费核算 func recallReport(c *fiber.Ctx) error { // 获取用户会话信息和参数 rid := c.Params("rid", "") diff --git a/excel/tenement.go b/excel/tenement.go new file mode 100644 index 0000000..25137b8 --- /dev/null +++ b/excel/tenement.go @@ -0,0 +1,22 @@ +package excel + +var tenementRecognizers = []*ColumnRecognizer{ + {Pattern: [][]string{{"商户全称"}}, Tag: "fullName", MatchIndex: -1}, + {Pattern: [][]string{{"联系地址"}}, Tag: "address", MatchIndex: -1}, + {Pattern: [][]string{{"入驻时间"}}, Tag: "movedInAt", MatchIndex: -1}, + {Pattern: [][]string{{"商铺名称"}}, Tag: "shortName", MatchIndex: -1}, + {Pattern: [][]string{{"联系人"}}, Tag: "contactName", MatchIndex: -1}, + {Pattern: [][]string{{"电话"}}, Tag: "contactPhone", MatchIndex: -1}, + {Pattern: [][]string{{"USCI"}}, Tag: "usci", MatchIndex: -1}, + {Pattern: [][]string{{"开票地址"}}, Tag: "invoiceAddress", MatchIndex: -1}, + {Pattern: [][]string{{"账号"}}, Tag: "account", MatchIndex: -1}, + {Pattern: [][]string{{"开户行"}}, Tag: "bank", MatchIndex: -1}, +} + +//func NewTenementExcelAnalyzer(file io.Reader) (*ExcelAnalyzer[model.TenementImportRow], error) { +// return NewExcelAnalyzer[model.TenementImportRow](file, tenementRecognizers) +//} + +//func NewMeterArchiveExcelAnalyzer(file io.Reader) (*ExcelAnalyzer[model.MeterImportRow], error) { +// return NewExcelAnalyzer[model.MeterImportRow](file, meterArchiveRecognizers) +//} diff --git a/global/db.go b/global/db.go index a19c5f4..0c77ff3 100644 --- a/global/db.go +++ b/global/db.go @@ -53,9 +53,7 @@ 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 8afb039..d28d8a9 100644 --- a/global/redis.go +++ b/global/redis.go @@ -18,10 +18,9 @@ func SetupRedisConnection() error { a := fmt.Sprintf("%s:%d", config.RedisSettings.Host, config.RedisSettings.Port) fmt.Println(a) Rd, err = rueidis.NewClient(rueidis.ClientOption{ - InitAddress: []string{"127.0.0.1:6379"}, - Password: "", + InitAddress: []string{fmt.Sprintf("%s:%d", config.RedisSettings.Host, config.RedisSettings.Port)}, + Password: config.RedisSettings.Password, SelectDB: config.RedisSettings.DB, - DisableCache:true, }) if err != nil { return err diff --git a/go.mod b/go.mod index 9f93995..efa80f7 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module electricity_bill_calc go 1.19 require ( - github.com/deckarep/golang-set/v2 v2.1.0 github.com/fufuok/utils v0.10.2 github.com/georgysavva/scany/v2 v2.0.0 github.com/gofiber/fiber/v2 v2.46.0 @@ -27,26 +26,18 @@ require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/puddle/v2 v2.2.0 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect github.com/klauspost/compress v1.16.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect github.com/tinylib/msgp v1.1.8 // indirect - github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect golang.org/x/sync v0.2.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - mellium.im/sasl v0.3.0 // indirect ) require ( @@ -59,7 +50,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect github.com/richardlehane/msoleps v1.0.3 // indirect @@ -68,9 +58,6 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect - github.com/uptrace/bun v1.1.8 - github.com/uptrace/bun/dialect/pgdialect v1.1.8 - github.com/uptrace/bun/driver/pgdriver v1.1.8 github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9 // indirect github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83 // indirect go.uber.org/atomic v1.11.0 // indirect @@ -81,6 +68,5 @@ require ( golang.org/x/sys v0.9.0 // indirect golang.org/x/text v0.10.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 62deb92..ff47fcd 100644 --- a/go.sum +++ b/go.sum @@ -36,12 +36,10 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -53,11 +51,10 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= -github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/doug-martin/goqu/v9 v9.18.0 h1:/6bcuEtAe6nsSMVK/M+fOiXUNfyFF3yYtE07DBPFMYY= github.com/doug-martin/goqu/v9 v9.18.0/go.mod h1:nf0Wc2/hV3gYK9LiyqIrzBEVGlI8qW3GuDCEobC4wBQ= @@ -67,14 +64,9 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/fufuok/utils v0.7.13 h1:FGx8Mnfg0ZB8HdVz1X60JJ2kFu1rtcsFDYUxUTzNKkU= -github.com/fufuok/utils v0.7.13/go.mod h1:ztIaorPqZGdbvmW3YlwQp80K8rKJmEy6xa1KwpJSsmk= github.com/fufuok/utils v0.10.2 h1:jXgE7yBSUW9z+sJs/VQq3o4MH+jN30PzIILVXFw73lE= github.com/fufuok/utils v0.10.2/go.mod h1:87MJq0gAZDYBgUOpxSGoLkdv8VCuRNOL9vK02F7JC3s= github.com/georgysavva/scany/v2 v2.0.0 h1:RGXqxDv4row7/FYoK8MRXAZXqoWF/NM+NP0q50k3DKU= @@ -83,10 +75,9 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/gofiber/fiber/v2 v2.38.1 h1:GEQ/Yt3Wsf2a30iTqtLXlBYJZso0JXPovt/tmj5H9jU= -github.com/gofiber/fiber/v2 v2.38.1/go.mod h1:t0NlbaXzuGH7I+7M4paE848fNWInZ7mfxI/Er1fTth8= github.com/gofiber/fiber/v2 v2.46.0 h1:wkkWotblsGVlLjXj2dpgKQAYHtXumsK/HyFugQM68Ns= github.com/gofiber/fiber/v2 v2.46.0/go.mod h1:DNl0/c37WLe0g92U6lx1VMQuxGUQY5V7EIaVoEsUffc= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -124,7 +115,7 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -162,36 +153,24 @@ github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= -github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= -github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/liamylian/jsontime/v2 v2.0.0 h1:3if2kDW/boymUdO+4Qj/m4uaXMBSF6np9KEgg90cwH0= github.com/liamylian/jsontime/v2 v2.0.0/go.mod h1:UHp1oAPqCBfspokvGmaGe0IAl2IgOpgOgDaKPcvcGGY= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.1 h1:6VXZrLU0jHBYyAqrSPa+MgPfnSvTPuMgK+k0o5kVFWo= github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -201,7 +180,6 @@ github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APP github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -214,20 +192,14 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/mozillazg/go-pinyin v0.19.0 h1:p+J8/kjJ558KPvVGYLvqBhxf8jbZA2exSLCs2uUVN8c= -github.com/mozillazg/go-pinyin v0.19.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ= github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= -github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/onsi/gomega v1.27.5 h1:T/X6I0RNFw/kTqgfkZPcQ5KU6vCnWNBGdtrIx2dpGeQ= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -243,16 +215,9 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rueian/rueidis v0.0.73 h1:+r0Z6C6HMnkquPgY3zaHVpTqmCyJL56Z36GSlyBrufk= -github.com/rueian/rueidis v0.0.73/go.mod h1:FwnfDILF2GETrvXcYFlhIiru/7NmSIm1f+7C5kutO0I= github.com/rueian/rueidis v0.0.100 h1:22yp/+8YHuWc/vcrp8bkjeE7baD3vygoh2gZ2+xu1KQ= github.com/rueian/rueidis v0.0.100/go.mod h1:ivvsRYRtAUcf9OnheuKc5Gpa8IebrkLT1P45Lr2jlXE= -github.com/samber/lo v1.27.0 h1:GOyDWxsblvqYobqsmUuMddPa2/mMzkKyojlXol4+LaQ= -github.com/samber/lo v1.27.0/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4= @@ -262,75 +227,45 @@ github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1Avp github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= -github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= -github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= -github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= -github.com/uptrace/bun v1.1.8 h1:slxuaP4LYWFbPRUmTtQhfJN+6eX/6ar2HDKYTcI50SA= -github.com/uptrace/bun v1.1.8/go.mod h1:iT89ESdV3uMupD9ixt6Khidht+BK0STabK/LeZE+B84= -github.com/uptrace/bun/dialect/pgdialect v1.1.8 h1:wayJhjYDPGv8tgOBLolbBtSFQ0TihFoo8E1T129UdA8= -github.com/uptrace/bun/dialect/pgdialect v1.1.8/go.mod h1:nNbU8PHTjTUM+CRtGmqyBb9zcuRAB8I680/qoFSmBUk= -github.com/uptrace/bun/driver/pgdriver v1.1.8 h1:gyL22axRQfjJS2Umq0erzJnp0bLOdUE8/USKZHPQB8o= -github.com/uptrace/bun/driver/pgdriver v1.1.8/go.mod h1:4tHK0h7a/UoldBoe9J3GU4tEYjr3mkd62U3Kq3PVk3E= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= -github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c= github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= -github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= -github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= -github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 h1:6932x8ltq1w4utjmfMPVj09jdMlkY0aiA6+Skbtl3/c= github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9 h1:ge5g8vsTQclA5lXDi+PuiAFw5GMIlMHOB/5e1hsf96E= github.com/xuri/efp v0.0.0-20230422071738-01f4e37c47e9/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= -github.com/xuri/excelize/v2 v2.6.1 h1:ICBdtw803rmhLN3zfvyEGH3cwSmZv+kde7LhTDT659k= -github.com/xuri/excelize/v2 v2.6.1/go.mod h1:tL+0m6DNwSXj/sILHbQTYsLi9IF4TW59H2EF3Yrx1AU= github.com/xuri/excelize/v2 v2.7.1 h1:gm8q0UCAyaTt3MEF5wWMjVdmthm2EHAWesGSKS9tdVI= github.com/xuri/excelize/v2 v2.7.1/go.mod h1:qc0+2j4TvAUrBw36ATtcTeC1VCM0fFdAXZOmcF4nTpY= -github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 h1:OAmKAfT06//esDdpi/DZ8Qsdt4+M5+ltca05dA5bG2M= github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83 h1:xVwnvkzzi+OiwhIkWOXvh1skFI6bagk8OvGuazM80Rw= github.com/xuri/nfp v0.0.0-20230503010013-3f38cdbb0b83/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= @@ -345,19 +280,11 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= -go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -368,18 +295,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220817201139-bc19a97f63c8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= -golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= @@ -393,14 +309,10 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= -golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 h1:LRtI4W37N+KFebI/qV0OFiLUv4GLOWeEW5hn/KEJvxE= -golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -459,15 +371,9 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= -golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= @@ -491,7 +397,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -530,23 +435,14 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220907062415-87db552b00fd h1:AZeIEzg+8RCELJYq8w+ODLVxFgLMMigSwO/ffKPEd9U= -golang.org/x/sys v0.0.0-20220907062415-87db552b00fd/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -561,13 +457,9 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -720,22 +612,13 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= -gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -745,8 +628,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -mellium.im/sasl v0.3.0 h1:0qoaTCTo5Py7u/g0cBIQZcMOgG/5LM71nshbXwznBh8= -mellium.im/sasl v0.3.0/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/model/calculate/calculate.go b/model/calculate/calculate.go index ff5ebb7..8036402 100644 --- a/model/calculate/calculate.go +++ b/model/calculate/calculate.go @@ -60,6 +60,7 @@ type TenementCharge struct { LossPooled decimal.Decimal PublicPooled decimal.Decimal FinalCharges decimal.Decimal + Loss decimal.Decimal Submeters []*Meter Poolings []*Meter } diff --git a/model/park.go b/model/park.go index b4e3435..a210e83 100644 --- a/model/park.go +++ b/model/park.go @@ -2,6 +2,7 @@ package model import ( "electricity_bill_calc/types" + "time" "github.com/shopspring/decimal" @@ -39,7 +40,7 @@ type Parks struct { } type ParkPeriodStatistics struct { - Id string `json:"id"` - Name string `json:"name"` + Id string `json:"id"` + Name string `json:"name"` Period *types.DateRange } diff --git a/model/synchronize.go b/model/synchronize.go new file mode 100644 index 0000000..a42e5e9 --- /dev/null +++ b/model/synchronize.go @@ -0,0 +1,38 @@ +package model + +import ( + "electricity_bill_calc/types" + _ "github.com/shopspring/decimal" + "time" +) + +type SynchronizeConfiguration struct { + User string `json:"user" db:"user_id"` + Park string `json:"park" db:"park_id"` + MeterReadingType int16 `json:"meter_reading_type"` + ImrsType string `json:"imrs_type"` + AuthorizationAccount string `json:"authorization_account" db:"imrs_authorization_account"` + AuthorizationSecret string `json:"authorization_secret" db:"imrs_authorization_secret"` + AuthorizationKey []byte `json:"authorization_key,omitempty" db:"imrs_authorization_key"` + Interval int16 `json:"interval"` + CollectAt time.Time `json:"collect_at" db:"-"` + MaxRetries int16 `json:"max_retries"` + RetryInterval int16 `json:"retry_interval"` + RetryIntervalAlgorithm int16 `json:"retry_interval_algorithm"` +} + +type SynchronizeSchedule struct { + User string `json:"userId" db:"user_id"` + UserName string `json:"userName" db:"user_name"` + Park string `json:"parkId" db:"park_id"` + ParkName string `json:"parkName" db:"park_name"` + TaskIdentity string `json:"taskIdentity" db:"task_identity"` + TaskName string `json:"taskName" db:"task_name"` + TaskDescription string `json:"taskDescription" db:"task_description"` + CreatedAt types.DateTime `json:"createdAt" db:"created_at"` + LastModifiedAt types.DateTime `json:"lastModifiedAt" db:"last_modified_at"` + LastDispatchedAt types.DateTime `json:"lastDispatchedAt" db:"last_dispatched_at"` + LastDispatchStatus int16 `json:"lastDispatchStatus" db:"last_dispatch_status"` + NextDispatchAt types.DateTime `json:"nextDispatchAt" db:"next_dispatch_at"` + CurrentRetries int16 `json:"currentRetries" db:"current_retries"` +} diff --git a/repository/calculate.go b/repository/calculate.go index 5f04d4c..eed635b 100644 --- a/repository/calculate.go +++ b/repository/calculate.go @@ -4,7 +4,16 @@ import ( "electricity_bill_calc/global" "electricity_bill_calc/logger" "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" "electricity_bill_calc/types" + "encoding/json" + "errors" + "fmt" + "github.com/jackc/pgx/v5" + "github.com/shopspring/decimal" + "golang.org/x/sync/errgroup" + "log" + "strings" "time" "github.com/doug-martin/goqu/v9" @@ -70,7 +79,7 @@ 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)) @@ -94,7 +103,7 @@ func (cr _CalculateRepository) GetAllPoolingMeterRelations(pid string, revokedAf 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() @@ -123,7 +132,7 @@ func (cr _CalculateRepository) GetAllTenementMeterRelations(pid string, associat } -//获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据 +// 获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据 func (cr _CalculateRepository) GetMeterReadings(rid string, meterType int16) ([]model.MeterReading, error) { cr.log.Info("获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据", zap.String("rid", rid), zap.Int16("meterType", meterType)) @@ -239,3 +248,264 @@ func (cr _CalculateRepository) GetAllTenements(rid string) ([]model.Tenement, er } return tenements, nil } +func (cr _CalculateRepository) ClearReportContent(tx pgx.Tx, rid string) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + querysql, querarg, _ := cr.ds.Delete("report_summary"). + Where(goqu.C("report_id").Eq(rid)).ToSQL() + _, err := tx.Exec(ctx, querysql, querarg...) + if err != nil { + return err + } + querysql, querarg, _ = cr.ds.Delete("report_public_consumption"). + Where(goqu.C("report_id").Eq(rid)).ToSQL() + _, err = tx.Exec(ctx, querysql, querarg...) + if err != nil { + return err + } + + querysql, querarg, _ = cr.ds.Delete("report_pooled_consumption"). + Where(goqu.C("report_id").Eq(rid)).ToSQL() + _, err = tx.Exec(ctx, querysql, querarg...) + if err != nil { + return err + } + + querysql, querarg, _ = cr.ds.Delete("report_tenement"). + Where(goqu.C("report_id").Eq(rid)).ToSQL() + _, err = tx.Exec(ctx, querysql, querarg...) + if err != nil { + return err + } + + return nil +} +func (cr _CalculateRepository) SaveReportPublics(tx pgx.Tx, rid string, meters []calculate.Meter) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + if len(meters) == 0 { + // 如果没有公共表计则直接返回 + return nil + } + // 准备插入表达式 + insertExpr := cr.ds.Insert("report_public_consumption"). + Cols( + "report_id", "park_meter_id", "overall", "critical", "peak", "flat", "valley", + "loss_adjust", "consumption_total", "loss_adjust_total", "final_total", + ).Prepared(true) + // 添加值到插入表达式中 + for _, meter := range meters { + insertExpr = insertExpr.Vals([]interface{}{ + rid, + meter.Code, + meter.Overall.Fee, + meter.Critical.Fee, + meter.Peak.Fee, + meter.Flat.Fee, + meter.Valley.Fee, + meter.AdjustLoss.Fee, + meter.Overall.Fee, + meter.AdjustLoss.Fee, + meter.Overall.Fee.Add(meter.AdjustLoss.Fee), + }) + } + + // 执行插入语句 + inserSql, insertArgs, err := insertExpr.Prepared(true).ToSQL() + if err != nil { + return err + } + if _, err := tx.Exec(ctx, inserSql, insertArgs); err != nil { + return fmt.Errorf("保存报表核算概要失败: %w", err) + } + + return nil +} +func (cr _CalculateRepository) SaveReportSummary(tx pgx.Tx, summary calculate.Summary) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + // 构建插入表达式 + insertsql, insertArgs, _ := cr.ds.Insert("report_summary"). + Cols( + "report_id", "overall", "critical", "peak", "flat", "valley", + "loss", "loss_fee", "basic_fee", "basic_pooled_price_consumption", "basic_pooled_price_area", + "adjust_fee", "adjust_pooled_price_consumption", "adjust_pooled_price_area", + "loss_diluted_price", "loss_proportion", "final_diluted_overall", + "consumption_fee", "authorize_loss", "overall_area", "total_consumption", + ). + Vals(goqu.Vals{ + summary.ReportId, summary.Overall, summary.Critical, summary.Peak, summary.Flat, + summary.Valley, summary.Loss, summary.LossFee, summary.BasicFee, + summary.BasicPooledPriceConsumption, summary.BasicPooledPriceArea, + summary.AdjustFee, summary.AdjustPooledPriceConsumption, summary.AdjustPooledPriceArea, + summary.LossDilutedPrice, summary.LossProportion, summary.FinalDilutedOverall, + summary.ConsumptionFee, summary.AuthoizeLoss, summary.OverallArea, summary.TotalConsumption, + }).Prepared(true).ToSQL() + + // 执行插入语句 + + if _, err := tx.Exec(ctx, insertsql, insertArgs...); err != nil { + cr.log.Error("保存报表核算概要失败。") + return err + } + + return nil +} + +type NestedMeter struct { + Overall model.ConsumptionUnit + Critical model.ConsumptionUnit + Peak model.ConsumptionUnit + Flat model.ConsumptionUnit + Valley model.ConsumptionUnit + CoveredArea decimal.Decimal + + // Add other fields here as needed +} + +func (cr _CalculateRepository) SaveReportPoolings(tx pgx.Tx, + rid string, + meters []calculate.Meter, + relations []model.MeterRelation, + tenements []calculate.Meter) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + if len(meters) == 0 { + return nil + } + relationsSlaves := make(map[string]bool) + for _, r := range relations { + relationsSlaves[r.SlaveMeter] = true + } + + tenementCodes := make(map[string]bool) + for _, t := range tenements { + tenementCodes[t.Code] = true + } + + for _, r := range relations { + if _, ok := tenementCodes[r.SlaveMeter]; !ok { + return errors.New("unknown tenement meter in active meter relations") + } + } + + var insertQueries []goqu.InsertDataset + for _, meter := range meters { + submeters := make([]NestedMeter, 0) + for _, r := range relations { + if r.MasterMeter == meter.Code { + for _, t := range tenements { + if t.Code == r.SlaveMeter { + submeters = append(submeters, NestedMeter{ + Overall: t.Overall, + Critical: t.Critical, + Peak: t.Peak, + Flat: t.Flat, + Valley: t.Valley, + }) + } + } + } + } + + submetersJSON, err := json.Marshal(submeters) + if err != nil { + return err + } + + insertQuery := goqu.Insert("report_pooled_consumption"). + Cols("report_id", "pooled_meter_id", "overall", "critical", "peak", "flat", "valley", "pooled_area", "diluted"). + Vals(goqu.Vals{rid, meter.Code, meter.Overall, meter.Critical, meter.Peak, meter.Flat, meter.Valley, meter.CoveredArea, submetersJSON}) + + insertQueries = append(insertQueries, *insertQuery) + } + + eg, _ := errgroup.WithContext(ctx) + for _, insertQuery := range insertQueries { + insertQuery := insertQuery // Capture loop variable + eg.Go(func() error { + sql, args, err := insertQuery.ToSQL() + if err != nil { + return err + } + _, err = tx.Exec(ctx, sql, args...) + return err + }) + } + return eg.Wait() +} +func (cr _CalculateRepository) SaveReportTenement(tx pgx.Tx, report model.ReportIndex, tenements []model.Tenement, tenementCharges []calculate.TenementCharge) error { + if len(tenements) == 0 { + // 如果没有商户则直接返回 + return nil + } + cr.log.Info("保存商户报表。") + ctx, cancel := global.TimeoutContext() + defer cancel() + insertQuery := cr.ds.Insert("report_tenement").Prepared(true) + values := []goqu.Record{} + for _, tenement := range tenements { + charge := findTenementCharge(tenementCharges, tenement.Id) + values = append(values, goqu.Record{ + "report_id": report.Id, + "tenement_id": tenement.Id, + "tenement_detail": toJSONString(tenement), + "calc_period": report.Period, + "overall": toJSONString(charge.Overall), + "critical": toJSONString(charge.Critical), + "peak": toJSONString(charge.Peak), + "flat": toJSONString(charge.Flat), + "valley": toJSONString(charge.Valley), + "loss": toJSONString(charge.Loss), + "basic_fee_pooled": charge.BasicFee, + "adjust_fee_pooled": charge.AdjustFee, + "loss_fee_pooled": charge.LossPooled, + "final_pooled": charge.PublicPooled, + "final_charge": charge.FinalCharges, + "meters": toJSONString(convertToNestedMeters(charge.Submeters)), + "pooled": toJSONString(convertToNestedMeters(charge.Poolings)), + }) + } + + sql, params, err := insertQuery.Rows(values).Prepared(true).ToSQL() + if err != nil { + log.Println("sql出现问题................................") + return err + } + tx.Exec(ctx, sql, params...) + if err != nil { + return err + } + return nil +} + +// findTenementCharge 在 TenementCharges 切片中查找指定商户的核算内容 +func findTenementCharge(charges []calculate.TenementCharge, tenementID string) calculate.TenementCharge { + for _, charge := range charges { + if charge.Tenement == tenementID { + return charge + } + } + return calculate.TenementCharge{} +} + +// convertToNestedMeters 将 Meter 切片转换为 NestedMeter 切片 +func convertToNestedMeters(meters []*calculate.Meter) []NestedMeter { + nestedMeters := []NestedMeter{} + for _, meter := range meters { + nestedMeters = append(nestedMeters, NestedMeter{ + Overall: meter.Overall, + Critical: meter.Critical, + Peak: meter.Peak, + Flat: meter.Flat, + Valley: meter.Valley, + CoveredArea: meter.CoveredArea, + }) + } + return nestedMeters +} + +// toJSONString 将对象转换为 JSON 字符串 +func toJSONString(obj interface{}) string { + return `"` + strings.ReplaceAll(fmt.Sprintf("%#v", obj), `"`, `\"`) + `"` +} diff --git a/repository/god.go b/repository/god.go new file mode 100644 index 0000000..87855ff --- /dev/null +++ b/repository/god.go @@ -0,0 +1,19 @@ +package repository + +import ( + "electricity_bill_calc/logger" + "github.com/doug-martin/goqu/v9" + "go.uber.org/zap" +) + +type _GodModRepository struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var GodModRepository = _GodModRepository{ + log: logger.Named("Repository", "GodMod"), + ds: goqu.Dialect("postgres"), +} + +// 删除指定园区中的表计和商户的绑定关系 diff --git a/repository/synchronize.go b/repository/synchronize.go new file mode 100644 index 0000000..c4b462d --- /dev/null +++ b/repository/synchronize.go @@ -0,0 +1,208 @@ +package repository + +import ( + "context" + "electricity_bill_calc/config" + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/model" + "electricity_bill_calc/tools" + "electricity_bill_calc/vo" + "fmt" + "github.com/doug-martin/goqu/v9" + "github.com/georgysavva/scany/v2/pgxscan" + "github.com/jackc/pgx/v5" + "go.uber.org/zap" + "strconv" +) + +type _SynchronizeRepository struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var SynchronizeRepository = _SynchronizeRepository{ + log: logger.Named("Repository", "Synchronize"), + ds: goqu.Dialect("postgres"), +} + +func (sr _SynchronizeRepository) SearchSynchronizeSchedules(userId *string, parkId *string, page uint, keyword *string) ([]*model.SynchronizeSchedule, int64, error) { + sr.log.Info("检索符合指定条件的同步记录", zap.String("user id", tools.DefaultTo(userId, "")), + zap.String("park id", tools.DefaultTo(parkId, "")), zap.Uint("page", page), + zap.String("keyword", tools.DefaultTo(keyword, ""))) + ctx, cancelFunc := global.TimeoutContext() + defer cancelFunc() + //scheduleQuery := "select ss.*, ud.name as user_name, p.name as park_name from synchronize_schedule as ss + //join park as p on p.id=ss.park_id join user_detail as ud on ud.id=ss.user_id where 1=1" + schedulequery := sr.ds.From(goqu.T("synchronize_schedule").As("ss")). + Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("ss.park_id")))). + Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("ud.id").Eq(goqu.I("ss.user_id")))). + Select("ss.*", goqu.I("ud.name").As("user_name"), goqu.I("p.name").As("park_name")) + //countQuery := "select count(ss.*) from synchronize_schedule as ss + //join park as p on p.id=ss.park_id join user_detail as ud on ud.id=ss.user_id where 1=1" + countquery := sr.ds.From(goqu.T("synchronize_schedule").As("ss")). + Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("ss.park_id")))). + Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.I("ud.id").Eq(goqu.I("ss.user_id")))). + Select(goqu.COUNT(goqu.I("ss.*"))) + if userId != nil && len(*userId) > 0 { + schedulequery = schedulequery.Where(goqu.I("ss.user_id").Eq(*userId)) + countquery = countquery.Where(goqu.I("ss.user_id").Eq(*userId)) + } + if parkId != nil && len(*parkId) > 0 { + schedulequery = schedulequery.Where(goqu.I("ss.park_id").Eq(*parkId)) + countquery = countquery.Where(goqu.I("ss.park_id").Eq(*parkId)) + } + if keyword != nil && len(*keyword) > 0 { + pattern := fmt.Sprintf("%%%s%%", *keyword) + schedulequery = schedulequery.Where(goqu.Or( + goqu.I("p.name").ILike(pattern), + goqu.I("p.abbr").ILike(pattern), + goqu.I("p.address").ILike(pattern), + goqu.I("p.contact").ILike(pattern), + goqu.I("p.phone").ILike(pattern), + goqu.I("ud.name").ILike(pattern), + goqu.I("ud.abbr").ILike(pattern), + goqu.I("ud.contact").ILike(pattern), + goqu.I("ud.phone").ILike(pattern), + goqu.I("ss.task_name").ILike(pattern), + goqu.I("ss.task_description").ILike(pattern), + )) + countquery = countquery.Where(goqu.Or( + goqu.I("p.name").ILike(pattern), + goqu.I("p.abbr").ILike(pattern), + goqu.I("p.address").ILike(pattern), + goqu.I("p.contact").ILike(pattern), + goqu.I("ud.name").ILike(pattern), + goqu.I("ud.abbr").ILike(pattern), + goqu.I("ud.contact").ILike(pattern), + goqu.I("ud.phone").ILike(pattern), + goqu.I("ss.task_name").ILike(pattern), + goqu.I("ss.task_description").ILike(pattern), + )) + } + startRow := (page - 1) * config.ServiceSettings.ItemsPageSize + schedulequery = schedulequery. + Order(goqu.I("ss.created_at").Desc()). + Offset(startRow).Limit(config.ServiceSettings.ItemsPageSize) + var ( + schedule []*model.SynchronizeSchedule = make([]*model.SynchronizeSchedule, 0) + count int64 + ) + querySql, queryArgs, _ := schedulequery.Prepared(true).ToSQL() + countSql, countArgs, _ := countquery.Prepared(true).ToSQL() + if err := pgxscan.Select(ctx, global.DB, &schedule, querySql, queryArgs...); err != nil { + sr.log.Error("获取同步任务时出现错误", zap.Error(err)) + return schedule, 0, err + } + if err := pgxscan.Get(ctx, global.DB, &count, countSql, countArgs...); err != nil { + sr.log.Error("检索同步任务总数量时出现错误", zap.Error(err)) + return schedule, 0, err + } + return schedule, count, nil +} + +// From("synchronize_schedule"). +// +// Select( +// goqu.I("synchronize_schedule.*"), +// goqu.I("user_detail.name").As("user_name"), +// goqu.I("park.name").As("park_name"), +// ). +// Join( +// goqu.T("park").On(goqu.I("park.id").Eq(goqu.I("synchronize_schedule.park_id"))), +// goqu.T("user_detail").On(goqu.I("user_detail.id").Eq(goqu.I("synchronize_schedule.user_id"))), +// ). +// Where(goqu.C("1").Eq(1)) +// +// SELECT count(ss.*) +// FROM synchronize_schedule AS ss +// JOIN park AS p ON p.id = ss.park_id +// JOIN user_detail AS ud ON ud.id = ss.user_id +// WHERE true` +// +// var args []interface{} +// +// if uid != nil { +// scheduleQuery += " AND ss.user_id = $1" +// countQuery += " AND ss.user_id = $1" +// args = append(args, *uid) +// } +// +// if pid != nil { +// scheduleQuery += " AND ss.park_id = $2" +// countQuery += " AND ss.park_id = $2" +// args = append(args, *pid) +// } +// +// if keyword != nil { +// pattern := "%" + *keyword + "%" +// scheduleQuery += ` AND (p.name LIKE $3 OR p.abbr LIKE $3 OR p.address LIKE $3 OR p.contact LIKE $3 OR +// +// p.phone LIKE $3 OR ud.name LIKE $3 OR ud.abbr LIKE $3 OR ud.contact LIKE $3 OR +// ud.phone LIKE $3 OR ss.task_name LIKE $3 OR ss.task_description LIKE $3)` +// +// args = append(args, pattern) +// } +func (sr _SynchronizeRepository) RetrieveSynchronizeConfiguration(uId, pId string) (vo.SynchronizeConfiguration, error) { + sr.log.Info("检索符合指定条件的同步记录", zap.String("user id", uId), zap.String("park id", pId)) + ctx, cancelFunc := global.TimeoutContext() + defer cancelFunc() + //select * from synchronize_config where user_id=$1 and park_id=$2 + configSql, configArgs, _ := sr.ds. + From(goqu.T("synchronize_config")). + Where(goqu.I("user_id").Eq(uId)). + Where(goqu.I("park_id").Eq(pId)). + Prepared(true).Select("*").ToSQL() + fmt.Println(configSql) + var configs []model.SynchronizeConfiguration + if err := pgxscan.Select(ctx, global.DB, &configs, configSql, configArgs...); err != nil { + fmt.Println(err) + sr.log.Error("获取同步任务时出现错误", zap.Error(err)) + return vo.SynchronizeConfiguration{}, err + } + if len(configs) <= 0 { + return vo.SynchronizeConfiguration{}, nil + } + maxr := strconv.Itoa(int(configs[0].MaxRetries)) + retry := strconv.Itoa(int(configs[0].RetryInterval)) + synconfig := vo.SynchronizeConfiguration{ + CollectAt: configs[0].CollectAt.Format("15:04:05"), + EntID: configs[0].User, + Imrs: configs[0].ImrsType, + ImrsAccount: configs[0].AuthorizationAccount, + ImrsKey: string(configs[0].AuthorizationKey), + ImrsSecret: configs[0].AuthorizationSecret, + Interval: float64(configs[0].Interval), + MaxRetries: maxr, + ParkID: configs[0].Park, + ReadingType: float64(configs[0].MeterReadingType), + RetryAlgorithm: float64(configs[0].RetryIntervalAlgorithm), + RetryInterval: retry, + } + return synconfig, nil +} +func (sr _SynchronizeRepository) CreateSynchronizeConfiguration(tx pgx.Tx, ctx context.Context, uId string, form *vo.SynchronizeConfigurationCreateForm) (bool, error) { + sr.log.Info("创建新的同步用户配置", zap.String("user Id", uId)) + ctx, cancel := global.TimeoutContext() + defer cancel() + //insert into synchronize_config (user_id, park_id, meter_reading_type, imrs_type, imrs_authorization_account, + // imrs_authorization_secret, imrs_authorization_key, interval, collect_at, max_retries, retry_interval, retry_interval_algorithm) values + configSql, configArgs, _ := sr.ds. + Insert(goqu.T("synchronize_config")). + Cols( + "user_id", "park_id", "meter_reading_type", "imrs_type", "imrs_authorization_account", "imrs_authorization_secret", + "imrs_authorization_key", "interval", "collect_at", "max_retries", + "retry_interval", "retry_interval_algorithm"). + Vals( + goqu.Vals{uId, form.ParkID, form.ReadingType, form.Imrs, form.ImrsAccount, form.ImrsSecret, form.ImrsKey, form.Interval, + form.CollectAt, form.MaxRetries, form.RetryInterval, form.RetryAlgorithm, + }, + ). + Prepared(true).ToSQL() + ok, err := tx.Exec(ctx, configSql, configArgs...) + if err != nil { + sr.log.Error("创建同步配置信息失败", zap.Error(err)) + return false, err + } + return ok.RowsAffected() > 0, nil +} diff --git a/router/router.go b/router/router.go index e09f7b7..5359d0d 100644 --- a/router/router.go +++ b/router/router.go @@ -41,7 +41,7 @@ func App() *fiber.App { })) //恢复中间件 app.Use(logger.NewLogMiddleware(logger.LogMiddlewareConfig{ Logger: logger.Named("App"), - })) //日志中间件 + })) //日志中间件 app.Use(security.SessionRecovery) //会话恢复中间件 controller.InitializeUserHandlers(app) diff --git a/service/calculate/checking.go b/service/calculate/checking.go index 7169626..e715ea4 100644 --- a/service/calculate/checking.go +++ b/service/calculate/checking.go @@ -1,4 +1,5 @@ package calculate + import ( "electricity_bill_calc/model" "fmt" @@ -15,7 +16,7 @@ func CheckMeterArea(report *model.ReportIndex, meters []*model.MeterDetail) (boo var meterWithoutArea int32 for _, m := range meters { - if (m.MeterType == model.METER_INSTALLATION_TENEMENT || m.MeterType == model.METER_INSTALLATION_POOLING) && + if (m.MeterType == model.METER_INSTALLATION_TENEMENT || m.MeterType == model.METER_INSTALLATION_POOLING) && m.Area == nil { atomic.AddInt32(&meterWithoutArea, 1) } diff --git a/service/calculate/meters.go b/service/calculate/meters.go new file mode 100644 index 0000000..7dbaade --- /dev/null +++ b/service/calculate/meters.go @@ -0,0 +1,448 @@ +package calculate + +import ( + "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" + "electricity_bill_calc/repository" + "errors" + "fmt" + "github.com/shopspring/decimal" +) + +func CollectMeters(tenements []calculate.PrimaryTenementStatistics, poolings []calculate.Meter, publics []calculate.Meter) (MeterMap, error) { + meters := make(MeterMap) + // Collect tenement meters + for _, t := range tenements { + for _, m := range t.Meters { + key := Key{TenementID: t.Tenement.Id, Code: m.Code} + meters[key] = m + } + } + // Collect poolings + for _, m := range poolings { + key := Key{TenementID: "", Code: m.Code} + meters[key] = m + } + // Collect publics + for _, m := range publics { + key := Key{TenementID: "", Code: m.Code} + meters[key] = m + } + return meters, nil +} + +// / 计算基本电费摊薄 +func CalculateBasicPooling(report *model.ReportIndex, summary *calculate.Summary, meters *MeterMap) error { + switch report.BasisPooled { + case model.POOLING_MODE_AREA: + if summary.OverallArea.IsZero() { + return fmt.Errorf("园区中表计覆盖总面积为零,无法按面积摊薄") + } + for _, meter := range *meters { + meterFee := meter.Overall.Amount.InexactFloat64() * summary.BasicPooledPriceArea.InexactFloat64() + meter.PooledBasic = model.ConsumptionUnit{ + Amount: meter.Overall.Amount, + Fee: decimal.NewFromFloat(meterFee), + Price: summary.BasicPooledPriceArea, + Proportion: summary.BasicFee, + } + } + case model.POOLING_MODE_CONSUMPTION: + for _, meter := range *meters { + meterFee := meter.Overall.Amount.InexactFloat64() * summary.BasicPooledPriceConsumption.InexactFloat64() + meter.PooledBasic = model.ConsumptionUnit{ + Amount: meter.Overall.Amount, + Fee: decimal.NewFromFloat(meterFee), + Price: summary.BasicPooledPriceConsumption, + Proportion: summary.BasicFee, + } + } + default: + } + return nil +} + +/// 计算调整电费摊薄 + +func CalculateAdjustPooling(report model.ReportIndex, summary calculate.Summary, meters MeterMap) error { + var p decimal.Decimal + switch report.AdjustPooled { + case model.POOLING_MODE_AREA: + if summary.OverallArea.IsZero() { + return fmt.Errorf("园区中表计覆盖总面积为零,无法按面积摊薄") + } + + for _, meter := range meters { + meterFee := meter.Overall.Amount.Mul(summary.AdjustPooledPriceArea) + if summary.AdjustFee.IsZero() { + p = decimal.Zero + } else { + p = meterFee.Div(summary.AdjustFee) + } + meter.PooledAdjust = model.ConsumptionUnit{ + Amount: meter.Overall.Amount, + Fee: meterFee, + Price: summary.AdjustPooledPriceArea, + Proportion: p, + } + } + case model.POOLING_MODE_CONSUMPTION: + for _, meter := range meters { + meterFee := meter.Overall.Amount.Mul(summary.AdjustPooledPriceConsumption) + if summary.AdjustFee.IsZero() { + p = decimal.Zero + } else { + p = meterFee.Div(summary.AdjustFee) + } + meter.PooledAdjust = model.ConsumptionUnit{ + Amount: meter.Overall.Amount, + Fee: meterFee, + Price: summary.AdjustPooledPriceConsumption, + Proportion: p, + } + } + default: + + } + return nil +} + +// 除数问题 +func CalculateLossPooling(report model.ReportIndex, summary calculate.Summary, meters MeterMap) error { + switch report.LossPooled { + case model.POOLING_MODE_AREA: + if summary.OverallArea.IsZero() { + return fmt.Errorf("园区中表计覆盖总面积为零,无法按面积摊薄") + } + for _, meter := range meters { + pooledLossAmount1 := meter.Detail.Area.Decimal.Div(summary.OverallArea) + pooledLossAmount := pooledLossAmount1.Mul(summary.AuthoizeLoss.Amount) + meter.PooledLoss = model.ConsumptionUnit{ + Amount: pooledLossAmount, + Fee: pooledLossAmount.Mul(summary.LossDilutedPrice), + Price: summary.LossDilutedPrice, + Proportion: meter.Detail.Area.Decimal.Div(summary.OverallArea), + } + } + case model.POOLING_MODE_CONSUMPTION: + for _, meter := range meters { + pooledLossAmount1 := meter.Detail.Area.Decimal.Div(summary.OverallArea) + pooledLossAmount := pooledLossAmount1.Mul(summary.AuthoizeLoss.Amount) + + meter.PooledLoss = model.ConsumptionUnit{ + Amount: pooledLossAmount, + Fee: pooledLossAmount.Mul(summary.LossDilutedPrice), + Price: summary.LossDilutedPrice, + Proportion: meter.Overall.Amount.Div(summary.Overall.Amount), + } + } + default: + // 其他情况下不做处理 + } + return nil +} + +/// 计算所有商户类型表计的全周期电量。 + +func CalculateTenementConsumptions(meters MeterMap) (map[string]decimal.Decimal, error) { + consumptions := make(map[string]decimal.Decimal) + for _, meter := range meters { + if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT { + amount, ok := consumptions[meter.Code] + if !ok { + amount = decimal.Decimal{} + } + amount.Add(meter.Overall.Amount).Add(amount) + consumptions[meter.Code] = amount + } + } + for _, meter := range meters { + if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT { + amount, ok := consumptions[meter.Code] + if !ok { + return nil, errors.New("meter code not found in consumptions") + } + + if amount.GreaterThan(decimal.Zero) { + meter.SharedPoolingProportion = meter.Overall.Amount.Div(amount) + } else if amount.IsZero() { + meter.SharedPoolingProportion = decimal.NewFromFloat(1.0) + } else { + meter.SharedPoolingProportion = decimal.NewFromFloat(1.0) + } + } + } + + return consumptions, nil +} + +/* +/// 计算商户表计的公摊分摊 + +func CalculateTenementPoolings(report model.ReportIndex, summary calculate.Summary, meters MeterMap, meterRelations []model.MeterRelation) error { + for _, meter := range meters { + if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT { + switch report.PublicPooled { + case model.POOLING_MODE_AREA: + for _, relation := range meterRelations { + if relation.SlaveMeter == meter.Code { + key := Key{ + Code: relation.MasterMeter, + } + parentMeter, ok := meters[key] + if !ok { + return errors.New("父级表记未找到") + } + + poolingAmount := meter.Detail.Area.Decimal.Div(parentMeter.CoveredArea). + Mul(meter.SharedPoolingProportion). + Mul(parentMeter.Overall.Amount).Mul(summary.Overall.Price) + + pooling := calculate.Pooling{ + Code: parentMeter.Code, + Detail: model.ConsumptionUnit{ + Amount: poolingAmount, + Fee: poolingAmount.Mul(summary.Overall.Price), + Price: summary.Overall.Price, + //后续debug此处需要判断, + Proportion: poolingAmount.Div(parentMeter.Overall.Amount), + }, + } + + pooling := calculate.Pooling{ + Code: parentMeter.Code, + Detail: model.ConsumptionUnit{ + Amount: poolingAmount, + Fee: poolingAmount.Mul(summary.Overall.Price), + Price: summary.Overall.Price, + Proportion: poolingAmount.Div(parentMeter.Overall.Amount), + }, + } + meter.PooledPublic = &ConsumptionUnit{ + Amount: poolingAmount, + Fee: new(big.Rat).Mul(poolingAmount, summary.Overall.Price), + Price: summary.Overall.Price, + Proportion: new(big.Rat).Quo(poolingAmount, parentAmount), + } + + meter.Poolings = append(meter.Poolings, pooling) + } + } + + case Consumption: + for _, relation := range meterRelations { + if relation.SlaveMeter == meter.Code { + parentMeter, ok := meters[relation.MasterMeter] + if !ok { + return errors.New("parent meter not found") + } + + if parentMeter.Overall.Amount.Cmp(new(big.Rat)) == 0 { + poolingAmount := new(big.Rat) + parentAmount := new(big.Rat) + + pooling := &Pooling{ + Code: parentMeter.Code, + Detail: &ConsumptionUnit{ + Amount: poolingAmount, + Fee: new(big.Rat), + Price: summary.Overall.Price, + Proportion: new(big.Rat), + }, + } + + meter.PooledPublic = &ConsumptionUnit{ + Amount: poolingAmount, + Fee: new(big.Rat), + Price: summary.Overall.Price, + Proportion: new(big.Rat), + } + + meter.Poolings = append(meter.Poolings, pooling) + } else { + poolingAmount := new(big.Rat).Mul(meter.Overall.Amount, new(big.Rat).Quo(parentMeter.Overall.Amount, parentMeter.Overall.Amount)) + parentAmount := parentMeter.Overall.Amount + + pooling := &Pooling{ + Code: parentMeter.Code, + Detail: &ConsumptionUnit{ + Amount: poolingAmount, + Fee: new(big.Rat).Mul(poolingAmount, summary.Overall.Price), + Price: summary.Overall.Price, + Proportion: new(big.Rat).Quo(poolingAmount, parentAmount), + }, + } + + meter.PooledPublic = &ConsumptionUnit{ + Amount: poolingAmount, + Fee: new(big.Rat).Mul(poolingAmount, summary.Overall.Price), + Price: summary.Overall.Price, + Proportion: new(big.Rat).Quo(poolingAmount, parentAmount), + } + + meter.Poolings = append(meter.Poolings, pooling) + } + } + } + + default: + // handle other pooling modes... + } + } + } + + return nil +} +*/ +// 计算商户表计的公摊分摊 +func CalculateTenementPoolings(report model.ReportIndex, summary calculate.Summary, meters MeterMap, meterRelations []model.MeterRelation) error { + + switch report.PublicPooled { + case model.POOLING_MODE_AREA: + for _, meter := range meters { + if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT { + var pooleds []struct { + PooledAmount decimal.Decimal + ParentAmount decimal.Decimal + ParentCode string + } + for _, relation := range meterRelations { + if relation.SlaveMeter == meter.Code { + key := Key{ + Code: relation.MasterMeter, + } + parentMeter, ok := meters[key] + if !ok { + // 处理未找到父级表计的情况 + continue + } + // 计算分摊电量和父级表电量 + + pooledAmount := meter.Detail.Area.Decimal.Div(parentMeter.CoveredArea).Mul(parentMeter.Overall.Amount).Mul(meter.SharedPoolingProportion) + pooleds = append(pooleds, struct { + PooledAmount decimal.Decimal + ParentAmount decimal.Decimal + ParentCode string + }{ + PooledAmount: pooledAmount, + ParentAmount: parentMeter.Overall.Amount, + ParentCode: parentMeter.Code, + }) + } + } + + // 计算总分摊电量和总父级电量 + var consumptions, total decimal.Decimal + for _, p := range pooleds { + consumptions = consumptions.Add(p.PooledAmount) + total = total.Add(p.ParentAmount) + } + + // 计算并更新公摊分摊信息 + for _, p := range pooleds { + poolingAmount := p.PooledAmount + proportion := p.PooledAmount.Div(p.ParentAmount) + fee := poolingAmount.Mul(summary.Overall.Price) + + // 更新父级表计的公摊分摊信息 + key := Key{ + Code: p.ParentCode, + } + parentMeter := meters[key] + parentMeter.PooledPublic.Amount = consumptions + parentMeter.PooledPublic.Fee = consumptions.Mul(summary.Overall.Price) + parentMeter.PooledPublic.Proportion = consumptions.Div(total) + meters[Key{Code: p.ParentCode}] = parentMeter + // 创建并更新分摊信息 + pooling := calculate.Pooling{ + Code: p.ParentCode, + Detail: model.ConsumptionUnit{ + Amount: poolingAmount, + Fee: fee, + Price: summary.Overall.Price, + Proportion: proportion, + }, + } + meter.Poolings = append(meter.Poolings, &pooling) + } + } + } + + case model.POOLING_MODE_CONSUMPTION: + for _, meter := range meters { + if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT { + var pooled []struct { + PooledAmount decimal.Decimal + ParentAmount decimal.Decimal + ParentCode string + } + for _, relation := range meterRelations { + if relation.SlaveMeter == meter.Code { + parentMeter, ok := meters[Key{Code: relation.MasterMeter}] + if !ok { + // 处理未找到父级表计的情况 + continue + } + // 计算分摊电量和父级电量 + var pooledAmount decimal.Decimal + if parentMeter.Overall.Amount.IsZero() { + relations, err := repository.MeterRepository.ListPooledMeterRelations(report.Park, meter.Code) + if err != nil { + return err + } + //此处rust版本有误,更新后的解决办法 + pooledAmount = meter.Overall.Amount.Div(decimal.NewFromInt(int64(len(relations)))).Mul(parentMeter.Overall.Amount) + } + pooled = append(pooled, struct { + PooledAmount decimal.Decimal + ParentAmount decimal.Decimal + ParentCode string + }{ + PooledAmount: pooledAmount, + ParentAmount: parentMeter.Overall.Amount, + ParentCode: parentMeter.Code, + }) + } + } + + // 计算总分摊电量和总父级表记电量 + var consumptions, total decimal.Decimal + for _, p := range pooled { + consumptions = consumptions.Add(p.PooledAmount) + total = total.Add(p.ParentAmount) + } + + // 计算并更新公摊分摊信息 + for _, p := range pooled { + poolingAmount := p.PooledAmount + proportion := p.PooledAmount.Div(p.ParentAmount) + fee := poolingAmount.Mul(summary.Overall.Price) + + // 更新父级表计的公摊分摊信息 + parentMeter := meters[Key{Code: p.ParentCode}] + parentMeter.PooledPublic.Amount = consumptions + parentMeter.PooledPublic.Fee = consumptions.Mul(summary.Overall.Price) + parentMeter.PooledPublic.Proportion = consumptions.Div(total) + meters[Key{Code: p.ParentCode}] = parentMeter + + // 创建并更新分摊信息 + pooling := calculate.Pooling{ + Code: p.ParentCode, + Detail: model.ConsumptionUnit{ + Amount: poolingAmount, + Fee: fee, + Price: summary.Overall.Price, + Proportion: proportion, + }, + } + meter.Poolings = append(meter.Poolings, &pooling) + } + } + } + + default: + // 处理其他分摊模式 + } + + return nil +} diff --git a/service/calculate/persist.go b/service/calculate/persist.go new file mode 100644 index 0000000..913ff12 --- /dev/null +++ b/service/calculate/persist.go @@ -0,0 +1,81 @@ +package calculate + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/model" + "electricity_bill_calc/model/calculate" + "electricity_bill_calc/repository" + "github.com/jackc/pgx/v5" +) + +// 向数据库保存核算概况结果 +func SaveSummary(tx pgx.Tx, summary calculate.Summary) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + + // 保存核算概况结果到数据库 + err := repository.CalculateRepository.SaveReportSummary(tx, summary) + if err != nil { + return err + } + tx.Commit(ctx) + return nil +} + +// type MeterMap map[string]map[string]calculate.Meter +// 向数据库保存公共表计的计算结果 +func SavePublics(tx pgx.Tx, report model.ReportIndex, meters MeterMap) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + + var filteredMeters []calculate.Meter + + for _, m := range meters { + if m.Detail.MeterType == model.METER_INSTALLATION_PARK { + filteredMeters = append(filteredMeters, m) + } + } + err := repository.CalculateRepository.SaveReportPublics(tx, report.Id, filteredMeters) + if err != nil { + return err + } + tx.Commit(ctx) + return nil +} + +func SavePoolings(tx pgx.Tx, report model.ReportIndex, meters MeterMap, relations []model.MeterRelation) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + var poolingMeters []calculate.Meter + var tenementMeters []calculate.Meter + // 根据条件筛选 Meter 并保存到对应的数组中 + for _, m := range meters { + if m.Detail.MeterType == model.METER_INSTALLATION_POOLING { + poolingMeters = append(poolingMeters, m) + } else if m.Detail.MeterType == model.METER_INSTALLATION_TENEMENT { + tenementMeters = append(tenementMeters, m) + } + } + err := repository.CalculateRepository.SaveReportPoolings(tx, report.Id, poolingMeters, relations, tenementMeters) + if err != nil { + return err + } + tx.Commit(ctx) + + return nil +} +func SaveTenements(tx pgx.Tx, report model.ReportIndex, tenement []calculate.PrimaryTenementStatistics, tc []calculate.TenementCharge) error { + ctx, cancel := global.TimeoutContext() + defer cancel() + var ts []model.Tenement + for _, r := range tenement { + ts = append(ts, r.Tenement) + } + err := repository.CalculateRepository.SaveReportTenement(tx, report, ts, tc) + if err != nil { + return err + } + tx.Commit(ctx) + + return nil +} diff --git a/service/calculate/summary.go b/service/calculate/summary.go index 13ba004..651566b 100644 --- a/service/calculate/summary.go +++ b/service/calculate/summary.go @@ -4,13 +4,13 @@ import ( "electricity_bill_calc/model" "electricity_bill_calc/model/calculate" "errors" - "fmt" "github.com/shopspring/decimal" + + "fmt" ) // 计算已经启用的商铺面积和 -func TotalConsumptionCalculate(tenements []calculate.PrimaryTenementStatistics, - summary calculate.Summary) decimal.Decimal { +func TotalConsumptionCalculate(tenements []calculate.PrimaryTenementStatistics, summary calculate.Summary) decimal.Decimal { var areaMaters []calculate.Meter for _, t := range tenements { areaMaters = append(areaMaters, t.Meters...) @@ -41,7 +41,7 @@ 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) @@ -91,7 +91,7 @@ func LossCalculate(report *model.ReportIndex, Public *[]calculate.Meter, // 计算已经启用的商铺面积和 func EnabledAreaCalculate(tenements *[]calculate.PrimaryTenementStatistics, - summary *calculate.Summary) error { + summary *calculate.Summary) (*decimal.Decimal, error) { var areaMeters []calculate.Meter for _, t := range *tenements { areaMeters = append(areaMeters, t.Meters...) @@ -108,13 +108,16 @@ func EnabledAreaCalculate(tenements *[]calculate.PrimaryTenementStatistics, if summary != nil { summary.OverallArea = areaTotal } else { - return errors.New("summary is nil") + return nil, errors.New("summary is nil") } - return nil + return &areaTotal, nil } -// 计算基本电费分摊、调整电费分摊以及电费摊薄单价。 -func PricesCalculate(summary *calculate.Summary) error { +// ================================================================================= +// / 计算基本电费分摊、调整电费分摊以及电费摊薄单价。 +// / +// / - `summary`:核算报表的摘要信息 +func CalculatePrices(summary *calculate.Summary) error { if summary.TotalConsumption.IsZero() { return nil } @@ -131,4 +134,5 @@ func PricesCalculate(summary *calculate.Summary) error { summary.AdjustPooledPriceArea = summary.AdjustFee.Div(summary.OverallArea) } return nil -} \ No newline at end of file + +} diff --git a/service/calculate/tenement.go b/service/calculate/tenement.go index 9bc9b74..1b84bd9 100644 --- a/service/calculate/tenement.go +++ b/service/calculate/tenement.go @@ -14,9 +14,9 @@ import ( ) // 核算园区中的全部商户表计电量用电 -func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, - PeriodEnd time.Time, meterDetails []*model.MeterDetail, - summary calculate.Summary) ([]calculate.PrimaryTenementStatistics, error) { +func TenementMetersCalculate(report *model.ReportIndex, + PeriodStart time.Time, PeriodEnd time.Time, + meterDetails []*model.MeterDetail, summary calculate.Summary) ([]calculate.PrimaryTenementStatistics, error) { tenements, err := repository.CalculateRepository.GetAllTenements(report.Id) if err != nil { fmt.Println("tenement 0", err) @@ -72,7 +72,7 @@ func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, return tenementReports, nil } -//TODO: 2023.08.02 此方法未完成此方法主要用于。确定指定商户在指定时间段内的所有表计读数(完成) +// TODO: 2023.08.02 此方法未完成此方法主要用于。确定指定商户在指定时间段内的所有表计读数(完成) func determineTenementConsumptions(tenement model.Tenement, relatedMeters []model.TenementMeter, periodStart time.Time, periodEnd time.Time, currentTermReadings []model.MeterReading, lastPeriodReadings []model.MeterReading, @@ -183,7 +183,7 @@ func getMeterDetail(meterDetails []*model.MeterDetail, code string) (model.Meter 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) { diff --git a/service/calculate/wattCost.go b/service/calculate/wattCost.go index 113eaab..f9f1d57 100644 --- a/service/calculate/wattCost.go +++ b/service/calculate/wattCost.go @@ -1,6 +1,7 @@ package calculate import ( + "electricity_bill_calc/global" "electricity_bill_calc/model/calculate" "electricity_bill_calc/repository" "fmt" @@ -73,23 +74,95 @@ func MainCalculateProcess(rid string) { } // 计算所有已经启用的商铺面积总和,仅计算所有未迁出的商户的所有表计对应的商铺面积。 - err = EnabledAreaCalculate(&tenementReports, &summary) + _, err = EnabledAreaCalculate(&tenementReports, &summary) if err != nil { fmt.Println("10", err) return } - err = PricesCalculate(&summary) + err = CalculatePrices(&summary) if err != nil { fmt.Println("11", err) return } - //为获取值初始化一个空的,合并分支时可忽略 - var meters MeterMap + //=========================================================================== + // 计算基本电费分摊、调整电费分摊、电费摊薄单价。 + err = CalculatePrices(&summary) + // 收集目前所有已经处理的表计,统一对其进行摊薄计算。 + meters, err := CollectMeters(tenementReports, poolingMetersReports, parkMetersReports) + if err != nil { + fmt.Println("12", err) + return + } // 计算商户的合计电费信息,并归总与商户相关联的表计记录 tenementCharges := TenementChargeCalculate(tenementReports, summary, meters) - fmt.Println(meterRelations, poolingMetersReports, tenementCharges) + // 根据核算报表中设置的摊薄内容,逐个表计进行计算 + err = CalculateBasicPooling(report, &summary, &meters) + if err != nil { + fmt.Println("13", err) + return + } + err = CalculateAdjustPooling(*report, summary, meters) + if err != nil { + fmt.Println("14", err) + return + } + err = CalculateLossPooling(*report, summary, meters) + if err != nil { + fmt.Println("15", err) + return + } + // 计算所有商户类型表计的全周期电量,并根据全周期电量计算共用过同一表计的商户的二次分摊比例。 + _, err = CalculateTenementConsumptions(meters) + if err != nil { + fmt.Println("16", err) + return + } + err = CalculateTenementPoolings(*report, summary, meters, meterRelations) + if err != nil { + fmt.Println("17", err) + return + } + // 计算商户的合计电费信息,并归总与商户相关联的表计记录 + tenementCharges = TenementChargeCalculate(tenementReports, summary, meters) + + // 从此处开始向数据库保存全部计算结果。 + ctx, cancel := global.TimeoutContext() + defer cancel() + tx, _ := global.DB.Begin(ctx) + err = repository.CalculateRepository.ClearReportContent(tx, report.Id) + if err != nil { + tx.Rollback(ctx) + fmt.Println("18", err) + + } + + err = SaveSummary(tx, summary) + if err != nil { + tx.Rollback(ctx) + fmt.Println("19", err) + + } + err = SavePublics(tx, *report, meters) + if err != nil { + tx.Rollback(ctx) + fmt.Println("20", err) + + } + err = SavePoolings(tx, *report, meters, meterRelations) + if err != nil { + tx.Rollback(ctx) + fmt.Println("21", err) + + } + err = SaveTenements(tx, *report, tenementReports, tenementCharges) + if err != nil { + tx.Rollback(ctx) + fmt.Println("22", err) + + } + tx.Commit(ctx) } diff --git a/service/synchronize.go b/service/synchronize.go new file mode 100644 index 0000000..bd2a810 --- /dev/null +++ b/service/synchronize.go @@ -0,0 +1,51 @@ +package service + +import ( + "electricity_bill_calc/global" + "electricity_bill_calc/logger" + "electricity_bill_calc/repository" + "electricity_bill_calc/vo" + "github.com/doug-martin/goqu/v9" + "go.uber.org/zap" +) + +type _SynchronizeService struct { + log *zap.Logger + ds goqu.DialectWrapper +} + +var SynchronizeService = _SynchronizeService{ + log: logger.Named("Service", "Synchronize"), + ds: goqu.Dialect("postgres"), +} + +func (ss _SynchronizeService) CreateSynchronizeConfiguration(userId string, form *vo.SynchronizeConfigurationCreateForm) error { + ss.log.Info("创建一条新的同步配置", zap.String("user id", userId)) + ctx, cancel := global.TimeoutContext() + defer cancel() + tx, err := global.DB.Begin(ctx) + if err != nil { + ss.log.Error("无法启动数据库事务。", zap.Error(err)) + return err + } + ok, err := repository.SynchronizeRepository.CreateSynchronizeConfiguration(tx, ctx, userId, form) + if err != nil { + ss.log.Error("无法创建新的同步配置。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + if !ok { + ss.log.Error("数据库未能记录新的同步配置。") + tx.Rollback(ctx) + return err + } + + err = tx.Commit(ctx) + if err != nil { + ss.log.Error("未能成功提交数据库事务。", zap.Error(err)) + tx.Rollback(ctx) + return err + } + return nil + +} diff --git a/service/user.go b/service/user.go index 2474921..08824b9 100644 --- a/service/user.go +++ b/service/user.go @@ -80,7 +80,9 @@ func (us _UserService) ProcessEnterpriseUserLogin(username, password string) (*m us.log.Error("处理企业用户登录失败。", zap.String("username", username), zap.Error(err)) return nil, err } + token, _ := uuid.NewRandom() //生成uuid作为会话的token使用 + userSession := &model.Session{ Uid: user.Id, Name: user.Username, diff --git a/settings.yaml b/settings.yaml index 9968ebe..fb5ec11 100644 --- a/settings.yaml +++ b/settings.yaml @@ -12,14 +12,16 @@ Server: ReadTimeout: 60 WriteTimeout: 60 Redis: - Host: redis + Host: 192.168.88.129 Port: 6379 - Password: TmFRS0w6BIrAPA1Raj + Password: 123456 DB: 1 Service: MaxSessionLife: 2h ItemsPageSize: 20 CacheLifeTime: 5m HostSerial: 5 + BaselineLineLossRatio: - Base: 基准线损率 \ No newline at end of file + Base: 基准线损率 + diff --git a/tools/utils.go b/tools/utils.go index 325453f..10411d8 100644 --- a/tools/utils.go +++ b/tools/utils.go @@ -147,7 +147,7 @@ func NullDecimalToString(d decimal.NullDecimal, precision ...int32) *string { return lo.ToPtr(d.Decimal.StringFixedBank(precision[0])) } -//将sql.NullTime转换为*string +// 将sql.NullTime转换为*string func NullTime2PointerString(nullTime sql.NullTime) *string { var strPtr *string if nullTime.Valid { @@ -160,7 +160,7 @@ func NullTime2PointerString(nullTime sql.NullTime) *string { } } -//该方法用于将时间解析为字符串指针 +// 该方法用于将时间解析为字符串指针 func TimeToStringPtr(t *time.Time) *string { if t == nil { return nil @@ -169,4 +169,3 @@ func TimeToStringPtr(t *time.Time) *string { timeStr := t.Format("2006-01-02 15:04:05") return &timeStr } - diff --git a/vo/synchronize.go b/vo/synchronize.go new file mode 100644 index 0000000..39edecb --- /dev/null +++ b/vo/synchronize.go @@ -0,0 +1,29 @@ +package vo + +type SynchronizeConfiguration struct { + CollectAt string `json:"collectAt"` // 采集时间,格式:HH:mm + EntID string `json:"entId"` // 企业ID + Imrs string `json:"imrs"` // 采集系统型号 + ImrsAccount string `json:"imrsAccount"` // 同步登录账号 + ImrsKey string `json:"imrsKey"` // 同步登录私钥,Base64或者私钥文件内容 + ImrsSecret string `json:"imrsSecret"` // 同步登录密钥,加盐双向加密 + Interval float64 `json:"interval"` // 采集周期,0:每小时,1:每日,2:每周,3:每月 + MaxRetries string `json:"maxRetries"` // 最大重试次数 + ParkID string `json:"parkId"` // 园区ID + ReadingType float64 `json:"readingType"` // 采集方式,0:自动+人工,1:自动,2:人工 + RetryAlgorithm float64 `json:"retryAlgorithm"` // 重试间隔算法,0:指数退避,1:2倍线性间隔,2:3倍线性间隔,3:固定间隔 + RetryInterval string `json:"retryInterval"` // 重试间隔,基础间隔时间,根据间隔算法不同会产生不同的间隔 +} +type SynchronizeConfigurationCreateForm struct { + CollectAt string `json:"collectAt"` // 采集时间,格式:HH:mm + Imrs string `json:"imrs"` // 采集系统型号,为空的时候表示不同步 + ImrsAccount string `json:"imrsAccount"` // 同步登录账号 + ImrsKey string `json:"imrsKey"` // 同步登录私钥,Base64或者私钥文件内容 + ImrsSecret string `json:"imrsSecret"` // 同步登录密钥,加盐双向加密 + Interval float64 `json:"interval"` // 采集周期,0:每小时,1:每日,2:每周,3:每月 + MaxRetries string `json:"maxRetries"` // 最大重试次数 + ParkID string `json:"parkId"` // 园区ID + ReadingType float64 `json:"readingType"` // 采集方式,0:自动+人工,1:自动,2:人工 + RetryAlgorithm float64 `json:"retryAlgorithm"` // 重试间隔算法,0:指数退避,1:2倍线性间隔,2:3倍线性间隔,3:固定间隔 + RetryInterval string `json:"retryInterval"` // 重试间隔,基础间隔时间,根据间隔算法不同会产生不同的间隔 +}