package calculate import ( "electricity_bill_calc/model" "electricity_bill_calc/model/calculate" "electricity_bill_calc/repository" "errors" "fmt" "github.com/shopspring/decimal" ) 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 }