357 lines
11 KiB
Go
357 lines
11 KiB
Go
package calculate
|
|
|
|
import (
|
|
"electricity_bill_calc/model"
|
|
"electricity_bill_calc/model/calculate"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/shopspring/decimal"
|
|
"log"
|
|
)
|
|
|
|
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 {
|
|
log.Println("m000000000000000000000000000", m.Code)
|
|
|
|
key := Key{TenementID: t.Tenement.Id, Code: m.Code}
|
|
meters[key] = m
|
|
}
|
|
}
|
|
// Collect poolings
|
|
for _, m := range poolings {
|
|
log.Println("m111111111111111111111111", m.Code)
|
|
key := Key{TenementID: "", Code: m.Code}
|
|
meters[key] = m
|
|
}
|
|
|
|
// Collect publics
|
|
for _, m := range publics {
|
|
log.Println("m222222222222222222222222222", m.Code)
|
|
|
|
key := Key{TenementID: "", Code: m.Code}
|
|
meters[key] = m
|
|
}
|
|
log.Println("m33333333333333333333333333333333333333", meters[Key{Code: "yq00001"}])
|
|
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 {
|
|
switch report.PublicPooled {
|
|
case model.POOLING_MODE_AREA:
|
|
for _, meter := range meters {
|
|
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,
|
|
TenementID: "",
|
|
}
|
|
parentMeter, ok := meters[key]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
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 {
|
|
Electricity decimal.Decimal
|
|
ParentElectricity decimal.Decimal
|
|
Code string
|
|
}{
|
|
Electricity: decimal.NewFromFloat(electricity),
|
|
ParentElectricity: overall.Amount,
|
|
Code: parentMeter.Code,
|
|
})
|
|
}
|
|
}
|
|
|
|
consumptions := 0.00
|
|
total := 0.00
|
|
var pooled []*calculate.Pooling
|
|
|
|
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,
|
|
}
|
|
|
|
if p.ParentElectricity != decimal.Zero {
|
|
unit.Proportion = decimal.NewFromFloat(p.Electricity.InexactFloat64() / p.ParentElectricity.InexactFloat64())
|
|
}
|
|
|
|
pooling := calculate.Pooling{
|
|
Code: p.Code,
|
|
Detail: unit,
|
|
}
|
|
|
|
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.PRICING_POLICY_CONSUMPTION:
|
|
for _, meter := range meters {
|
|
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
|
|
pooled := 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,
|
|
TenementID: "",
|
|
}
|
|
parentMeter, ok := meters[key]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
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,
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
consumptions := decimal.Zero.InexactFloat64()
|
|
total := decimal.Zero.InexactFloat64()
|
|
var poolings []*calculate.Pooling
|
|
|
|
for _, p := range pooled {
|
|
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,
|
|
}
|
|
|
|
if p.ParentElectricity != decimal.Zero {
|
|
unit.Proportion = decimal.NewFromFloat(p.Electricity.InexactFloat64() / p.ParentElectricity.InexactFloat64())
|
|
}
|
|
|
|
pooling := calculate.Pooling{
|
|
Code: p.Code,
|
|
Detail: unit,
|
|
}
|
|
|
|
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
|
|
}
|