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 }