合并分支

This commit is contained in:
2023-08-04 17:11:10 +08:00
parent 12ec8d26bf
commit 020e76b901
100 changed files with 12692 additions and 2574 deletions

455
service/calculate/meters.go Normal file
View File

@@ -0,0 +1,455 @@
package calculate
import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"errors"
"fmt"
"github.com/shopspring/decimal"
)
// / 合并所有的表计
type Key struct {
Code string
TenementID string
}
type MeterMap map[Key]calculate.Meter
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
}

72
service/calculate/mod.go Normal file
View File

@@ -0,0 +1,72 @@
package calculate
import (
"electricity_bill_calc/global"
"electricity_bill_calc/repository"
"github.com/doug-martin/goqu/v9"
)
type _ModService struct {
ds goqu.DialectWrapper
}
var ModService = _ModService{
ds: goqu.Dialect("postgres"),
}
func mainCalculateProcess(rid string) error {
// 计算所有已经启用的商铺面积总和,仅计算所有未迁出的商户的所有表计对应的商铺面积。
err := CalculateEnabledArea(tenementreports, &summary)
// 计算基本电费分摊、调整电费分摊、电费摊薄单价。
err = CalculatePrices(&summary)
// 收集目前所有已经处理的表计,统一对其进行摊薄计算。
collectMeters, err := CollectMeters(tenementreports, poolingmetersreports, parkmetersreports)
meters, err := collectMeters, err
if err != nil {
return err
}
// 根据核算报表中设置的摊薄内容,逐个表计进行计算
CalculateBasicPooling(report, summary, meters)
CalculateAdjustPooling(report, summary, meters)
CalculateLossPooling(report, summary, meters)
// 计算所有商户类型表计的全周期电量,并根据全周期电量计算共用过同一表计的商户的二次分摊比例。
CalculateTenementConsumptions(meters)
CalculateTenementPoolings(report, summary, meters, metersrelations)
// 计算商户的合计电费信息,并归总与商户相关联的表计记录
tenementCharges, err := CalculateTenementCharge(tenementReports, summary, meters, meterRelations)
if err != nil {
// 处理错误
}
// 从此处开始向数据库保存全部计算结果。
ctx, cancel := global.TimeoutContext()
defer cancel()
tx, _ := global.DB.Begin(ctx)
err = repository.CalculateRepository.ClearReportContent(tx, report.Id)
if err != nil {
tx.Rollback(ctx)
return err
}
err = SaveSummary(tx, summary)
if err != nil {
tx.Rollback(ctx)
return err
}
err = SavePublics(tx, report, meters)
if err != nil {
tx.Rollback(ctx)
return err
}
err = SavePoolings(tx)
if err != nil {
tx.Rollback(ctx)
return err
}
err = SaveTenements(tx)
if err != nil {
tx.Rollback(ctx)
return err
}
tx.Commit(ctx)
}

View File

@@ -0,0 +1,75 @@
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
}
return nil
}
func SaveTenements(tx pgx.Tx, report model.ReportIndex, tenement []calculate.PrimaryTenementStatistics, tc []*calculate.TenementCharge) error {
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
}
return nil
}

View File

@@ -0,0 +1,55 @@
package calculate
import (
"electricity_bill_calc/model/calculate"
"errors"
"github.com/shopspring/decimal"
)
// / 计算已经启用的商铺面积和
// /
// / - `tenements`:所有商户的电量信息
// / - `summary`:核算报表的摘要信息
func CalculateEnabledArea(tenements []calculate.PrimaryTenementStatistics, summary *calculate.Summary) error {
var areaMeters []calculate.Meter
for _, t := range tenements {
areaMeters = append(areaMeters, t.Meters...)
}
// 去重
uniqueAreaMeters := make(map[string]calculate.Meter)
for _, meter := range areaMeters {
uniqueAreaMeters[meter.Code] = meter
}
var areaTotal decimal.Decimal
for _, meter := range uniqueAreaMeters {
areaTotal = areaTotal.Add(meter.Detail.Area.Decimal)
}
if summary != nil {
summary.OverallArea = areaTotal
} else {
return nil, errors.New("summary is nil")
}
return &areaTotal, nil
}
// / 计算基本电费分摊、调整电费分摊以及电费摊薄单价。
// /
// / - `summary`:核算报表的摘要信息
func CalculatePrices(summary *calculate.Summary) error {
if summary.TotalConsumption.IsZero() {
return nil
}
summary.BasicPooledPriceConsumption = summary.BasicFee.Div(summary.TotalConsumption)
if summary.OverallArea.IsZero() {
summary.BasicPooledPriceArea = decimal.Zero
} else {
summary.BasicPooledPriceArea = summary.BasicFee.Div(summary.OverallArea)
}
summary.AdjustPooledPriceConsumption = summary.AdjustFee.Div(summary.TotalConsumption)
if summary.OverallArea.IsZero() {
summary.AdjustPooledPriceArea = decimal.Zero
} else {
summary.AdjustPooledPriceArea = summary.AdjustFee.Div(summary.OverallArea)
}
return nil
}

View File

@@ -0,0 +1,221 @@
package calculate
import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"errors"
"github.com/shopspring/decimal"
"math/big"
)
// / 计算各个商户的合计信息,并归总与商户关联的表计记录
func CalculateTenementCharge(tenements []calculate.PrimaryTenementStatistics, summary calculate.Summary, meters MeterMap, relations []model.MeterRelation) ([]calculate.TenementCharge, error) {
tenementCharges := make([]calculate.TenementCharge, 0)
for _, tenement := range tenements {
relatedMeters := make([]calculate.Meter, 0)
for _, meter := range tenement.Meters {
code := meter.Code
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
code = meter.Detail.Code
}
relatedMeter, ok := meters[Key{Code: code}]
if !ok {
return nil, errors.New("related meter not found")
}
relatedMeters = append(relatedMeters, relatedMeter)
}
// Calculate overall, critical, peak, flat, valley, etc.
//var overall, critical, peak, flat, valley model.ConsumptionUnit
basicPooled, adjustPooled, lossPooled, publicPooled := new(big.Rat), new(big.Rat), new(big.Rat), new(big.Rat)
lossAmount := new(big.Rat)
for _, meter := range relatedMeters {
overall.Add(overall, meter.Overall)
critical.Add(critical, meter.Critical)
peak.Add(peak, meter.Peak)
flat.Add(flat, meter.Flat)
valley.Add(valley, meter.Valley)
basicPooled.Add(basicPooled, meter.PooledBasic.Fee)
adjustPooled.Add(adjustPooled, meter.PooledAdjust.Fee)
lossAmount.Add(lossAmount, meter.AdjustLoss.Amount)
lossPooled.Add(lossPooled, meter.PooledLoss.Fee)
publicPooled.Add(publicPooled, meter.PooledPublic.Fee)
}
// Update proportions and other data for related meters
for _, meter := range relatedMeters {
meter.Overall.Proportion = new(big.Rat).Quo(meter.Overall.Amount, overall.Amount)
meter.Critical.Proportion = new(big.Rat).Quo(meter.Critical.Amount, critical.Amount)
meter.Peak.Proportion = new(big.Rat).Quo(meter.Peak.Amount, peak.Amount)
meter.Flat.Proportion = new(big.Rat).Quo(meter.Flat.Amount, flat.Amount)
meter.Valley.Proportion = new(big.Rat).Quo(meter.Valley.Amount, valley.Amount)
meter.PooledBasic.Proportion = new(big.Rat).Quo(meter.PooledBasic.Fee, basicPooled)
meter.PooledAdjust.Proportion = new(big.Rat).Quo(meter.PooledAdjust.Fee, adjustPooled)
meter.PooledLoss.Proportion = new(big.Rat).Quo(meter.PooledLoss.Fee, lossPooled)
meter.PooledPublic.Proportion = new(big.Rat).Quo(meter.PooledPublic.Fee, publicPooled)
}
tenementCharges = append(tenementCharges, TenementCharges{
Tenement: tenement.Tenement.ID,
Overall: ConsumptionUnit{
Amount: overall.Amount,
Fee: new(big.Rat).Mul(overall.Amount, summary.Overall.Price),
Price: summary.Overall.Price,
Proportion: new(big.Rat).Quo(overall.Amount, summary.Overall.Amount),
},
Critical: ConsumptionUnit{
Amount: critical.Amount,
Fee: new(big.Rat).Mul(critical.Amount, summary.Critical.Price),
Price: summary.Critical.Price,
Proportion: new(big.Rat).Quo(critical.Amount, summary.Critical.Amount),
},
Peak: ConsumptionUnit{
Amount: peak.Amount,
Fee: new(big.Rat).Mul(peak.Amount, summary.Peak.Price),
Price: summary.Peak.Price,
Proportion: new(big.Rat).Quo(peak.Amount, summary.Peak.Amount),
},
Flat: ConsumptionUnit{
Amount: flat.Amount,
Fee: new(big.Rat).Mul(flat.Amount, summary.Flat.Price),
Price: summary.Flat.Price,
Proportion: new(big.Rat).Quo(flat.Amount, summary.Flat.Amount),
},
Valley: ConsumptionUnit{
Amount: valley.Amount,
Fee: new(big.Rat).Mul(valley.Amount, summary.Valley.Price),
Price: summary.Valley.Price,
Proportion: new(big.Rat).Quo(valley.Amount, summary.Valley.Amount),
},
Loss: ConsumptionUnit{
Amount: lossAmount,
Fee: new(big.Rat).Mul(lossPooled, summary.AuthorizeLoss.Price),
Price: summary.AuthorizeLoss.Price,
Proportion: new(big.Rat).Quo(lossAmount, summary.AuthorizeLoss.Amount),
},
BasicFee: basicPooled,
AdjustFee: adjustPooled,
LossPooled: lossPooled,
PublicPooled: publicPooled,
// ... 其他字段的初始化
})
}
return tenementCharges, nil
}
func calculateTenementCharge(
tenements []*PrimaryTenementStatistics,
summary *Summary,
meters MeterMap,
_relations []MeterRelation,
) ([]TenementCharges, error) {
var tenementCharges []TenementCharges
for _, t := range tenements {
meterCodes := make([]string, len(t.Meters))
for i, m := range t.Meters {
meterCodes[i] = m.Code
}
relatedMeters := make([]*Meter, len(meterCodes))
for i, code := range meterCodes {
relatedMeter, ok := meters[Key{Code: code, TenementID: t.Tenement.ID}]
if !ok {
// 处理未找到相关表计的情况
continue
}
relatedMeters[i] = relatedMeter
}
var overall, critical, peak, flat, valley ConsumptionUnit
var basicPooled, adjustPooled, lossAmount, lossPooled, publicPooled decimal.Decimal
for _, meter := range relatedMeters {
overall.Amount = overall.Amount.Add(meter.Overall.Amount)
overall.Fee = overall.Fee.Add(meter.Overall.Fee)
critical.Amount = critical.Amount.Add(meter.Critical.Amount)
critical.Fee = critical.Fee.Add(meter.Critical.Fee)
peak.Amount = peak.Amount.Add(meter.Peak.Amount)
peak.Fee = peak.Fee.Add(meter.Peak.Fee)
flat.Amount = flat.Amount.Add(meter.Flat.Amount)
flat.Fee = flat.Fee.Add(meter.Flat.Fee)
valley.Amount = valley.Amount.Add(meter.Valley.Amount)
valley.Fee = valley.Fee.Add(meter.Valley.Fee)
basicPooled = basicPooled.Add(meter.PooledBasic.Fee)
adjustPooled = adjustPooled.Add(meter.PooledAdjust.Fee)
lossAmount = lossAmount.Add(meter.AdjustLoss.Amount)
lossPooled = lossPooled.Add(meter.PooledLoss.Fee)
publicPooled = publicPooled.Add(meter.PooledPublic.Fee)
}
// 反写商户表计的统计数据
for _, meter := range relatedMeters {
meter.Overall.Proportion = meter.Overall.Amount.Div(overall.Amount)
meter.Critical.Proportion = meter.Critical.Amount.Div(critical.Amount)
meter.Peak.Proportion = meter.Peak.Amount.Div(peak.Amount)
meter.Flat.Proportion = meter.Flat.Amount.Div(flat.Amount)
meter.Valley.Proportion = meter.Valley.Amount.Div(valley.Amount)
meter.PooledBasic.Proportion = meter.PooledBasic.Fee.Div(basicPooled)
meter.PooledAdjust.Proportion = meter.PooledAdjust.Fee.Div(adjustPooled)
meter.PooledLoss.Proportion = meter.PooledLoss.Fee.Div(lossPooled)
meter.PooledPublic.Proportion = meter.PooledPublic.Fee.Div(publicPooled)
}
// 构造并添加商户的合计信息
tenementCharges = append(tenementCharges, TenementCharges{
Tenement: t.Tenement.ID,
Overall: ConsumptionUnit{
Price: summary.Overall.Price,
Proportion: overall.Amount.Div(summary.Overall.Amount),
Amount: overall.Amount,
Fee: overall.Fee,
},
Critical: ConsumptionUnit{
Price: summary.Critical.Price,
Proportion: critical.Amount.Div(summary.Critical.Amount),
Amount: critical.Amount,
Fee: critical.Fee,
},
Peak: ConsumptionUnit{
Price: summary.Peak.Price,
Proportion: peak.Amount.Div(summary.Peak.Amount),
Amount: peak.Amount,
Fee: peak.Fee,
},
Flat: ConsumptionUnit{
Price: summary.Flat.Price,
Proportion: flat.Amount.Div(summary.Flat.Amount),
Amount: flat.Amount,
Fee: flat.Fee,
},
Valley: ConsumptionUnit{
Price: summary.Valley.Price,
Proportion: valley.Amount.Div(summary.Valley.Amount),
Amount: valley.Amount,
Fee: valley.Fee,
},
Loss: ConsumptionUnit{
Price: summary.AuthorizeLoss.Price,
Proportion: lossAmount.Div(summary.AuthorizeLoss.Amount),
Amount: lossAmount,
Fee: lossPooled,
},
BasicFee: basicPooled,
AdjustFee: adjustPooled,
LossPooled: lossPooled,
PublicPooled: publicPooled,
FinalCharges: overall.Fee.Add(basicPooled).Add(adjustPooled).Add(lossPooled).Add(publicPooled),
Submeters: relatedMeters,
Poolings: make([]Meter, 0), // TODO: Add pooling logic here
})
}
return tenementCharges, nil
}