package calculate import ( "electricity_bill_calc/model" "electricity_bill_calc/model/calculate" "errors" "github.com/shopspring/decimal" "fmt" ) // 计算已经启用的商铺面积和 func TotalConsumptionCalculate(tenements []calculate.PrimaryTenementStatistics, summary calculate.Summary) decimal.Decimal { var areaMaters []calculate.Meter for _, t := range tenements { areaMaters = append(areaMaters, t.Meters...) } areaMaters = removeDuplicates(areaMaters) var areaTotal float64 for _, m := range areaMaters { areaTotal += m.Detail.Area.Decimal.InexactFloat64() } areaTotal += summary.OverallArea.InexactFloat64() return decimal.NewFromFloat(areaTotal) } func removeDuplicates(meters []calculate.Meter) []calculate.Meter { result := make([]calculate.Meter, 0, len(meters)) seen := make(map[string]bool) for _, meter := range meters { if !seen[meter.Code] { seen[meter.Code] = true result = append(result, meter) } } return result } // 计算线损以及调整线损 func LossCalculate(report *model.ReportIndex, Public []calculate.Meter, publicTotal *decimal.Decimal, summary *calculate.Summary) error { summary.Loss = summary.Overall.Amount.Sub(summary.TotalConsumption) var summaryAmount decimal.Decimal if summary.Overall.Amount == decimal.Zero { summaryAmount = decimal.NewFromFloat(1.0) } else { summaryAmount = summary.Overall.Amount } summary.LossProportion = summary.Loss.Div(summaryAmount) var authorizedLossRate decimal.Decimal // TODO: 2023.08.04 在此发现reportIndex结构体与数据库中的report表字段不对应缺少两个相应字段,在此添加的,如在其他地方有错误优先查找这里 if summary.LossProportion.InexactFloat64() > report.AuthorizedLossRate { authorizedLossRate = summary.LossProportion } else { return errors.New(fmt.Sprintf("经过核算园区的线损率为:{%.8f}, 核定线损率为:{%.8f}", summary.LossProportion.InexactFloat64(), authorizedLossRate.InexactFloat64())) } summary.AuthoizeLoss = model.ConsumptionUnit{ Amount: decimal.NewFromFloat(summary.Overall.Amount.InexactFloat64() * authorizedLossRate.InexactFloat64()), Fee: decimal.NewFromFloat((summary.Overall.Amount.InexactFloat64() * authorizedLossRate.InexactFloat64()) * summary.Overall.Price.InexactFloat64()), Price: summary.Overall.Price, Proportion: authorizedLossRate, } differentialLoss := summary.LossDilutedPrice.Sub(summary.AuthoizeLoss.Amount) fmt.Println(publicTotal.InexactFloat64()) if publicTotal.InexactFloat64() <= decimal.Zero.InexactFloat64() { return errors.New("园区公共表计的电量总和为非正值,或者园区未设置公共表计,无法计算核定线损") } if Public == nil { return nil } for _, meter := range Public { amountProportion := meter.Overall.Amount.InexactFloat64() / publicTotal.InexactFloat64() adjustAmount := differentialLoss.InexactFloat64() * decimal.NewFromFloat(-1.0).InexactFloat64() meter.AdjustLoss = model.ConsumptionUnit{ Amount: decimal.NewFromFloat(adjustAmount), Fee: decimal.NewFromFloat(adjustAmount * summary.LossDilutedPrice.InexactFloat64()), Price: summary.LossDilutedPrice, Proportion: decimal.NewFromFloat(amountProportion), } } return nil } // 计算已经启用的商铺面积和 func EnabledAreaCalculate(tenements *[]calculate.PrimaryTenementStatistics, summary *calculate.Summary) (*decimal.Decimal, 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 }