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 }