electricity_bill_calc_service/service/calculate/tenement.go

289 lines
8.6 KiB
Go

package calculate
import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"errors"
"fmt"
"github.com/shopspring/decimal"
"strings"
"time"
"unsafe"
)
// 核算园区中的全部商户表计电量用电
func TenementMetersCalculate(report *model.ReportIndex, PeriodStart time.Time,
PeriodEnd time.Time, meterDetails []*model.MeterDetail,
summary calculate.Summary) ([]model.TenementMeter, 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 []model.Tenement
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
}
report := model.Tenement{
Id: pt.Tenement.Id,
Park: pt.Tenement.Park,
FullName: pt.Tenement.FullName,
ShortName: pt.Tenement.ShortName,
Abbr: pt.Tenement.Abbr,
Address: pt.Tenement.Address,
ContactName: pt.Tenement.ContactName,
ContactPhone: pt.Tenement.ContactPhone,
Building: pt.Tenement.Building,
BuildingName: pt.Tenement.BuildingName,
OnFloor: pt.Tenement.OnFloor,
InvoiceInfo: pt.Tenement.InvoiceInfo,
MovedInAt: pt.Tenement.MovedInAt,
MovedOutAt: pt.Tenement.MovedOutAt,
CreatedAt: pt.Tenement.CreatedAt,
LastModifiedAt: pt.Tenement.LastModifiedAt,
DeletedAt: pt.Tenement.DeletedAt,
}
tenementReports = append(tenementReports, report)
}
return tenementMeterRelations, 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 := &currentTermReading
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)
}