package calculate import ( "electricity_bill_calc/model" "electricity_bill_calc/model/calculate" "electricity_bill_calc/repository" "errors" "fmt" "github.com/shopspring/decimal" "sort" "strings" "time" "unsafe" ) // 核算园区中的全部商户表计电量用电 func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time, PeriodEnd time.Time, meterDetails []*model.MeterDetail, summary calculate.Summary) ([]calculate.PrimaryTenementStatistics, error) { tenements, err := repository.CalculateRepository.GetAllTenements(report.Id) if err != nil { fmt.Println("tenement 0", err) return nil, err } tenementMeterRelations, err := repository.CalculateRepository.GetAllTenementMeterRelations(report.Park, PeriodEnd, PeriodStart) if err != nil { fmt.Println("tenement 1", err) return nil, err } tenementMeterReadings, err := repository.CalculateRepository.GetMeterReadings(report.Id, model.METER_INSTALLATION_TENEMENT) if err != nil { fmt.Println("tenement 2", err) return nil, err } lastPeriodReadings, err := repository.CalculateRepository.GetLastPeriodReadings(report.Id, model.METER_INSTALLATION_TENEMENT) if err != nil { fmt.Println("tenement 3", err) return nil, err } var tenementReports []calculate.PrimaryTenementStatistics for _, tenement := range tenements { var meters []model.TenementMeter for _, relation := range tenementMeterRelations { if strings.EqualFold(relation.TenementId, tenement.Id) { meters = append(meters, relation) } } pt, err := determineTenementConsumptions( tenement, meters, PeriodStart, PeriodEnd, tenementMeterReadings, lastPeriodReadings, meterDetails, summary, ) if err != nil { return nil, err } tenementReports = append(tenementReports, pt) } return tenementReports, nil } //TODO: 2023.08.02 此方法未完成此方法主要用于。确定指定商户在指定时间段内的所有表计读数(完成) func determineTenementConsumptions(tenement model.Tenement, relatedMeters []model.TenementMeter, periodStart time.Time, periodEnd time.Time, currentTermReadings []model.MeterReading, lastPeriodReadings []model.MeterReading, meterDetails []*model.MeterDetail, summary calculate.Summary) (calculate.PrimaryTenementStatistics, error) { var meters []calculate.Meter for _, meter := range relatedMeters { startReading, err := determineTenementMeterStartReading(meter.MeterId, periodStart, ShiftToAsiaShanghai(tenement.MovedInAt.Time), meter, currentTermReadings, lastPeriodReadings) if err != nil { fmt.Println(err) return calculate.PrimaryTenementStatistics{}, err } endReading, err := determineTenementMeterEndReading(meter.MeterId, periodEnd, ShiftToAsiaShanghai(tenement.MovedOutAt.Time), meter, currentTermReadings) if err != nil { fmt.Println(err) return calculate.PrimaryTenementStatistics{}, err } detail, err := getMeterDetail(meterDetails, meter.MeterId) if err != nil { return calculate.PrimaryTenementStatistics{}, err } overall, err := ComputeOverall(*startReading, *endReading, summary) if err != nil { return calculate.PrimaryTenementStatistics{}, err } critical, err := ComputeCritical(*startReading, *endReading, summary) if err != nil { return calculate.PrimaryTenementStatistics{}, err } peak, err := ComputePeak(*startReading, *endReading, summary) if err != nil { return calculate.PrimaryTenementStatistics{}, err } flat, err := ComputeFlat(*startReading, *endReading, summary) if err != nil { return calculate.PrimaryTenementStatistics{}, err } valley, err := ComputeValley(*startReading, *endReading, summary) if err != nil { return calculate.PrimaryTenementStatistics{}, err } lastTermReading := model.Reading{ Ratio: startReading.Ratio, Overall: startReading.Overall, Critical: startReading.Critical, Peak: startReading.Peak, Flat: startReading.Flat, Valley: startReading.Valley, } lastTermReadingPtr := &lastTermReading currentTermReading := model.Reading{ Ratio: endReading.Ratio, Overall: endReading.Overall, Critical: endReading.Critical, Peak: endReading.Peak, Flat: endReading.Flat, Valley: endReading.Valley, } currentTermReadingPtr := ¤tTermReading meter := calculate.Meter{ Code: meter.MeterId, Detail: detail, CoveredArea: decimal.NewFromFloat(detail.Area.Decimal.InexactFloat64()), LastTermReading: (*calculate.Reading)(unsafe.Pointer(lastTermReadingPtr)), CurrentTermReading: (*calculate.Reading)(unsafe.Pointer(currentTermReadingPtr)), Overall: overall, Critical: critical, Peak: peak, Flat: flat, Valley: valley, AdjustLoss: model.ConsumptionUnit{}, PooledBasic: model.ConsumptionUnit{}, PooledAdjust: model.ConsumptionUnit{}, PooledLoss: model.ConsumptionUnit{}, PooledPublic: model.ConsumptionUnit{}, SharedPoolingProportion: decimal.Decimal{}, Poolings: nil, } meters = append(meters, meter) } return calculate.PrimaryTenementStatistics{ Tenement: tenement, Meters: meters, }, nil } func getMeterDetail(meterDetails []*model.MeterDetail, code string) (model.MeterDetail, error) { for _, detail := range meterDetails { if detail.Code == code { return *detail, nil } } return model.MeterDetail{}, errors.New(fmt.Sprintf("表计 %s 的详细信息不存在", code)) } //确定指定表计的起始读数 func determineTenementMeterStartReading(meterId string, periodStart time.Time, tenementMovedInAt time.Time, meterRelation model.TenementMeter, currentTermReadings []model.MeterReading, lastPeriodReadings []model.MeterReading) (*model.MeterReading, error) { var startTime time.Time timeList := []time.Time{ periodStart, tenementMovedInAt, meterRelation.AssociatedAt.Time, } for _, t := range timeList { if t.After(startTime) { startTime = t } } if startTime.IsZero() { return nil, fmt.Errorf("无法确定表计 %s 的计量的起始时间", meterId) } var startReading *model.MeterReading if startTime.Equal(periodStart) { for _, reading := range lastPeriodReadings { if reading.Meter == meterId { if startReading == nil || reading.ReadAt.After(startReading.ReadAt.Time) { startReading = &reading } } } } else { for _, reading := range currentTermReadings { readingAt := ShiftToAsiaShanghai(reading.ReadAt.Time) if reading.Meter == meterId && readingAt.After(startTime) { if startReading == nil || readingAt.Before(startReading.ReadAt.Time) { startReading = &reading } } } } if startReading == nil { return nil, errors.New("无法确定表计 " + meterId + " 的计量的起始读数") } return startReading, nil } // 确定指定表计的终止读书 func determineTenementMeterEndReading(meterId string, periodEnd time.Time, TenementMovedOutAt time.Time, meterRelation model.TenementMeter, currentTermReadings []model.MeterReading) (*model.MeterReading, error) { var endTime time.Time timeList := []time.Time{ periodEnd, TenementMovedOutAt, ShiftToAsiaShanghai(meterRelation.DisassociatedAt.Time), } for _, t := range timeList { if t.After(endTime) { endTime = t } } if endTime.IsZero() { return nil, fmt.Errorf("无法确定表计 %s 的计量的结束时间", meterId) } var endReading *model.MeterReading for _, reading := range currentTermReadings { readingAt := ShiftToAsiaShanghai(reading.ReadAt.Time) if reading.Meter == meterId && readingAt.Before(endTime) { if endReading == nil || readingAt.After(ShiftToAsiaShanghai(endReading.ReadAt.Time)) { endReading = &reading } } } if endReading == nil { return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的结束读数", meterId)) } return endReading, nil } func ShiftToAsiaShanghai(t time.Time) time.Time { location, _ := time.LoadLocation("Asia/Shanghai") return t.In(location) } // 计算各个商户的合计信息,并归总与商户关联的表计记录 func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics, summary calculate.Summary, meters MeterMap, _relations []model.MeterRelation) { result := make(map[string][]string) for _, t := range tenements { meterCodes := make([]string, 0) for _, m := range t.Meters { meterCodes = append(meterCodes, m.Code) } sort.Strings(meterCodes) result[t.Tenement.Id] = meterCodes } var Key Key for tCode, meterCodes := range result { relatedMeters := make([]calculate.Meter, 0) for _, code := range meterCodes { Key.Code = code + "_" + tCode meter, ok := meters[Key] if ok { relatedMeters = append(relatedMeters, meter) } } // 计算商户的合计电费信息 } }