forked from free-lancers/electricity_bill_calc_service
enhance(meter):基本完成表计抄表记录上传解析,待测。
This commit is contained in:
117
service/meter.go
117
service/meter.go
@@ -686,28 +686,115 @@ func (ms _MeterService) RecordReading(pid, meterCode string, form *vo.MeterReadi
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取指定园区的全部待抄表计列表,并将其输出到Excel文件模板中,提供生成文件的二进制内容
|
||||
func (ms _MeterService) GenerateParkMeterReadingTemplate(pid string, meters []*model.SimpleMeterDocument) ([]byte, error) {
|
||||
// 步骤1:复制公用模板文件到临时文件夹,文件以园区ID命名
|
||||
|
||||
// 步骤2:打开复制后的园区文件
|
||||
// 步骤3:获取园区中需要抄表的表计列表
|
||||
// 步骤4:循环表计列表,将表计信息写入到Excel文件中
|
||||
// 步骤5:将生成的临时文件的具体二进制内容返回给调用者
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// 处理上传的Excel格式的表计抄表记录,所有满足审查条件的记录都将被保存到数据库中。
|
||||
// 无论峰谷表计还是普通表计,只要抄表记录中不存在峰谷数据,都将自动使用平段配平。
|
||||
func (ms _MeterService) BatchImportReadings(pid string, uploadContent []byte) error {
|
||||
func (ms _MeterService) BatchImportReadings(pid string, file *multipart.FileHeader) ([]excel.ExcelAnalysisError, error) {
|
||||
ms.log.Info("处理上传的Excel格式的表计抄表记录", zap.String("park id", pid))
|
||||
ctx, cancel := global.TimeoutContext()
|
||||
defer cancel()
|
||||
// 步骤1:将解析到的数据转换成创建表单数据
|
||||
activeFile, err := file.Open()
|
||||
if err != nil {
|
||||
ms.log.Error("无法打开上传的抄表数据文件。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法打开上传的抄表数据文件,%w", err)
|
||||
}
|
||||
analyzer, err := excel.NewMeterReadingsExcelAnalyzer(activeFile)
|
||||
if err != nil {
|
||||
ms.log.Error("无法根据上传的 Excel 文件创建表计抄表数据解析器。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法根据上传的 Excel 文件创建表计抄表数据解析器,%w", err)
|
||||
}
|
||||
records, errs := analyzer.Analysis(*new(model.ReadingImportRow))
|
||||
if len(errs) > 0 {
|
||||
ms.log.Error("表计抄表数据解析器在解析上传的 Excel 文件时发生错误。", zap.Int("error count", len(errs)))
|
||||
return errs, fmt.Errorf("表计抄表数据解析器在解析上传的 Excel 文件时发生错误。")
|
||||
}
|
||||
ms.log.Debug("已经解析到的上传数据", zap.Any("records", records))
|
||||
// 步骤2:对目前已经解析到的数据进行合法性检测,检测包括表计编号在同一抄表时间是否重复
|
||||
var collectRecords = make(map[types.DateTime][]string, 0)
|
||||
for _, record := range records {
|
||||
if _, ok := collectRecords[record.ReadAt]; !ok {
|
||||
collectRecords[record.ReadAt] = []string{}
|
||||
}
|
||||
collectRecords[record.ReadAt] = append(collectRecords[record.ReadAt], record.Code)
|
||||
}
|
||||
for readAt, codes := range collectRecords {
|
||||
valCounts := lo.CountValues(codes)
|
||||
for code, count := range valCounts {
|
||||
if count > 1 {
|
||||
errs = append(errs, excel.ExcelAnalysisError{
|
||||
Row: 0,
|
||||
Col: 0,
|
||||
Err: excel.AnalysisError{
|
||||
Err: fmt.Errorf("表计编号 %s 在同一抄表时间 %s 内重复出现 %d 次", code, readAt.ToString(), count),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
ms.log.Error("表计抄表数据解析器在解析上传的 Excel 文件时发生错误。", zap.Int("error count", len(errs)))
|
||||
return errs, fmt.Errorf("表计抄表数据解析器在解析上传的 Excel 文件时发生错误。")
|
||||
}
|
||||
// 步骤3:从数据库中获取当前园区中已有的表计编号
|
||||
meters, err := repository.MeterRepository.AllMeters(pid)
|
||||
if err != nil {
|
||||
ms.log.Error("无法从数据库中获取当前园区中已有的表计编号。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法从数据库中获取当前园区中已有的表计编号,%w", err)
|
||||
}
|
||||
// 步骤4.0:启动数据库事务
|
||||
tx, err := global.DB.Begin(ctx)
|
||||
if err != nil {
|
||||
ms.log.Error("无法启动数据库事务。", zap.Error(err))
|
||||
return make([]excel.ExcelAnalysisError, 0), fmt.Errorf("无法启动数据库事务,%w", err)
|
||||
}
|
||||
// 步骤4.1:对比检查数据库中的表计编号与上传文件中的表计编号是否存在差异。非差异内容将直接保存
|
||||
// 步骤4.1.1:抄表的表计在数据库中已经存在,可以直接保存起数据。
|
||||
// 步骤4.1.2:抄表表计在数据库中不存在,需要将其记录进入错误。
|
||||
for row, record := range records {
|
||||
meter, exists := lo.Find(meters, func(element *model.MeterDetail) bool {
|
||||
return element.Code == record.Code
|
||||
})
|
||||
if exists {
|
||||
// 步骤4.1.1:抄表的表计在数据库中已经存在,可以直接保存起数据。
|
||||
_, err := repository.MeterRepository.RecordReading(tx, ctx, pid, record.Code, meter.MeterType, meter.Ratio, &vo.MeterReadingForm{
|
||||
ReadAt: lo.ToPtr(record.ReadAt),
|
||||
Overall: record.Overall,
|
||||
Critical: record.Critical.Decimal,
|
||||
Peak: record.Peak.Decimal,
|
||||
Flat: record.Overall.Sub(record.Peak.Decimal).Sub(record.Valley.Decimal).Sub(record.Critical.Decimal),
|
||||
Valley: record.Valley.Decimal,
|
||||
})
|
||||
if err != nil {
|
||||
ms.log.Error("无法在数据插入阶段保存抄表信息。", zap.String("meter code", record.Code), zap.Error(err))
|
||||
errs = append(errs, excel.ExcelAnalysisError{
|
||||
Row: row + 1,
|
||||
Col: 0,
|
||||
Err: excel.AnalysisError{
|
||||
Err: fmt.Errorf("无法在数据插入阶段保存抄表信息,%w", err),
|
||||
},
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// 步骤4.1.2:抄表表计在数据库中不存在,需要将其记录进入错误。
|
||||
errs = append(errs, excel.ExcelAnalysisError{
|
||||
Row: row + 1,
|
||||
Col: 0,
|
||||
Err: excel.AnalysisError{
|
||||
Err: fmt.Errorf("表计编号 %s 在系统中不存在", record.Code),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
// 步骤4.3:如果批处理过程中存在错误,撤销全部导入动作。
|
||||
if len(errs) > 0 {
|
||||
ms.log.Error("表计抄表数据解析器在解析上传的 Excel 文件时发生错误。", zap.Int("error count", len(errs)))
|
||||
tx.Rollback(ctx)
|
||||
return errs, fmt.Errorf("表计抄表数据解析器在解析上传的 Excel 文件时发生错误。")
|
||||
}
|
||||
// 步骤5:执行事务,更新数据库,获取完成更改的行数。
|
||||
return nil
|
||||
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