forked from free-lancers/electricity_bill_calc_service
[计算相关]获取所有的物业表计,然后对所有的物业表计电量进行计算。(完成)
This commit is contained in:
32
service/calculate/checking.go
Normal file
32
service/calculate/checking.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package calculate
|
||||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
func CheckMeterArea(report *model.ReportIndex, meters []*model.MeterDetail) (bool, error) {
|
||||
anyAreaOptions := report.BasisPooled == model.POOLING_MODE_AREA ||
|
||||
report.AdjustPooled == model.POOLING_MODE_AREA ||
|
||||
report.PublicPooled == model.POOLING_MODE_AREA ||
|
||||
report.LossPooled == model.POOLING_MODE_AREA
|
||||
|
||||
if anyAreaOptions {
|
||||
var meterWithoutArea int32
|
||||
|
||||
for _, m := range meters {
|
||||
if (m.MeterType == model.METER_INSTALLATION_TENEMENT || m.MeterType == model.METER_INSTALLATION_POOLING) &&
|
||||
m.Area == nil {
|
||||
atomic.AddInt32(&meterWithoutArea, 1)
|
||||
}
|
||||
}
|
||||
|
||||
if meterWithoutArea != 0 {
|
||||
return false, fmt.Errorf("园区中有 %d 个表计没有设置面积,无法进行按面积摊薄。", meterWithoutArea)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
37
service/calculate/park.go
Normal file
37
service/calculate/park.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package calculate
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/model/calculate"
|
||||
"electricity_bill_calc/repository"
|
||||
"time"
|
||||
)
|
||||
|
||||
func MetersParkCalculate(report model.ReportIndex, periodStart time.Time,
|
||||
periodEnd time.Time, meterDetail []*model.MeterDetail,
|
||||
summary calculate.Summary) ([]calculate.Meter, error) {
|
||||
parkMeterReadings, err := repository.CalculateRepository.GetMeterReadings(report.Id, model.METER_INSTALLATION_PARK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lastTermParkMeterReadings, err := repository.CalculateRepository.GetLastPeriodReadings(report.Id, model.METER_INSTALLATION_PARK)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parkMeterReadings = append(parkMeterReadings, lastTermParkMeterReadings...)
|
||||
|
||||
var parkMetersReports []calculate.Meter
|
||||
for _, meter := range meterDetail {
|
||||
if meter.MeterType == model.METER_INSTALLATION_PARK {
|
||||
parkMetersReport, err := determinePublicMeterConsumptions(meter.Code, periodStart, periodEnd, parkMeterReadings, *meter, summary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parkMetersReports = append(parkMetersReports, parkMetersReport)
|
||||
}
|
||||
|
||||
}
|
||||
return parkMetersReports, nil
|
||||
}
|
111
service/calculate/pooled.go
Normal file
111
service/calculate/pooled.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package calculate
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/model/calculate"
|
||||
"electricity_bill_calc/repository"
|
||||
"github.com/shopspring/decimal"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//核算园区中的全部公摊表计的电量用量
|
||||
func PooledMetersCalculate(report *model.ReportIndex, periodStart time.Time,
|
||||
periodEnd time.Time, meterDetails []*model.MeterDetail,
|
||||
summary calculate.Summary) ([]calculate.Meter, error) {
|
||||
poolingMeterReadings, err := repository.CalculateRepository.GetMeterReadings(report.Id, model.METER_INSTALLATION_POOLING)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lastTermPoolingMeterReadings, err := repository.CalculateRepository.GetLastPeriodReadings(report.Id, model.METER_INSTALLATION_POOLING)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
poolingMeterReadings = append(poolingMeterReadings, lastTermPoolingMeterReadings...)
|
||||
|
||||
var poolingMetersReports []calculate.Meter
|
||||
for _, meter := range meterDetails {
|
||||
poolingMetersReport, err := determinePublicMeterConsumptions(meter.Code, periodStart, periodEnd, poolingMeterReadings, *meter, summary)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
poolingMetersReports = append(poolingMetersReports, poolingMetersReport)
|
||||
}
|
||||
return poolingMetersReports, nil
|
||||
}
|
||||
|
||||
// 确定指定非商户表计在指定时间段内的全部电量
|
||||
func determinePublicMeterConsumptions(meterId string, periodStart time.Time,
|
||||
periodEnd time.Time, readings []model.MeterReading,
|
||||
meterDetail model.MeterDetail, summary calculate.Summary) (calculate.Meter, error) {
|
||||
startReading, err := DeterminePublicMeterStartReading(meterId, periodStart, meterDetail.DetachedAt.Time, readings)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
endReading, err := DeterminePublicMeterEndReading(meterId, periodEnd, meterDetail.DetachedAt.Time, readings)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
overall, err := ComputeOverall(*startReading, *endReading, summary)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
critical, err := ComputeCritical(*startReading, *endReading, summary)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
peak, err := ComputePeak(*startReading, *endReading, summary)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
flat, err := ComputeFlat(*startReading, *endReading, summary)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
valley, err := ComputeValley(*startReading, *endReading, summary)
|
||||
if err != nil {
|
||||
return calculate.Meter{}, err
|
||||
}
|
||||
|
||||
return calculate.Meter{
|
||||
Code: meterId,
|
||||
Detail: meterDetail,
|
||||
CoveredArea: meterDetail.Area.Decimal,
|
||||
LastTermReading: (*calculate.Reading)(unsafe.Pointer(&model.Reading{
|
||||
Ratio: startReading.Ratio,
|
||||
Overall: startReading.Overall,
|
||||
Critical: startReading.Critical,
|
||||
Peak: startReading.Peak,
|
||||
Flat: startReading.Flat,
|
||||
Valley: startReading.Valley,
|
||||
})),
|
||||
CurrentTermReading: (*calculate.Reading)(unsafe.Pointer(&model.Reading{
|
||||
Ratio: endReading.Ratio,
|
||||
Overall: endReading.Overall,
|
||||
Critical: endReading.Critical,
|
||||
Peak: endReading.Peak,
|
||||
Flat: endReading.Flat,
|
||||
Valley: endReading.Valley,
|
||||
})),
|
||||
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,
|
||||
}, nil
|
||||
}
|
105
service/calculate/shared.go
Normal file
105
service/calculate/shared.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package calculate
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/types"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 确定指定非商户表计的起始读数
|
||||
func DeterminePublicMeterStartReading(meterId string, periodStart time.Time,
|
||||
attachedAt time.Time, meterReadings []model.MeterReading) (*model.MeterReading, error) {
|
||||
periodBeginning := types.Date{Time: periodStart}.ToBeginningOfDate()
|
||||
|
||||
if len(meterReadings) <= 0 {
|
||||
return nil, errors.New(fmt.Sprintf("表计的抄表记录数据不足%s", meterId))
|
||||
}
|
||||
|
||||
var minReading types.DateTime
|
||||
for _, reading := range meterReadings {
|
||||
if reading.ReadAt.Before(minReading.Time) {
|
||||
minReading = reading.ReadAt
|
||||
}
|
||||
}
|
||||
startTimes := []time.Time{
|
||||
minReading.Time,
|
||||
periodBeginning.Time,
|
||||
ShiftToAsiaShanghai(attachedAt),
|
||||
}
|
||||
if len(startTimes) < 0 {
|
||||
return nil, errors.New(fmt.Sprintf("无法确定表计 {%s} 的计量的起始时间", meterId))
|
||||
}
|
||||
|
||||
var startReading []model.MeterReading
|
||||
for _, reading := range meterReadings {
|
||||
readingAt := ShiftToAsiaShanghai(reading.ReadAt.UTC())
|
||||
for _, startTime := range startTimes {
|
||||
if reading.Meter == meterId && readingAt.After(startTime) || readingAt.Equal(startTime) {
|
||||
startReading = append(startReading, reading)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(startReading) <= 0 {
|
||||
return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的起始读数", meterId))
|
||||
}
|
||||
|
||||
var startReadings *model.MeterReading
|
||||
for _, readings := range startReading {
|
||||
if startReadings == nil || readings.ReadAt.Before(startReadings.ReadAt.Time) {
|
||||
startReadings = &readings
|
||||
}
|
||||
}
|
||||
return startReadings, nil
|
||||
}
|
||||
|
||||
// 确定指定非商户表计的结束读数
|
||||
func DeterminePublicMeterEndReading(meterId string, periodEnd time.Time,
|
||||
detachedAt time.Time, meterReadings []model.MeterReading) (*model.MeterReading, error) {
|
||||
periodEnding := types.Date{Time: periodEnd}.ToEndingOfDate()
|
||||
|
||||
if len(meterReadings) <= 0 {
|
||||
return nil, errors.New(fmt.Sprintf("表计的抄表记录数据不足%s", meterId))
|
||||
}
|
||||
|
||||
var minReading types.DateTime
|
||||
for _, reading := range meterReadings {
|
||||
if reading.ReadAt.Before(minReading.Time) {
|
||||
minReading = reading.ReadAt
|
||||
}
|
||||
}
|
||||
startTimes := []time.Time{
|
||||
minReading.Time,
|
||||
periodEnding.Time,
|
||||
ShiftToAsiaShanghai(detachedAt),
|
||||
}
|
||||
if len(startTimes) < 0 {
|
||||
return nil, errors.New(fmt.Sprintf("无法确定表计 {%s} 的计量的终止时间", meterId))
|
||||
}
|
||||
|
||||
var startReading []model.MeterReading
|
||||
for _, reading := range meterReadings {
|
||||
readingAt := ShiftToAsiaShanghai(reading.ReadAt.UTC())
|
||||
for _, startTime := range startTimes {
|
||||
if reading.Meter == meterId && readingAt.After(startTime) || readingAt.Equal(startTime) {
|
||||
startReading = append(startReading, reading)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(startReading) <= 0 {
|
||||
return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的终止读数", meterId))
|
||||
}
|
||||
|
||||
var startReadings *model.MeterReading
|
||||
for _, readings := range startReading {
|
||||
if startReadings == nil || readings.ReadAt.Before(startReadings.ReadAt.Time) {
|
||||
startReadings = &readings
|
||||
}
|
||||
}
|
||||
return startReadings, nil
|
||||
}
|
1
service/calculate/summary.go
Normal file
1
service/calculate/summary.go
Normal file
@@ -0,0 +1 @@
|
||||
package calculate
|
288
service/calculate/tenement.go
Normal file
288
service/calculate/tenement.go
Normal file
@@ -0,0 +1,288 @@
|
||||
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 := ¤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)
|
||||
}
|
141
service/calculate/utils.go
Normal file
141
service/calculate/utils.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package calculate
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/model/calculate"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// 计算两个读书之间的有功(总)电量
|
||||
func ComputeOverall(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) {
|
||||
start := startReading.Overall.InexactFloat64() * startReading.Ratio.InexactFloat64()
|
||||
end := endReading.Overall.InexactFloat64() * endReading.Ratio.InexactFloat64()
|
||||
|
||||
if start > end {
|
||||
return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("表计 {%s} 有功(总)开始读数 {%x} 大于结束读数 {%x}", startReading.Meter, start, end))
|
||||
}
|
||||
|
||||
amount := end - start
|
||||
|
||||
var summaryAmount float64
|
||||
if summary.Overall.Amount == decimal.Zero {
|
||||
summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64()
|
||||
} else {
|
||||
summaryAmount = summary.Overall.Amount.InexactFloat64()
|
||||
}
|
||||
|
||||
return model.ConsumptionUnit{
|
||||
Amount: decimal.NewFromFloat(amount),
|
||||
Fee: decimal.NewFromFloat(amount * summary.Overall.Price.InexactFloat64()),
|
||||
Price: decimal.NewFromFloat(summary.Overall.Price.InexactFloat64()),
|
||||
Proportion: decimal.NewFromFloat(amount / summaryAmount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//计算两个读书之间的尖峰电量
|
||||
func ComputeCritical(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) {
|
||||
start := startReading.Critical.InexactFloat64() * startReading.Ratio.InexactFloat64()
|
||||
end := endReading.Critical.InexactFloat64() * endReading.Ratio.InexactFloat64()
|
||||
|
||||
if start > end {
|
||||
return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("尖峰开始读数 {%x} 大于结束读数 {%x}", start, end))
|
||||
}
|
||||
|
||||
amount := end - start
|
||||
var summaryAmount float64
|
||||
|
||||
if summary.Critical.Amount.Equal(decimal.Zero) {
|
||||
summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64()
|
||||
} else {
|
||||
summaryAmount = summary.Critical.Amount.InexactFloat64()
|
||||
}
|
||||
|
||||
return model.ConsumptionUnit{
|
||||
Amount: decimal.NewFromFloat(amount),
|
||||
Fee: decimal.NewFromFloat(amount * summary.Critical.Amount.InexactFloat64()),
|
||||
Price: decimal.NewFromFloat(summary.Critical.Price.InexactFloat64()),
|
||||
Proportion: decimal.NewFromFloat(amount / summaryAmount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 计算两个读数之间的峰电量
|
||||
func ComputePeak(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) {
|
||||
start := startReading.Peak.InexactFloat64() * startReading.Ratio.InexactFloat64()
|
||||
end := startReading.Peak.InexactFloat64() * endReading.Ratio.InexactFloat64()
|
||||
|
||||
if start > end {
|
||||
return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("峰开始读数 {%x} 大于结束读数 {%x}", start, end))
|
||||
}
|
||||
|
||||
amount := end - start
|
||||
var summaryAmount float64
|
||||
|
||||
if summary.Peak.Amount.Equal(decimal.Zero) {
|
||||
summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64()
|
||||
} else {
|
||||
summaryAmount = summary.Peak.Amount.InexactFloat64()
|
||||
}
|
||||
|
||||
return model.ConsumptionUnit{
|
||||
Amount: decimal.NewFromFloat(amount),
|
||||
Fee: decimal.NewFromFloat(amount * summary.Peak.Price.InexactFloat64()),
|
||||
Price: decimal.NewFromFloat(summary.Peak.Price.InexactFloat64()),
|
||||
Proportion: decimal.NewFromFloat(amount / summaryAmount),
|
||||
}, nil
|
||||
|
||||
}
|
||||
|
||||
//计算两个读数之间的平电量
|
||||
func ComputeFlat(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) {
|
||||
start := startReading.Flat.InexactFloat64() * startReading.Ratio.InexactFloat64()
|
||||
end := endReading.Flat.InexactFloat64() * endReading.Ratio.InexactFloat64()
|
||||
|
||||
if start > end {
|
||||
return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("平开始读数 {%x} 大于结束读数 {%x}", start, end))
|
||||
}
|
||||
|
||||
amount := end - start
|
||||
var summaryAmount float64
|
||||
|
||||
if summary.Flat.Amount.Equal(decimal.Zero) {
|
||||
summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64()
|
||||
} else {
|
||||
summaryAmount = summary.Flat.Amount.InexactFloat64()
|
||||
}
|
||||
|
||||
return model.ConsumptionUnit{
|
||||
Amount: decimal.NewFromFloat(amount),
|
||||
Fee: decimal.NewFromFloat(amount * summary.Flat.Price.InexactFloat64()),
|
||||
Price: decimal.NewFromFloat(summary.Flat.Price.InexactFloat64()),
|
||||
Proportion: decimal.NewFromFloat(amount / summaryAmount),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//计算两个读数之间的谷电量
|
||||
func ComputeValley(startReading model.MeterReading, endReading model.MeterReading, summary calculate.Summary) (model.ConsumptionUnit, error) {
|
||||
start := startReading.Valley.InexactFloat64() * startReading.Ratio.InexactFloat64()
|
||||
end := endReading.Valley.InexactFloat64() * endReading.Ratio.InexactFloat64()
|
||||
|
||||
if start > end {
|
||||
return model.ConsumptionUnit{}, errors.New(fmt.Sprintf("谷开始读数 {%x} 大于结束读数 {%x}", start, end))
|
||||
}
|
||||
|
||||
amount := end - start
|
||||
|
||||
var summaryAmount float64
|
||||
|
||||
if summary.Valley.Amount.Equal(decimal.Zero) {
|
||||
summaryAmount = decimal.NewFromFloat(1.0).InexactFloat64()
|
||||
} else {
|
||||
summaryAmount = summary.Valley.Amount.InexactFloat64()
|
||||
}
|
||||
|
||||
return model.ConsumptionUnit{
|
||||
Amount: decimal.NewFromFloat(amount),
|
||||
Fee: decimal.NewFromFloat(amount * summary.Valley.Price.InexactFloat64()),
|
||||
Price: decimal.NewFromFloat(summary.Valley.Price.InexactFloat64()),
|
||||
Proportion: decimal.NewFromFloat(amount / summaryAmount),
|
||||
}, nil
|
||||
}
|
66
service/calculate/wattCost.go
Normal file
66
service/calculate/wattCost.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package calculate
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/model/calculate"
|
||||
"electricity_bill_calc/repository"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func MainCalculateProcess(rid string) {
|
||||
report, err := repository.ReportRepository.GetReportIndex(rid)
|
||||
if err != nil {
|
||||
fmt.Println("1", err.Error()+"指定报表不存在")
|
||||
return
|
||||
}
|
||||
|
||||
reportSummary, err := repository.ReportRepository.RetrieveReportSummary(rid)
|
||||
if err != nil {
|
||||
fmt.Println("2", err.Error()+"指定报表的基本电量电费数据不存在")
|
||||
return
|
||||
}
|
||||
|
||||
summary := calculate.FromReportSummary(reportSummary, report)
|
||||
|
||||
periodStart := report.Period.SafeLower()
|
||||
periodEnd := report.Period.SafeUpper()
|
||||
|
||||
meterDetails, err := repository.MeterRepository.AllUsedMetersInReport(report.Id)
|
||||
if err != nil {
|
||||
fmt.Println("3", err)
|
||||
return
|
||||
}
|
||||
|
||||
meterRelations, err := repository.CalculateRepository.GetAllPoolingMeterRelations(report.Park, periodStart.Time)
|
||||
if err != nil {
|
||||
fmt.Println("4", err)
|
||||
return
|
||||
}
|
||||
_, err = CheckMeterArea(report, meterDetails)
|
||||
if err != nil {
|
||||
fmt.Println("5", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 寻找每一个商户的所有表计读数,然后对分配到各个商户的表计读数进行初步的计算.
|
||||
tenementReports, err := TenementMetersCalculate(report, periodStart.Time, periodEnd.Time, meterDetails, summary)
|
||||
if err != nil {
|
||||
fmt.Println("6", err)
|
||||
return
|
||||
}
|
||||
|
||||
//取得所有公摊表计的读数,以及公摊表计对应的分摊表计
|
||||
poolingMetersReports, err := PooledMetersCalculate(report, periodStart.Time, periodEnd.Time, meterDetails, summary)
|
||||
if err != nil {
|
||||
fmt.Println("7", err)
|
||||
return
|
||||
}
|
||||
|
||||
parkMetersReports, err := MetersParkCalculate(*report, periodStart.Time, periodEnd.Time, meterDetails, summary)
|
||||
if err != nil {
|
||||
fmt.Println("8", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(meterRelations, tenementReports, poolingMetersReports, parkMetersReports)
|
||||
|
||||
}
|
Reference in New Issue
Block a user