forked from free-lancers/electricity_bill_calc_service
enhance(meter):完成大部分表计相关的接口。
This commit is contained in:
144
service/meter.go
144
service/meter.go
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/cache"
|
||||
"electricity_bill_calc/excel"
|
||||
"electricity_bill_calc/global"
|
||||
"electricity_bill_calc/logger"
|
||||
"electricity_bill_calc/model"
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"electricity_bill_calc/vo"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/shopspring/decimal"
|
||||
@@ -108,8 +110,146 @@ func (ms _MeterService) UpdateMeterRecord(pid string, code string, form *vo.Mete
|
||||
}
|
||||
|
||||
// 处理上传的Excel格式表计档案文件,根据表号自动更新数据库
|
||||
func (ms _MeterService) BatchImportMeters(pid string, file multipart.FileHeader) error {
|
||||
return nil
|
||||
func (ms _MeterService) BatchImportMeters(pid string, file *multipart.FileHeader) ([]excel.ExcelAnalysisError, error) {
|
||||
ms.log.Info("处理上传的Excel格式表计档案文件", zap.String("park id", pid))
|
||||
ctx, cancel := global.TimeoutContext(10)
|
||||
defer cancel()
|
||||
archiveFile, err := file.Open()
|
||||
if err != nil {
|
||||
ms.log.Error("无法打开上传的Excel格式表计档案文件。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法打开上传的文件,%w", err)
|
||||
}
|
||||
analyzer, err := excel.NewMeterArchiveExcelAnalyzer(archiveFile)
|
||||
if err != nil {
|
||||
ms.log.Error("无法根据上传的 Excel 文件创建表计档案分析器。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法创建表计档案解析器,%w", err)
|
||||
}
|
||||
records, errs := analyzer.Analysis(*new(model.MeterImportRow))
|
||||
if len(errs) > 0 {
|
||||
ms.log.Error("表计档案分析器在解析上传的 Excel 文件时发生错误。", zap.Int("error count", len(errs)))
|
||||
return errs, fmt.Errorf("表计档案分析器在解析上传的 Excel 文件时发生错误。")
|
||||
}
|
||||
// 步骤1:对目前已经解析到的数据进行重复检测,记录重复内容并直接返回
|
||||
var codeStat = make(map[string]int, 0)
|
||||
for _, record := range records {
|
||||
if _, ok := codeStat[record.Code]; !ok {
|
||||
codeStat[record.Code] = 0
|
||||
}
|
||||
codeStat[record.Code]++
|
||||
}
|
||||
duplicatedCodes := make([]string, 0)
|
||||
for code, count := range codeStat {
|
||||
if count > 1 {
|
||||
duplicatedCodes = append(duplicatedCodes, code)
|
||||
}
|
||||
}
|
||||
if len(duplicatedCodes) > 0 {
|
||||
ms.log.Error("表计档案分析器在解析上传的 Excel 文件时发现重复的表计编号。", zap.Strings("duplicated codes", duplicatedCodes))
|
||||
return []excel.ExcelAnalysisError{
|
||||
{Row: 0, Col: 0, Err: excel.AnalysisError{Err: fmt.Errorf("表计档案分析器在解析上传的 Excel 文件时发现重复的表计编号。(%s)", strings.Join(duplicatedCodes, ", "))}},
|
||||
}, fmt.Errorf("表计档案分析器在解析上传的 Excel 文件时发现重复的表计编号。(%s)", strings.Join(duplicatedCodes, ", "))
|
||||
}
|
||||
// 步骤2:获取指定园区下的所有建筑信息
|
||||
buildings, err := repository.ParkRepository.RetrieveParkBuildings(pid)
|
||||
if err != nil {
|
||||
ms.log.Error("无法获取指定园区下的所有建筑信息。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法获取指定园区下的所有建筑信息,%w", err)
|
||||
}
|
||||
buildingNames := lo.Map(buildings, func(element *model.ParkBuilding, _ int) string {
|
||||
return element.Name
|
||||
})
|
||||
// 步骤2.1:获取表计档案中出现的所有建筑,并对档案中新出现的建筑进行创建操作
|
||||
unexistsBuildingNames := make([]string, 0)
|
||||
for _, record := range records {
|
||||
if !lo.Contains(buildingNames, *record.Building) {
|
||||
unexistsBuildingNames = append(unexistsBuildingNames, *record.Building)
|
||||
}
|
||||
}
|
||||
tx, err := global.DB.Begin(ctx)
|
||||
if err != nil {
|
||||
ms.log.Error("无法在自动导入建筑阶段启动数据库事务。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法在自动导入建筑阶段启动数据库事务,%w", err)
|
||||
}
|
||||
for _, name := range unexistsBuildingNames {
|
||||
_, err := repository.ParkRepository.CreateParkBuildingWithTransaction(tx, ctx, pid, name, nil)
|
||||
if err != nil {
|
||||
ms.log.Error("无法在自动导入建筑阶段创建新的建筑。", zap.String("building name", name), zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法在自动导入建筑阶段创建新的建筑,%w", err)
|
||||
}
|
||||
}
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
ms.log.Error("无法在自动导入建筑阶段提交数据库事务。", zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法在自动导入建筑阶段提交数据库事务,%w", err)
|
||||
}
|
||||
buildings, err = repository.ParkRepository.RetrieveParkBuildings(pid)
|
||||
if err != nil {
|
||||
ms.log.Error("无法重新获取指定园区下的所有建筑信息。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法重新获取指定园区下的所有建筑信息,%w", err)
|
||||
}
|
||||
// 步骤2.3:检测并替换表计档案中的建筑ID
|
||||
for _, record := range records {
|
||||
for _, building := range buildings {
|
||||
if building.Name == *record.Building {
|
||||
record.Building = &building.Id
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// 步骤3:启动数据库事务,直接构建表计插入语句,但提供On Conflict Do Update功能
|
||||
tx, err = global.DB.Begin(ctx)
|
||||
if err != nil {
|
||||
ms.log.Error("无法启动数据插入阶段的数据库事务。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法启动数据插入阶段的数据库事务,%w", err)
|
||||
}
|
||||
meterCreationForms := lo.Map(records, func(element model.MeterImportRow, _ int) vo.MeterCreationForm {
|
||||
return vo.MeterCreationForm{
|
||||
Code: element.Code,
|
||||
Address: element.Address,
|
||||
MeterType: element.MeterType,
|
||||
Ratio: element.Ratio,
|
||||
Seq: element.Seq,
|
||||
Enabled: true,
|
||||
Building: element.Building,
|
||||
OnFloor: element.OnFloor,
|
||||
Area: element.Area,
|
||||
MeterReadingForm: vo.MeterReadingForm{
|
||||
ReadAt: &element.ReadAt,
|
||||
Overall: element.Overall,
|
||||
Critical: element.Critical.Decimal,
|
||||
Peak: element.Peak.Decimal,
|
||||
Flat: element.Flat.Decimal,
|
||||
Valley: element.Valley.Decimal,
|
||||
},
|
||||
}
|
||||
})
|
||||
for _, record := range meterCreationForms {
|
||||
_, err := repository.MeterRepository.CreateOrUpdateMeter(tx, ctx, pid, record)
|
||||
if err != nil {
|
||||
ms.log.Error("无法在数据插入阶段创建或更新表计。", zap.String("meter code", record.Code), zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法在数据插入阶段创建或更新表计,%w", err)
|
||||
}
|
||||
}
|
||||
// 步骤5:将全部抄表信息保存进入数据库
|
||||
for _, record := range meterCreationForms {
|
||||
_, err := repository.MeterRepository.RecordReading(tx, ctx, pid, record.Code, record.MeterType, record.Ratio, &record.MeterReadingForm)
|
||||
if err != nil {
|
||||
ms.log.Error("无法在数据插入阶段保存抄表信息。", zap.String("meter code", record.Code), zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法在数据插入阶段保存抄表信息,%w", err)
|
||||
}
|
||||
}
|
||||
// 步骤6:执行事务,更新数据库
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
ms.log.Error("无法在数据插入阶段提交数据库事务。", zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法在数据插入阶段提交数据库事务,%w", err)
|
||||
}
|
||||
return make([]excel.ExcelAnalysisError, 0), nil
|
||||
}
|
||||
|
||||
// 更换系统中的表计
|
||||
|
Reference in New Issue
Block a user