electricity_bill_calc_service/service/tenement.go

242 lines
9.6 KiB
Go

package service
import (
"electricity_bill_calc/global"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/repository"
"electricity_bill_calc/vo"
"fmt"
"github.com/samber/lo"
"go.uber.org/zap"
)
type _TenementService struct {
log *zap.Logger
}
var TenementService = _TenementService{
log: logger.Named("Service", "Tenement"),
}
// 列出指定商户下的全部计量表计,不包含公摊表计
func (ts _TenementService) ListMeter(pid, tid string) ([]*model.MeterDetail, error) {
ts.log.Info("列出指定商户下的全部表计", zap.String("Park", pid), zap.String("Tenement", tid))
meterCodes, err := repository.TenementRepository.ListMeterCodesBelongsTo(pid, tid)
if err != nil {
ts.log.Error("列出指定商户下的全部表计失败,未能获取属于商户的表计编号", zap.Error(err))
return make([]*model.MeterDetail, 0), err
}
meters, err := repository.MeterRepository.ListMetersByIDs(pid, meterCodes)
if err != nil {
ts.log.Error("列出指定商户下的全部表计失败,未能获取表计编号对应的表计详细信息", zap.Error(err))
return make([]*model.MeterDetail, 0), err
}
return meters, nil
}
// 增加一个新的商户
func (ts _TenementService) CreateTenementRecord(pid string, creationForm *vo.TenementCreationForm) error {
ts.log.Info("增加一个新的商户", zap.String("Park", pid), zap.Any("Form", creationForm))
ctx, cancel := global.TimeoutContext()
defer cancel()
tx, err := global.DB.Begin(ctx)
if err != nil {
ts.log.Error("增加一个新商户失败的,未能启动数据库事务", zap.Error(err))
return fmt.Errorf("未能启动数据库事务,%w", err)
}
err = repository.TenementRepository.AddTenement(tx, ctx, pid, creationForm)
if err != nil {
ts.log.Error("增加一个新商户失败的,未能增加商户记录", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能增加商户记录,%w", err)
}
err = tx.Commit(ctx)
if err != nil {
ts.log.Error("增加一个新商户失败的,未能提交数据库事务", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能提交数据库事务,%w", err)
}
return nil
}
// 向商户绑定一个新表计
func (ts _TenementService) BindMeter(pid, tid, meterCode string, reading *vo.MeterReadingForm) error {
ts.log.Info("向商户绑定一个新表计", zap.String("Park", pid), zap.String("Tenement", tid), zap.String("Meter", meterCode))
ctx, cancel := global.TimeoutContext()
defer cancel()
tx, err := global.DB.Begin(ctx)
if err != nil {
ts.log.Error("向商户绑定一个新表计失败,未能启动数据库事务", zap.Error(err))
return fmt.Errorf("未能启动数据库事务,%w", err)
}
meterDetail, err := repository.MeterRepository.FetchMeterDetail(pid, meterCode)
if err != nil {
ts.log.Error("向商户绑定一个新表计失败,未能获取表计详细信息", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能获取表计详细信息,%w", err)
}
err = repository.TenementRepository.BindMeter(tx, ctx, pid, tid, meterCode,reading)
if err != nil {
ts.log.Error("向商户绑定一个新表计失败,未能绑定表计", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能绑定表计,%w", err)
}
ok, err := repository.MeterRepository.RecordReading(tx, ctx, pid, meterCode, meterDetail.MeterType, meterDetail.Ratio, reading)
if err != nil {
ts.log.Error("向商户绑定一个新表计失败,记录表计读数出现错误", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("记录表计读数出现错误,%w", err)
}
if !ok {
ts.log.Error("向商户绑定一个新表计失败,记录表计读数失败")
tx.Rollback(ctx)
return fmt.Errorf("记录表计读数失败")
}
err = tx.Commit(ctx)
if err != nil {
ts.log.Error("向商户绑定一个新表计失败,未能提交数据库事务", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能提交数据库事务,%w", err)
}
return nil
}
// 解除商户与指定表计的绑定
func (ts _TenementService) UnbindMeter(pid, tid, meterCode string, reading *vo.MeterReadingForm) error {
ts.log.Info("解除商户与指定表计的绑定", zap.String("Park", pid), zap.String("Tenement", tid), zap.String("Meter", meterCode))
ctx, cancel := global.TimeoutContext()
defer cancel()
tx, err := global.DB.Begin(ctx)
if err != nil {
ts.log.Error("解除商户与指定表计的绑定失败,未能启动数据库事务", zap.Error(err))
return fmt.Errorf("未能启动数据库事务,%w", err)
}
meterDetail, err := repository.MeterRepository.FetchMeterDetail(pid, meterCode)
if err != nil {
ts.log.Error("解除商户与指定表计的绑定失败,未能获取表计详细信息", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能获取表计详细信息,%w", err)
}
err = repository.TenementRepository.UnbindMeter(tx, ctx, pid, tid, meterCode)
if err != nil {
ts.log.Error("解除商户与指定表计的绑定失败,未能解除绑定", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能解除绑定,%w", err)
}
ok, err := repository.MeterRepository.RecordReading(tx, ctx, pid, meterCode, meterDetail.MeterType, meterDetail.Ratio, reading)
if err != nil {
ts.log.Error("解除商户与指定表计的绑定失败,记录表计读数出现错误", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("记录表计读数出现错误,%w", err)
}
if !ok {
ts.log.Error("解除商户与指定表计的绑定失败,记录表计读数失败")
tx.Rollback(ctx)
return fmt.Errorf("记录表计读数失败")
}
err = tx.Commit(ctx)
if err != nil {
ts.log.Error("解除商户与指定表计的绑定失败,未能提交数据库事务", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能提交数据库事务,%w", err)
}
return nil
}
// 迁出指定商户
func (ts _TenementService) MoveOutTenement(pid, tid string, reading []*vo.MeterReadingFormWithCode) error {
ts.log.Info("迁出指定商户", zap.String("Park", pid), zap.String("Tenement", tid))
ctx, cancel := global.TimeoutContext()
defer cancel()
tx, err := global.DB.Begin(ctx)
if err != nil {
ts.log.Error("迁出指定商户失败,未能启动数据库事务", zap.Error(err))
return fmt.Errorf("未能启动数据库事务,%w", err)
}
meterCodes, err := repository.TenementRepository.ListMeterCodesBelongsTo(pid, tid)
if err != nil {
ts.log.Error("迁出指定商户失败,未能获取属于商户的表计编号", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能获取属于商户的表计编号,%w", err)
}
meters, err := repository.MeterRepository.ListMetersByIDs(pid, meterCodes)
if err != nil {
ts.log.Error("迁出指定商户失败,未能获取表涉及计编号对应的表计详细信息", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能获取涉及表计编号对应的表计详细信息,%w", err)
}
for _, meterCode := range meterCodes {
meterDetail, exists := lo.Find(meters, func(m *model.MeterDetail) bool {
return m.Code == meterCode
})
if !exists {
ts.log.Error("迁出指定商户失败,找不到指定表计的详细信息", zap.String("Meter", meterCode))
tx.Rollback(ctx)
return fmt.Errorf("找不到指定表计[%s]的详细信息,%w", meterCode, err)
}
if meterDetail.MeterType != model.METER_INSTALLATION_TENEMENT {
ts.log.Error("迁出指定商户失败,需要解绑的表计不是商户表计", zap.String("Meter", meterCode))
tx.Rollback(ctx)
return fmt.Errorf("需要解绑的表计[%s]不是商户表计,%w", meterCode, err)
}
reading, exists := lo.Find(reading, func(r *vo.MeterReadingFormWithCode) bool {
return r.Code == meterCode
})
if !exists {
ts.log.Error("迁出指定商户失败,找不到指定表计的抄表信息", zap.String("Meter", meterCode))
tx.Rollback(ctx)
return fmt.Errorf("找不到指定表计[%s]的抄表信息,%w", meterCode, err)
}
if reading.Validate() {
ts.log.Error("迁出指定商户失败,表计读数不能正确配平,尖锋电量、峰电量、谷电量之和超过总电量。", zap.String("Meter", meterCode))
tx.Rollback(ctx)
return fmt.Errorf("表计[%s]读数不能正确配平,尖锋电量、峰电量、谷电量之和超过总电量。", meterCode)
}
err = repository.TenementRepository.UnbindMeter(tx, ctx, pid, tid, meterCode)
if err != nil {
ts.log.Error("迁出指定商户失败,未能解除表计绑定", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能解除表计[%s]绑定,%w", meterCode, err)
}
ok, err := repository.MeterRepository.RecordReading(tx, ctx, pid, meterCode, meterDetail.MeterType, meterDetail.Ratio, &reading.MeterReadingForm)
if err != nil {
ts.log.Error("迁出指定商户失败,记录表计抄表信息出现错误", zap.String("Meter", meterCode), zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("记录表计[%s]抄表信息出现错误,%w", meterCode, err)
}
if !ok {
ts.log.Error("迁出指定商户失败,记录表计抄表数据失败", zap.String("Meter", meterCode))
tx.Rollback(ctx)
return fmt.Errorf("记录表计[%s]抄表数据失败", meterCode)
}
}
err = repository.TenementRepository.MoveOut(tx, ctx, pid, tid)
if err != nil {
ts.log.Error("迁出指定商户失败,未能迁出指定商户", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能迁出指定商户,%w", err)
}
err = tx.Commit(ctx)
if err != nil {
ts.log.Error("迁出指定商户失败,未能提交数据库事务", zap.Error(err))
tx.Rollback(ctx)
return fmt.Errorf("未能提交数据库事务,%w", err)
}
return nil
}