fix(#10): 修复创建报表错误

This commit is contained in:
ZiHangQin 2023-08-14 10:05:09 +08:00
parent 559c2d439d
commit 845bd75348
7 changed files with 199 additions and 171 deletions

View File

@ -24,23 +24,23 @@ type Pooling struct {
}
type Meter struct {
Code string
Detail model.MeterDetail
CoveredArea decimal.Decimal
LastTermReading *Reading
CurrentTermReading *Reading
Overall model.ConsumptionUnit
Critical model.ConsumptionUnit
Peak model.ConsumptionUnit
Flat model.ConsumptionUnit
Valley model.ConsumptionUnit
AdjustLoss model.ConsumptionUnit
PooledBasic model.ConsumptionUnit
PooledAdjust model.ConsumptionUnit
PooledLoss model.ConsumptionUnit
PooledPublic model.ConsumptionUnit
SharedPoolingProportion decimal.Decimal
Poolings []*Pooling
Code string `json:"code"`
Detail model.MeterDetail `json:"detail"`
CoveredArea decimal.Decimal `json:"covered_area"`
LastTermReading *Reading `json:"last_term_reading"`
CurrentTermReading *Reading `json:"current_term_reading"`
Overall model.ConsumptionUnit `json:"overall"`
Critical model.ConsumptionUnit `json:"critical"`
Peak model.ConsumptionUnit `json:"peak"`
Flat model.ConsumptionUnit `json:"flat"`
Valley model.ConsumptionUnit `json:"valley"`
AdjustLoss model.ConsumptionUnit `json:"adjust_loss"`
PooledBasic model.ConsumptionUnit `json:"pooled_basic"`
PooledAdjust model.ConsumptionUnit `json:"pooled_adjust"`
PooledLoss model.ConsumptionUnit `json:"pooled_loss"`
PooledPublic model.ConsumptionUnit `json:"pooled_public"`
SharedPoolingProportion decimal.Decimal `json:"shared_pooling_proportion"`
Poolings []*Pooling `json:"poolings"`
}
type PrimaryTenementStatistics struct {

View File

@ -1,6 +1,7 @@
package repository
import (
"context"
"electricity_bill_calc/global"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
@ -322,43 +323,47 @@ func (cr _CalculateRepository) ClearReportContent(tx pgx.Tx, rid string) error {
return nil
}
func (cr _CalculateRepository) SaveReportPublics(tx pgx.Tx, rid string, meters []calculate.Meter) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
func (cr _CalculateRepository) SaveReportPublics(tx pgx.Tx, ctx context.Context, rid string, meters []calculate.Meter) error {
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{}{
// 准备插入表达式
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",
)
// 添加值到插入表达式中
overall,_ := json.Marshal(meter.Overall)
criyical,_ := json.Marshal(meter.Critical)
peak,_ := json.Marshal(meter.Peak)
flat,_ := json.Marshal(meter.Flat)
valley,_ := json.Marshal(meter.Valley)
adjustLoss,_ := json.Marshal(meter.AdjustLoss)
insertExpr = insertExpr.Vals(goqu.Vals{
rid,
meter.Code,
meter.Overall.Fee,
meter.Critical.Fee,
meter.Peak.Fee,
meter.Flat.Fee,
meter.Valley.Fee,
meter.AdjustLoss.Fee,
overall,
criyical,
peak,
flat,
valley,
adjustLoss,
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)
// 执行插入语句
inserSql, insertArgs, _ := insertExpr.ToSQL()
fmt.Println(inserSql)
_, err := tx.Exec(ctx, inserSql, insertArgs...)
if err != nil {
_ = tx.Rollback(ctx)
return fmt.Errorf("保存报表核算概要失败: %w", err)
}
}
return nil
@ -454,10 +459,15 @@ func (cr _CalculateRepository) SaveReportPoolings(tx pgx.Tx,
if err != nil {
return err
}
overall,_ := json.Marshal(meter.Overall)
criyical,_ := json.Marshal(meter.Critical)
peak,_ := json.Marshal(meter.Peak)
flat,_ := json.Marshal(meter.Flat)
valley,_ := json.Marshal(meter.Valley)
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})
Vals(goqu.Vals{rid, meter.Code, overall, criyical, peak, flat, valley, meter.CoveredArea, submetersJSON})
insertQueries = append(insertQueries, *insertQuery)
}

View File

@ -3,7 +3,6 @@ package calculate
import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"errors"
"fmt"
"github.com/shopspring/decimal"
@ -189,147 +188,169 @@ func CalculateTenementPoolings(report model.ReportIndex, summary calculate.Summa
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
}
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
pooleds := make([]struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}, 0)
for _, relation := range meterRelations {
if relation.SlaveMeter == meter.Code {
key := Key{
Code: relation.MasterMeter,
Code: relation.MasterMeter,
TenementID: "",
}
parentMeter, ok := meters[key]
if !ok {
// 处理未找到父级表计的情况
continue
}
// 计算分摊电量和父级表电量
pooledAmount := meter.Detail.Area.Decimal.Div(parentMeter.CoveredArea).Mul(parentMeter.Overall.Amount).Mul(meter.SharedPoolingProportion)
area := parentMeter.CoveredArea
coveredArea := area
overall := parentMeter.Overall
proportion := meter.SharedPoolingProportion
electricity := area.InexactFloat64() / coveredArea.InexactFloat64() * overall.Amount.InexactFloat64() * proportion.InexactFloat64()
pooleds = append(pooleds, struct {
PooledAmount decimal.Decimal
ParentAmount decimal.Decimal
ParentCode string
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}{
PooledAmount: pooledAmount,
ParentAmount: parentMeter.Overall.Amount,
ParentCode: parentMeter.Code,
Electricity: decimal.NewFromFloat(electricity),
ParentElectricity: overall.Amount,
Code: 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)
consumptions := 0.00
total := 0.00
var pooled []*calculate.Pooling
// 更新父级表计的公摊分摊信息
key := Key{
Code: p.ParentCode,
for _, p := range pooleds {
consumptions += p.Electricity.InexactFloat64()
total += p.ParentElectricity.InexactFloat64()
unit := model.ConsumptionUnit{
Amount: p.Electricity,
Fee: decimal.NewFromFloat(p.Electricity.InexactFloat64() * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.Zero,
}
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
// 创建并更新分摊信息
if p.ParentElectricity != decimal.Zero {
unit.Proportion = decimal.NewFromFloat(p.Electricity.InexactFloat64() / p.ParentElectricity.InexactFloat64())
}
pooling := calculate.Pooling{
Code: p.ParentCode,
Detail: model.ConsumptionUnit{
Amount: poolingAmount,
Fee: fee,
Price: summary.Overall.Price,
Proportion: proportion,
},
Code: p.Code,
Detail: unit,
}
meter.Poolings = append(meter.Poolings, &pooling)
pooled = append(pooled, &pooling)
}
meter.PooledPublic = model.ConsumptionUnit{
Amount: decimal.NewFromFloat(consumptions),
Fee: decimal.NewFromFloat(consumptions * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.NewFromFloat(consumptions / total),
}
meter.Poolings = pooled
}
}
case model.POOLING_MODE_CONSUMPTION:
case model.PRICING_POLICY_CONSUMPTION:
for _, meter := range meters {
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
var pooled []struct {
PooledAmount decimal.Decimal
ParentAmount decimal.Decimal
ParentCode string
}
pooled := make([]struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}, 0)
for _, relation := range meterRelations {
if relation.SlaveMeter == meter.Code {
parentMeter, ok := meters[Key{Code: relation.MasterMeter}]
key := Key{
Code: relation.MasterMeter,
TenementID: "",
}
parentMeter, ok := meters[key]
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)
overall := parentMeter.Overall
if overall.Amount == decimal.Zero {
pooled = append(pooled, struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}{
Electricity: decimal.Zero,
ParentElectricity: decimal.Zero,
Code: parentMeter.Code,
})
} else { //TODO: 2023.08.11 计算处理流程修改到此处,以下问题未作修改还存在问题
electricity := meter.Overall.Amount.InexactFloat64() / overall.Amount.InexactFloat64() * overall.Amount.InexactFloat64()
pooled = append(pooled, struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}{
Electricity: decimal.NewFromFloat(electricity),
ParentElectricity: overall.Amount,
Code: parentMeter.Code,
})
}
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
consumptions := decimal.Zero.InexactFloat64()
total := decimal.Zero.InexactFloat64()
var poolings []*calculate.Pooling
for _, p := range pooled {
consumptions = consumptions.Add(p.PooledAmount)
total = total.Add(p.ParentAmount)
}
consumptions += p.Electricity.InexactFloat64()
total += p.ParentElectricity.InexactFloat64()
// 计算并更新公摊分摊信息
for _, p := range pooled {
poolingAmount := p.PooledAmount
proportion := p.PooledAmount.Div(p.ParentAmount)
fee := poolingAmount.Mul(summary.Overall.Price)
unit := model.ConsumptionUnit{
Amount: p.Electricity,
Fee: decimal.NewFromFloat(p.Electricity.InexactFloat64() * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.Zero,
}
// 更新父级表计的公摊分摊信息
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
if p.ParentElectricity != decimal.Zero {
unit.Proportion = decimal.NewFromFloat(p.Electricity.InexactFloat64() / p.ParentElectricity.InexactFloat64())
}
// 创建并更新分摊信息
pooling := calculate.Pooling{
Code: p.ParentCode,
Detail: model.ConsumptionUnit{
Amount: poolingAmount,
Fee: fee,
Price: summary.Overall.Price,
Proportion: proportion,
},
Code: p.Code,
Detail: unit,
}
meter.Poolings = append(meter.Poolings, &pooling)
poolings = append(poolings, &pooling)
}
meter.PooledPublic = model.ConsumptionUnit{
Amount: decimal.NewFromFloat(consumptions),
Fee: decimal.NewFromFloat(consumptions * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.Zero,
}
if total != decimal.Zero.InexactFloat64() {
meter.SharedPoolingProportion = decimal.NewFromFloat(consumptions / total)
}
meter.Poolings = poolings
}
}
default:
// 处理其他分摊模式
return nil
}
return nil
}

View File

@ -1,43 +1,41 @@
package calculate
import (
"context"
"electricity_bill_calc/global"
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"fmt"
"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()
func SavePublics(tx pgx.Tx, ctx context.Context, report model.ReportIndex, meters MeterMap) error {
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)
fmt.Println(tx)
err := repository.CalculateRepository.SaveReportPublics(tx, ctx, report.Id, filteredMeters)
if err != nil {
return err
}
tx.Commit(ctx)
return nil
}

View File

@ -94,7 +94,7 @@ func determineTenementConsumptions(tenement model.Tenement,
moveOutAt := tenement.MovedOutAt
if moveOutAt == nil {
shiftedTime := ShiftToAsiaShanghai(time.Time{})
moveOutAt = &types.DateTime{Time: shiftedTime}// 使用 types.DateTime 的零值表示时间的最大值
moveOutAt = &types.DateTime{Time: shiftedTime} // 使用 types.DateTime 的零值表示时间的最大值
}
endReading, err := determineTenementMeterEndReading(meter.MeterId, periodEnd, ShiftToAsiaShanghai(moveOutAt.Time), meter, currentTermReadings)
if err != nil {
@ -296,7 +296,7 @@ func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
for tCode, meterCodes := range result {
relatedMeters := make([]calculate.Meter, 0)
for _, code := range meterCodes {
Key.Code = code + "_" + tCode
Key.Code = code
meter, ok := meters[Key]
if ok {
relatedMeters = append(relatedMeters, meter)
@ -401,28 +401,29 @@ func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
}
var CriticalProportion decimal.Decimal
if summary.Critical.Amount == decimal.Zero {
fmt.Println(summary.Critical.Amount == decimal.Zero)
if summary.Critical.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
CriticalProportion = decimal.Zero
} else {
CriticalProportion = decimal.NewFromFloat(critical.Amount.InexactFloat64() / summary.Critical.Amount.InexactFloat64())
}
var PeakProportion decimal.Decimal
if summary.Peak.Amount == decimal.Zero {
if summary.Peak.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
PeakProportion = decimal.Zero
} else {
PeakProportion = decimal.NewFromFloat(peak.Amount.InexactFloat64() / summary.Peak.Amount.InexactFloat64())
}
var FlatProportion decimal.Decimal
if summary.Flat.Amount == decimal.Zero {
if summary.Flat.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
FlatProportion = decimal.Zero
} else {
FlatProportion = decimal.NewFromFloat(flat.Amount.InexactFloat64() / summary.Flat.Amount.InexactFloat64())
}
var ValleyProportion decimal.Decimal
if summary.Valley.Amount == decimal.Zero {
if summary.Valley.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
ValleyProportion = decimal.Zero
} else {
ValleyProportion = decimal.NewFromFloat(valley.Amount.InexactFloat64() / summary.Valley.Amount.InexactFloat64())
@ -465,5 +466,6 @@ func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
tc = append(tc, tenementCharge)
}
}
fmt.Println(tc)
return tc
}

View File

@ -94,9 +94,6 @@ func MainCalculateProcess(rid string) error {
return err
}
// 计算商户的合计电费信息,并归总与商户相关联的表计记录
tenementCharges := TenementChargeCalculate(tenementReports, summary, meters)
// 根据核算报表中设置的摊薄内容,逐个表计进行计算
err = CalculateBasicPooling(report, &summary, &meters)
if err != nil {
@ -125,7 +122,7 @@ func MainCalculateProcess(rid string) error {
return err
}
// 计算商户的合计电费信息,并归总与商户相关联的表计记录
tenementCharges = TenementChargeCalculate(tenementReports, summary, meters)
tenementCharges := TenementChargeCalculate(tenementReports, summary, meters)
// 从此处开始向数据库保存全部计算结果。
ctx, cancel := global.TimeoutContext()
@ -133,35 +130,35 @@ func MainCalculateProcess(rid string) error {
tx, _ := global.DB.Begin(ctx)
err = repository.CalculateRepository.ClearReportContent(tx, report.Id)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("18", err)
return err
}
err = SaveSummary(tx, summary)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("19", err)
return err
}
err = SavePublics(tx, *report, meters)
err = SavePublics(tx, ctx, *report, meters)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("20", err)
return err
}
err = SavePoolings(tx, *report, meters, meterRelations)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("21", err)
return err
}
err = SaveTenements(tx, *report, tenementReports, tenementCharges)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("22", err)
return err
}
tx.Commit(ctx)
_ = tx.Commit(ctx)
return nil
}

View File

@ -12,9 +12,9 @@ Server:
ReadTimeout: 60
WriteTimeout: 60
Redis:
Host: 192.168.88.129
Host: 127.0.0.1
Port: 6379
Password: 123456
Password:
DB: 1
Service:
MaxSessionLife: 2h