Compare commits

...

42 Commits

Author SHA1 Message Date
0f91b8a332 doc(calculate): 优化代码格式,删除部分无用打印语句 2023-08-15 15:20:59 +08:00
59a604bab0 fix(park): 修复创建报表中核定线损未显示问题 2023-08-15 15:13:10 +08:00
eaf45331f1 fix(calculate_tenement):修复计算相关赋值问题 2023-08-15 14:46:04 +08:00
2844db1a86 fix(#27): 修复用户电量电费详细为空 2023-08-15 14:13:25 +08:00
7d3fafeb04 fix(#27): 未完全修复成功 2023-08-15 11:05:41 +08:00
032d38181a fix(#26): 修复获取公摊表计下的摊薄表计失败[如果没有公摊关系,则无提示,无显示信息] 2023-08-14 17:26:58 +08:00
292a50029f Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-14 16:34:16 +08:00
de176ce61d fix(#23): 修复获取园区公共电费概况有问题 2023-08-14 16:34:12 +08:00
8a383515d3 fix(#22):修复部分字段读数问题 2023-08-14 14:42:15 +08:00
37bd0da1f2 Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-14 13:49:48 +08:00
bfa7ac1508 fix(#24):修复获取到指定核算报表中的分页公摊表计的核算信息问题 2023-08-14 13:48:58 +08:00
3f36153968 fix(#22):修复无法获取报表的总览信息错误 2023-08-14 13:24:25 +08:00
845bd75348 fix(#10): 修复创建报表错误 2023-08-14 10:05:09 +08:00
559c2d439d Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-11 15:31:37 +08:00
d6829fce27 fix(#10):修复空指针 2023-08-11 15:31:24 +08:00
d1e8c63ec9 fix(park): 修复删除园区返回信息错误 2023-08-11 15:19:06 +08:00
e229f3976d fix(#20): 修复在删除充值记录的时候出现问题 2023-08-11 14:52:15 +08:00
683907b363 fix(#10): 计算相关读取数据部分debug完成 2023-08-11 13:13:45 +08:00
c1b84d1fbb Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-11 11:00:32 +08:00
2021d67d03 fix(#10):修复空指针 2023-08-11 10:59:53 +08:00
b988ffcb75 fix(pooled): 增加缺少字段loss 2023-08-11 10:57:45 +08:00
361b302407 Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-11 10:37:40 +08:00
d8f470e660 fix(#10): 修复部分计算错误,遗留问题在pooled中的deteminePublicMeterConsumpyions里时间为空错误 2023-08-11 10:37:17 +08:00
c472eb4196 fix(#17):修复有绑定表计的商户迁出时无法迁出的错误 2023-08-11 09:02:57 +08:00
98866a8de5 fix(#16):修复商户入驻时间为指定日期,并非当前日期 2023-08-10 16:33:41 +08:00
c89a5f20ad fix(doc): 注释优化 2023-08-10 16:13:12 +08:00
01e944cb5a fix(meter): 修改结构体MeterCreationForm中的字段名称,和此结构体的调用处 2023-08-10 16:12:13 +08:00
c2d43bd98e fix(#15): 修复: 更换表计的时候,在代码中接收了参数未作任何处理 2023-08-10 15:27:59 +08:00
a543b33276 Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-10 15:03:49 +08:00
6289257ac1 fix(#13):修复历史电费核算时未选择园区时显示园区中的数据,选中某一园区时显示不同园区的数据 2023-08-10 14:54:12 +08:00
5d997c14ee Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-10 10:49:47 +08:00
b50eabbca6 fix(meter): 修复:更换电表时的修改逻辑 2023-08-10 10:49:40 +08:00
a34aa6ad07 fix(#12):修复抄表记录与表记管理处无论选择任何表记类型只会显示全部错误 2023-08-10 09:54:57 +08:00
3d918eea85 fix(tenement): 解决向园区中指定商户下绑定一个新的表计时时间异常问题 2023-08-10 09:32:38 +08:00
7f46f2f36b fix(calculate): 修复创建报表时的状态错误 2023-08-09 16:24:16 +08:00
ed10996a06 Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.2 2023-08-09 15:44:10 +08:00
2aa3729e03 fix(#12):修复抄表记录与表记管理处无论选择任何表记类型只会显示全部错误 2023-08-09 15:42:37 +08:00
7d59121c2f fix(report): 调试,历史电费核算部分 2023-08-09 15:35:02 +08:00
b2efb972dc fix(report): 调试,历史电费核算部分 2023-08-09 15:28:17 +08:00
5f750dd0e0 Merge branch '0.2' of https://git.archgrid.xyz/free-lancers/electricity_bill_calc_service into 0.7 2023-08-09 10:51:57 +08:00
dd6becc994 fix(#10):修复创建报表错误,但查出列出园区bug 2023-08-09 10:48:33 +08:00
00cf35ec2a fix(#10):修复创建报表错误,但查出列出园区bug 2023-08-08 17:41:16 +08:00
30 changed files with 802 additions and 526 deletions

View File

@ -12,12 +12,11 @@ import (
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"fmt"
"net/http"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"github.com/samber/lo"
"go.uber.org/zap"
"net/http"
)
var meterLog = logger.Named("Handler", "Meter")
@ -54,7 +53,8 @@ func searchMetersWithinPark(c *fiber.Ctx) error {
}
keyword := c.Query("keyword")
page := c.QueryInt("page", 1)
meters, total, err := repository.MeterRepository.MetersIn(parkId, uint(page), &keyword)
mtype := c.QueryInt("type", 3)
meters, total, err := repository.MeterRepository.MetersIn(parkId, uint(page), &keyword, mtype)
if err != nil {
meterLog.Error("无法查询指定园区下的表计信息,无法获取表计列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
@ -100,6 +100,7 @@ func createNewMeterManually(c *fiber.Ctx) error {
meterLog.Error("无法手动添加一条0.4kV表计记录,无法解析表计创建表单", zap.Error(err))
return result.NotAccept(err.Error())
}
if err := service.MeterService.CreateMeterRecord(parkId, &creationForm); err != nil {
meterLog.Error("无法手动添加一条0.4kV表计记录,无法创建表计记录", zap.Error(err))
return result.NotAccept(err.Error())
@ -201,7 +202,12 @@ func replaceMeter(c *fiber.Ctx) error {
meterLog.Error("无法更换系统中的表计,无法解析表计更换表单", zap.Error(err))
return result.NotAccept(err.Error())
}
return nil
err := service.MeterService.ReplaceMeter(parkId, meterId, &replacementForm.OldReading, replacementForm.NewMeter.Code, replacementForm.NewMeter.Ratio, &replacementForm.NewMeter.Reading)
if err != nil {
meterLog.Error("更换表计出错1111", zap.Error(err))
return result.Error(500, err.Error())
}
return result.Success("更换成功")
}
// 列出指定公摊表计下的所有关联表计
@ -349,6 +355,7 @@ func listUnboundTenementMeters(c *fiber.Ctx) error {
func queryMeterReadings(c *fiber.Ctx) error {
result := response.NewResult(c)
parkId := c.Params("pid")
mtype := c.QueryInt("type", 3)
if pass, err := checkParkBelongs(parkId, meterLog, c, &result); !pass {
return err
}
@ -373,7 +380,7 @@ func queryMeterReadings(c *fiber.Ctx) error {
endDate = &parsedDate
}
}
readings, total, err := service.MeterService.SearchMeterReadings(parkId, building, startDate, endDate, uint(page), keyword)
readings, total, err := service.MeterService.SearchMeterReadings(parkId, building, startDate, endDate, uint(page), keyword, uint(mtype))
if err != nil {
meterLog.Error("查询指定园区中的表计读数,无法获取表计读数列表", zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())

View File

@ -187,7 +187,7 @@ func deleteSpecificPark(c *fiber.Ctx) error {
parkLog.Error("无法删除园区。", zap.String("park id", parkId), zap.String("user id", session.Uid), zap.Error(err))
return result.Error(http.StatusInternalServerError, err.Error())
}
return result.Deleted("已删除指定的园区")
return result.Success("已删除指定的园区")
}
// 列出指定园区中已经登记的建筑

View File

@ -11,6 +11,9 @@ import (
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"log"
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
"github.com/samber/lo"
@ -244,8 +247,28 @@ func getReportSummary(c *fiber.Ctx) error {
reportLog.Error("未找到核算报表的总览信息")
return result.NotFound("未找到核算报表的总览信息。")
}
var summaryResponse vo.ParkSummaryResponse
copier.Copy(&summaryResponse, report)
summaryResponse := vo.ParkSummaryResponse{
ReportId: report.ReportId,
OverallDisplay: vo.ConsumptionDisplay{
AmountStr: strconv.FormatFloat(report.Overall.Amount.InexactFloat64(), 'f', -1, 64),
FeeStr: strconv.FormatFloat(report.Overall.Fee.InexactFloat64(), 'f', -1, 64),
PriceStr: strconv.FormatFloat(report.Overall.Price.InexactFloat64(), 'f', -1, 64),
ProportionStr: strconv.FormatFloat(report.Overall.Proportion.InexactFloat64(), 'f', -1, 64),
},
Area: report.OverallArea,
BasicFee: report.BasicFee,
PooledBasicFeeByAmount: report.BasicPooledPriceConsumption.Decimal,
PooledBasicFeeByArea: report.BasicPooledPriceArea.Decimal,
AdjustFee: report.AdjustFee,
PooledAdjustFeeByAmount: report.AdjustPooledPriceConsumption.Decimal,
PooledAdjustFeeByArea: report.AdjustPooledPriceArea.Decimal,
Consumption: report.ConsumptionFee.Decimal,
//Loss: report.Loss.Decimal,
Loss: report.AuthorizeLoss.Amount,
//LossRate: report.LossFee.Decimal,
LossRate: report.AuthorizeLoss.Proportion,
}
//copier.Copy(&summaryResponse, report)
return result.Success(
"已经获取到核算报表的总览信息。",
fiber.Map{"summary": summaryResponse},
@ -264,15 +287,45 @@ func listPublicMetersInReport(c *fiber.Ctx) error {
reportLog.Error("无法获取核算报表中的公共表计信息", zap.Error(err))
return result.Error(fiber.StatusInternalServerError, "无法获取核算报表中的公共表计信息。")
}
meterResponse := lo.Map(meters, func(meter *model.ReportDetailedPublicConsumption, _ int) *vo.ReportPublicQueryResponse {
m := &vo.ReportPublicQueryResponse{}
m.FromReportDetailPublicConsumption(meter)
return m
})
var meterResponses []vo.Public
for _, meter := range meters {
meterResponse := vo.Public{
Address: meter.Address,
AdjustLoss: model.ConsumptionUnit{
Amount: meter.LossAdjust.Amount,
Fee: meter.LossAdjust.Fee,
Price: meter.LossAdjust.Price,
Proportion: meter.LossAdjust.Proportion,
},
Area: meter.Area.Decimal.String(),
AttachedAt: meter.AttachedAt,
Building: meter.Building,
BuildingName: meter.BuildingName,
Code: meter.ParkMeterID,
DetachedAt: meter.DetachedAt,
DisplayRatio: strconv.FormatFloat(meter.DisplayRatio, 'f', -1, 64),
Enabled: meter.Enabled,
OnFloor: meter.OnFloor,
Overall: model.ConsumptionUnit{
Amount: meter.Overall.Amount,
Fee: meter.Overall.Fee,
Price: meter.Overall.Price,
Proportion: meter.Overall.Proportion,
},
ParkID: meter.ParkID,
Ratio: meter.Ratio.String(),
Seq: meter.Seq,
Type: float64(meter.MeterType),
}
meterResponses = append(meterResponses, meterResponse)
}
return result.Success(
"已经获取到指定核算报表中的分页公共表计的核算信息。",
response.NewPagedResponse(page, total).ToMap(),
fiber.Map{"public": meterResponse},
fiber.Map{"public": meterResponses},
)
}
@ -394,7 +447,7 @@ func reportComprehensiveSearch(c *fiber.Ctx) error {
reportLog.Error("无法获取当前用户的会话信息", zap.Error(err))
return result.Unauthorized("无法获取当前用户的会话信息。")
}
park := tools.EmptyToNil(c.Query("park_id"))
park := tools.EmptyToNil(c.Query("park"))
if session.Type == model.USER_TYPE_ENT && park != nil && len(*park) > 0 {
if pass, err := checkParkBelongs(*park, reportLog, c, &result); !pass {
return err

View File

@ -19,7 +19,7 @@ import (
var tenementLog = logger.Named("Handler", "Tenement")
func InitializeTenementHandler(router *fiber.App) {
func InitializeTenementHandler(router *fiber.App) {
router.Get("/tenement/choice", security.EnterpriseAuthorize, listTenementForChoice)
router.Get("/tenement/:pid", security.EnterpriseAuthorize, listTenement)
router.Put("/tenement/:pid/:tid", security.EnterpriseAuthorize, updateTenement)

View File

@ -8,6 +8,7 @@ import (
"electricity_bill_calc/tools"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/jinzhu/copier"
@ -136,7 +137,8 @@ func deleteTopUp(c *fiber.Ctx) error {
topUpLog.Error("删除一条指定的商户充值记录,删除失败", zap.Error(err))
return result.NotAccept("商户充值记录删除不成功")
}
return result.Deleted(
fmt.Println("已经删除一条指定的商户充值记录")
return result.Success(
"已经删除一条指定的商户充值记录",
)
}

View File

@ -24,23 +24,23 @@ type Pooling struct {
}
type Meter struct {
Code string
Detail model.MeterDetail
CoveredArea decimal.Decimal
LastTermReading *Reading
CurrentTermReading *Reading
Overall model.ConsumptionUnit
Critical model.ConsumptionUnit
Peak model.ConsumptionUnit
Flat model.ConsumptionUnit
Valley model.ConsumptionUnit
AdjustLoss model.ConsumptionUnit
PooledBasic model.ConsumptionUnit
PooledAdjust model.ConsumptionUnit
PooledLoss model.ConsumptionUnit
PooledPublic model.ConsumptionUnit
SharedPoolingProportion decimal.Decimal
Poolings []*Pooling
Code string `json:"code"`
Detail model.MeterDetail `json:"detail"`
CoveredArea decimal.Decimal `json:"covered_area"`
LastTermReading *Reading `json:"last_term_reading"`
CurrentTermReading *Reading `json:"current_term_reading"`
Overall model.ConsumptionUnit `json:"overall"`
Critical model.ConsumptionUnit `json:"critical"`
Peak model.ConsumptionUnit `json:"peak"`
Flat model.ConsumptionUnit `json:"flat"`
Valley model.ConsumptionUnit `json:"valley"`
AdjustLoss model.ConsumptionUnit `json:"adjust_loss"`
PooledBasic model.ConsumptionUnit `json:"pooled_basic"`
PooledAdjust model.ConsumptionUnit `json:"pooled_adjust"`
PooledLoss model.ConsumptionUnit `json:"pooled_loss"`
PooledPublic model.ConsumptionUnit `json:"pooled_public"`
SharedPoolingProportion decimal.Decimal `json:"shared_pooling_proportion"`
Poolings []*Pooling `json:"poolings"`
}
type PrimaryTenementStatistics struct {
@ -49,20 +49,20 @@ type PrimaryTenementStatistics struct {
}
type TenementCharge struct {
Tenement string
Overall model.ConsumptionUnit
Critical model.ConsumptionUnit
Peak model.ConsumptionUnit
Flat model.ConsumptionUnit
Valley model.ConsumptionUnit
BasicFee decimal.Decimal
AdjustFee decimal.Decimal
LossPooled decimal.Decimal
PublicPooled decimal.Decimal
FinalCharges decimal.Decimal
Loss decimal.Decimal
Submeters []*Meter
Poolings []*Meter
Tenement string `json:"tenement"`
Overall model.ConsumptionUnit `json:"overall"`
Critical model.ConsumptionUnit `json:"critical"`
Peak model.ConsumptionUnit `json:"peak"`
Flat model.ConsumptionUnit `json:"flat"`
Valley model.ConsumptionUnit `json:"valley"`
BasicFee decimal.Decimal `json:"basic_fee"`
AdjustFee decimal.Decimal `json:"adjust_fee"`
LossPooled decimal.Decimal `json:"loss_pooled"`
PublicPooled decimal.Decimal `json:"public_pooled"`
FinalCharges decimal.Decimal `json:"final_charges"`
Loss model.ConsumptionUnit `json:"loss"`
Submeters []*Meter `json:"submeters"`
Poolings []*Meter `json:"poolings"`
}
type Summary struct {

View File

@ -32,7 +32,7 @@ type Park struct {
CreatedAt time.Time `json:"createdAt"`
LastModifiedAt time.Time `json:"lastModifiedAt"`
DeletedAt *time.Time `json:"deletedAt"`
NormAuthorizedLossRate float64 `json:"norm_authorized_loss_rate"`
NormAuthorizedLossRate float64 `json:"normAuthorizedLoss"db:"norm_authorized_loss_rate"`
}
type ParkPeriodStatistics struct {

View File

@ -122,6 +122,7 @@ type ReportTenement struct {
Invoice []string `json:"invoice" db:"invoice"`
Meters []NestedMeter `json:"meters" db:"meters"`
Pooled []NestedMeter `json:"pooled" db:"pooled"`
Loss ConsumptionUnit `json:"loss"` //TODO: 2023.08.11 测试时发现少一个字段(已补全)
}
type ReportTask struct {

View File

@ -7,7 +7,7 @@ type Tenement struct {
Park string `json:"parkId" db:"park_id"`
FullName string `json:"fullName" db:"full_name"`
ShortName *string `json:"shortName" db:"short_name"`
Abbr string `json:"-"`
Abbr string `json:"abbr"`
Address string `json:"address"`
ContactName string `json:"contactName" db:"contact_name"`
ContactPhone string `json:"contactPhone" db:"contact_phone"`

View File

@ -1,6 +1,7 @@
package repository
import (
"context"
"electricity_bill_calc/global"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
@ -12,8 +13,6 @@ import (
"github.com/jackc/pgx/v5"
"github.com/shopspring/decimal"
"golang.org/x/sync/errgroup"
"log"
"strings"
"time"
"github.com/doug-martin/goqu/v9"
@ -32,18 +31,26 @@ var CalculateRepository = _CalculateRepository{
ds: goqu.Dialect("postgres"),
}
//更新当前报表的核算状态
// 更新当前报表的核算状态
func (cr _CalculateRepository) UpdateReportCalculateStatus(rid string, status string,
message string) (bool, error) {
ctx, cancel := global.TimeoutContext()
defer cancel()
var atio int
var err error
currentTime := time.Now()
if status == "success" {
atio = 1 //创建报表成功
} else {
atio = 2 // 数据不足
}
updateResultSql, updateResultArgs, _ := cr.ds.
Update(goqu.T("report_task")).
Set(goqu.Record{
"status": status,
"status": int16(atio),
"last_modified_at": currentTime,
"message": message,
}).Where(goqu.I("id").Eq(rid)).
@ -124,7 +131,7 @@ func (cr _CalculateRepository) GetAllPoolingMeterRelations(pid string, revokedAf
var meterRelation []model.MeterRelation
err := pgxscan.Select(ctx, global.DB, meterRelation, relationsSql, relationsArgs...)
err := pgxscan.Select(ctx, global.DB, &meterRelation, relationsSql, relationsArgs...)
if err != nil {
cr.log.Error("获取当前园区中所有公摊表计与商户表计之间的关联关系,包括已经解除的出错", zap.Error(err))
return nil, err
@ -142,21 +149,24 @@ func (cr _CalculateRepository) GetAllTenementMeterRelations(pid string, associat
From(goqu.T("tenement_meter")).
Where(goqu.I("park_id").Eq(pid)).
Where(goqu.And(
goqu.I("associated_at").IsNull(),
goqu.I("associated_at").IsNotNull(),
goqu.I("associated_at").Lte(associatedBefore),
)).
Where(goqu.And(
goqu.I("associated_at").IsNull(),
goqu.I("associated_at").Gte(disassociatedAfter),
goqu.Or(
goqu.I("disassociated_at").IsNull(),
goqu.I("disassociated_at").Gte(disassociatedAfter),
),
)).ToSQL()
var tenementMeter []model.TenementMeter
err := pgxscan.Select(ctx, global.DB, tenementMeter, relationsQuerySql, relationsQueryArgs...)
err := pgxscan.Select(ctx, global.DB, &tenementMeter, relationsQuerySql, relationsQueryArgs...)
if err != nil {
cr.log.Error("获取当前园区中所有的商户与表计的关联关系,包括已经解除的", zap.Error(err))
return nil, err
}
fmt.Println("==", tenementMeter)
return tenementMeter, nil
}
@ -178,13 +188,13 @@ func (cr _CalculateRepository) GetMeterReadings(rid string, meterType int16) ([]
goqu.I("r.id").Eq(rid),
goqu.I("mr.meter_type").Eq(meterType),
// TODO2023.08.02 此方法出错优先查看是否这里出问题
goqu.I("mr.read_at::date <@ r.period"),
goqu.L("?::date <@ ?", goqu.I("mr.read_at"), goqu.I("r.period")),
).
Order(goqu.I("mr.read_at").Asc()).Select(goqu.I("mr.*")).ToSQL()
var readings []model.MeterReading
err := pgxscan.Select(ctx, global.DB, readings, readingsQuerySql, readingsQueryArgs...)
err := pgxscan.Select(ctx, global.DB, &readings, readingsQuerySql, readingsQueryArgs...)
if err != nil {
cr.log.Error("获取指定报表中所有涉及到的指定类型表计在核算时间段内的所有读数数据出错", zap.Error(err))
return nil, err
@ -199,7 +209,8 @@ func (cr _CalculateRepository) GetLastPeriodReadings(rid string, meterType int16
ctx, cancel := global.TimeoutContext()
defer cancel()
readingsSql, readingsArgs, _ := cr.ds.From(goqu.T("meter_reading").As("mr")).
readingsSql, readingsArgs, _ := cr.ds.
From(goqu.T("meter_reading").As("mr")).
Select(
goqu.MAX("mr.read_at").As("read_at"),
goqu.I("mr.park_id"),
@ -219,7 +230,7 @@ func (cr _CalculateRepository) GetLastPeriodReadings(rid string, meterType int16
Where(
goqu.I("r.id").Eq(rid),
goqu.I("mr.meter_type").Eq(meterType),
goqu.I(" mr.read_at::date <= lower(r.period)"),
goqu.L(" read_at <= lower(r.period)"),
).
GroupBy(
goqu.I("mr.park_id"),
@ -235,11 +246,12 @@ func (cr _CalculateRepository) GetLastPeriodReadings(rid string, meterType int16
).ToSQL()
var readings []model.MeterReading
err := pgxscan.Select(ctx, global.DB, readings, readingsSql, readingsArgs...)
err := pgxscan.Select(ctx, global.DB, &readings, readingsSql, readingsArgs...)
if err != nil {
cr.log.Error("获取指定报表中所有涉及到的表计在核算起始日期前的最后一次读数出错", zap.Error(err))
return nil, err
}
return readings, nil
}
@ -266,11 +278,11 @@ func (cr _CalculateRepository) GetAllTenements(rid string) ([]model.Tenement, er
).
Where(
goqu.I("r.id").Eq(rid),
goqu.I("t.moved_in_at <= upper(r.period)"),
goqu.L("t.moved_in_at <= upper(r.period)"),
).ToSQL()
fmt.Println(tenementQuerySql)
var tenements []model.Tenement
err := pgxscan.Select(ctx, global.DB, tenements, tenementQuerySql, tenementQueryArgs...)
err := pgxscan.Select(ctx, global.DB, &tenements, tenementQuerySql, tenementQueryArgs...)
if err != nil {
cr.log.Error("取得指定报表所涉及的所有商户信息出错", zap.Error(err))
return nil, err
@ -309,52 +321,59 @@ func (cr _CalculateRepository) ClearReportContent(tx pgx.Tx, rid string) error {
return nil
}
func (cr _CalculateRepository) SaveReportPublics(tx pgx.Tx, rid string, meters []calculate.Meter) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
func (cr _CalculateRepository) SaveReportPublics(tx pgx.Tx, ctx context.Context, rid string, meters []calculate.Meter) error {
if len(meters) == 0 {
// 如果没有公共表计则直接返回
return nil
}
// 准备插入表达式
insertExpr := cr.ds.Insert("report_public_consumption").
Cols(
"report_id", "park_meter_id", "overall", "critical", "peak", "flat", "valley",
"loss_adjust", "consumption_total", "loss_adjust_total", "final_total",
).Prepared(true)
// 添加值到插入表达式中
for _, meter := range meters {
insertExpr = insertExpr.Vals([]interface{}{
// 准备插入表达式
insertExpr := cr.ds.Insert("report_public_consumption").
Cols(
"report_id", "park_meter_id", "overall", "critical", "peak", "flat", "valley",
"loss_adjust", "consumption_total", "loss_adjust_total", "final_total",
)
// 添加值到插入表达式中
overall, _ := json.Marshal(meter.Overall)
criyical, _ := json.Marshal(meter.Critical)
peak, _ := json.Marshal(meter.Peak)
flat, _ := json.Marshal(meter.Flat)
valley, _ := json.Marshal(meter.Valley)
adjustLoss, _ := json.Marshal(meter.AdjustLoss)
insertExpr = insertExpr.Vals(goqu.Vals{
rid,
meter.Code,
meter.Overall.Fee,
meter.Critical.Fee,
meter.Peak.Fee,
meter.Flat.Fee,
meter.Valley.Fee,
meter.AdjustLoss.Fee,
overall,
criyical,
peak,
flat,
valley,
adjustLoss,
meter.Overall.Fee,
meter.AdjustLoss.Fee,
meter.Overall.Fee.Add(meter.AdjustLoss.Fee),
})
}
// 执行插入语句
inserSql, insertArgs, err := insertExpr.Prepared(true).ToSQL()
if err != nil {
return err
}
if _, err := tx.Exec(ctx, inserSql, insertArgs); err != nil {
return fmt.Errorf("保存报表核算概要失败: %w", err)
// 执行插入语句
inserSql, insertArgs, _ := insertExpr.ToSQL()
_, err := tx.Exec(ctx, inserSql, insertArgs...)
if err != nil {
_ = tx.Rollback(ctx)
return fmt.Errorf("保存报表核算概要失败: %w", err)
}
}
return nil
}
func (cr _CalculateRepository) SaveReportSummary(tx pgx.Tx, summary calculate.Summary) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
func (cr _CalculateRepository) SaveReportSummary(tx pgx.Tx, ctx context.Context, summary calculate.Summary) error {
// 构建插入表达式
insertsql, insertArgs, _ := cr.ds.Insert("report_summary").
Overall, _ := json.Marshal(summary.Overall)
Critical, _ := json.Marshal(summary.Critical)
Peak, _ := json.Marshal(summary.Peak)
Flat, _ := json.Marshal(summary.Flat)
Valley, _ := json.Marshal(summary.Valley)
AuthoizeLoss, _ := json.Marshal(summary.AuthoizeLoss)
insertsql, insertArgs, err := cr.ds.Insert(goqu.T("report_summary")).
Cols(
"report_id", "overall", "critical", "peak", "flat", "valley",
"loss", "loss_fee", "basic_fee", "basic_pooled_price_consumption", "basic_pooled_price_area",
@ -363,16 +382,18 @@ func (cr _CalculateRepository) SaveReportSummary(tx pgx.Tx, summary calculate.Su
"consumption_fee", "authorize_loss", "overall_area", "total_consumption",
).
Vals(goqu.Vals{
summary.ReportId, summary.Overall, summary.Critical, summary.Peak, summary.Flat,
summary.Valley, summary.Loss, summary.LossFee, summary.BasicFee,
summary.ReportId, Overall, Critical, Peak, Flat,
Valley, summary.Loss, summary.LossFee, summary.BasicFee,
summary.BasicPooledPriceConsumption, summary.BasicPooledPriceArea,
summary.AdjustFee, summary.AdjustPooledPriceConsumption, summary.AdjustPooledPriceArea,
summary.LossDilutedPrice, summary.LossProportion, summary.FinalDilutedOverall,
summary.ConsumptionFee, summary.AuthoizeLoss, summary.OverallArea, summary.TotalConsumption,
}).Prepared(true).ToSQL()
summary.ConsumptionFee, AuthoizeLoss, summary.OverallArea, summary.TotalConsumption,
}).ToSQL()
if err != nil {
fmt.Println(err)
return err
}
// 执行插入语句
if _, err := tx.Exec(ctx, insertsql, insertArgs...); err != nil {
cr.log.Error("保存报表核算概要失败。")
return err
@ -441,10 +462,15 @@ func (cr _CalculateRepository) SaveReportPoolings(tx pgx.Tx,
if err != nil {
return err
}
overall, _ := json.Marshal(meter.Overall)
criyical, _ := json.Marshal(meter.Critical)
peak, _ := json.Marshal(meter.Peak)
flat, _ := json.Marshal(meter.Flat)
valley, _ := json.Marshal(meter.Valley)
insertQuery := goqu.Insert("report_pooled_consumption").
Cols("report_id", "pooled_meter_id", "overall", "critical", "peak", "flat", "valley", "pooled_area", "diluted").
Vals(goqu.Vals{rid, meter.Code, meter.Overall, meter.Critical, meter.Peak, meter.Flat, meter.Valley, meter.CoveredArea, submetersJSON})
Vals(goqu.Vals{rid, meter.Code, overall, criyical, peak, flat, valley, meter.CoveredArea, submetersJSON})
insertQueries = append(insertQueries, *insertQuery)
}
@ -471,40 +497,55 @@ func (cr _CalculateRepository) SaveReportTenement(tx pgx.Tx, report model.Report
cr.log.Info("保存商户报表。")
ctx, cancel := global.TimeoutContext()
defer cancel()
insertQuery := cr.ds.Insert("report_tenement").Prepared(true)
values := []goqu.Record{}
insertQuery := cr.ds.
Insert("report_tenement")
var rows []goqu.Record
for _, tenement := range tenements {
charge := findTenementCharge(tenementCharges, tenement.Id)
values = append(values, goqu.Record{
tenementCharge := findTenementCharge(tenementCharges, tenement.Id)
tenementDetail, _ := json.Marshal(tenement)
overallJSON, _ := json.Marshal(tenementCharge.Overall)
criticalJSON, _ := json.Marshal(tenementCharge.Critical)
peakJSON, _ := json.Marshal(tenementCharge.Peak)
flatJSON, _ := json.Marshal(tenementCharge.Flat)
valleyJSON, _ := json.Marshal(tenementCharge.Valley)
lossJSON, _ := json.Marshal(tenementCharge.Loss)
submetersJSON, _ := json.Marshal(convertToNestedMeters(tenementCharge.Submeters))
poolingsJSON, _ := json.Marshal(convertToNestedMeters(tenementCharge.Poolings))
row := goqu.Record{
"report_id": report.Id,
"tenement_id": tenement.Id,
"tenement_detail": toJSONString(tenement),
"tenement_detail": tenementDetail,
"calc_period": report.Period,
"overall": toJSONString(charge.Overall),
"critical": toJSONString(charge.Critical),
"peak": toJSONString(charge.Peak),
"flat": toJSONString(charge.Flat),
"valley": toJSONString(charge.Valley),
"loss": toJSONString(charge.Loss),
"basic_fee_pooled": charge.BasicFee,
"adjust_fee_pooled": charge.AdjustFee,
"loss_fee_pooled": charge.LossPooled,
"final_pooled": charge.PublicPooled,
"final_charge": charge.FinalCharges,
"meters": toJSONString(convertToNestedMeters(charge.Submeters)),
"pooled": toJSONString(convertToNestedMeters(charge.Poolings)),
})
"overall": overallJSON,
"critical": criticalJSON,
"peak": peakJSON,
"flat": flatJSON,
"valley": valleyJSON,
"loss": lossJSON,
"basic_fee_pooled": tenementCharge.BasicFee,
"adjust_fee_pooled": tenementCharge.AdjustFee,
"loss_fee_pooled": tenementCharge.LossPooled,
"final_pooled": tenementCharge.PublicPooled,
"final_charge": tenementCharge.FinalCharges,
"meters": submetersJSON,
"pooled": poolingsJSON,
}
rows = append(rows, row)
}
sql, params, err := insertQuery.Rows(values).Prepared(true).ToSQL()
if err != nil {
log.Println("sql出现问题................................")
return err
}
tx.Exec(ctx, sql, params...)
sql, params, err := insertQuery.Rows(rows).Prepared(true).ToSQL()
if err != nil {
fmt.Println(err)
}
_, err = tx.Exec(ctx, sql, params...)
if err != nil {
fmt.Println(err.Error())
return err
}
return nil
}
@ -533,8 +574,3 @@ func convertToNestedMeters(meters []*calculate.Meter) []NestedMeter {
}
return nestedMeters
}
// toJSONString 将对象转换为 JSON 字符串
func toJSONString(obj interface{}) string {
return `"` + strings.ReplaceAll(fmt.Sprintf("%#v", obj), `"`, `\"`) + `"`
}

View File

@ -12,13 +12,13 @@ import (
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"fmt"
"github.com/doug-martin/goqu/v9"
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
"github.com/georgysavva/scany/v2/pgxscan"
"github.com/jackc/pgx/v5"
"github.com/shopspring/decimal"
"go.uber.org/zap"
"log"
)
type _MeterRepository struct {
@ -121,11 +121,10 @@ func (mr _MeterRepository) AllUsedMetersInReport(rid string) ([]*model.MeterDeta
}
// 分页列出指定园区下的表计信息
func (mr _MeterRepository) MetersIn(pid string, page uint, keyword *string) ([]*model.MeterDetail, int64, error) {
func (mr _MeterRepository) MetersIn(pid string, page uint, keyword *string, mtype int) ([]*model.MeterDetail, int64, error) {
mr.log.Info("分页列出指定园区下的表计信息", zap.String("park id", pid), zap.Uint("page", page), zap.String("keyword", tools.DefaultTo(keyword, "")))
ctx, cancel := global.TimeoutContext()
defer cancel()
meterQuery := mr.ds.
From(goqu.T("meter_04kv").As("m")).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("m.building").Eq(goqu.I("b.id")))).
@ -143,7 +142,10 @@ func (mr _MeterRepository) MetersIn(pid string, page uint, keyword *string) ([]*
goqu.I("m.park_id").Eq(pid),
goqu.I("m.detached_at").IsNull(),
)
if mtype != 3 {
meterQuery = meterQuery.Where(goqu.I("m.meter_type").Eq(uint(mtype)))
countQuery = countQuery.Where(goqu.I("m.meter_type").Eq(uint(mtype)))
}
if keyword != nil && len(*keyword) > 0 {
pattern := fmt.Sprintf("%%%s%%", *keyword)
meterQuery = meterQuery.Where(
@ -174,11 +176,11 @@ func (mr _MeterRepository) MetersIn(pid string, page uint, keyword *string) ([]*
mr.log.Error("查询表计信息失败", zap.Error(err))
return make([]*model.MeterDetail, 0), 0, err
}
if err := pgxscan.Get(ctx, global.DB, &total, countSql, countArgs...); err != nil {
mr.log.Error("查询表计数量失败", zap.Error(err))
return make([]*model.MeterDetail, 0), 0, err
}
return meters, total, nil
}
@ -209,12 +211,12 @@ func (mr _MeterRepository) ListMetersByIDs(pid string, ids []string) ([]*model.M
mr.log.Error("查询表计信息失败", zap.Error(err))
return make([]*model.MeterDetail, 0), err
}
return meters, nil
}
// 获取指定表计的详细信息
func (mr _MeterRepository) FetchMeterDetail(pid, code string) (*model.MeterDetail, error) {
log.Println("获取指定标记的详细信息1111111111111111")
mr.log.Info("获取指定表计的详细信息", zap.String("park id", pid), zap.String("meter code", code))
ctx, cancel := global.TimeoutContext()
defer cancel()
@ -231,7 +233,7 @@ func (mr _MeterRepository) FetchMeterDetail(pid, code string) (*model.MeterDetai
goqu.I("m.code").Eq(code),
).
Prepared(true).ToSQL()
log.Println("111111111111111111111111", meterSql)
if err := pgxscan.Get(ctx, global.DB, &meter, meterSql, meterArgs...); err != nil {
mr.log.Error("查询表计信息失败", zap.Error(err))
return nil, err
@ -242,8 +244,10 @@ func (mr _MeterRepository) FetchMeterDetail(pid, code string) (*model.MeterDetai
// 创建一条新的表计信息
func (mr _MeterRepository) CreateMeter(tx pgx.Tx, ctx context.Context, pid string, meter vo.MeterCreationForm) (bool, error) {
log.Println("创建一条新的表记55555555555555555555")
mr.log.Info("创建一条新的表计信息", zap.String("park id", pid), zap.String("meter code", meter.Code))
timeNow := types.Now()
//timeNow := types.Now()
meterSql, meterArgs, _ := mr.ds.
Insert(goqu.T("meter_04kv")).
Cols(
@ -251,8 +255,9 @@ func (mr _MeterRepository) CreateMeter(tx pgx.Tx, ctx context.Context, pid strin
"attached_at", "created_at", "last_modified_at",
).
Vals(
goqu.Vals{pid, meter.Code, meter.Address, meter.Ratio, meter.Seq, meter.MeterType, meter.Building, meter.OnFloor, meter.Area, meter.Enabled,
timeNow, timeNow, timeNow,
goqu.Vals{pid, meter.Code, meter.Address, meter.Ratio, meter.Seq, meter.MeterType, meter.Building, meter.OnFloor,
meter.Area, meter.Enabled,
meter.Reading.ReadAt, meter.Reading.ReadAt, meter.Reading.ReadAt,
},
).
Prepared(true).ToSQL()
@ -262,6 +267,7 @@ func (mr _MeterRepository) CreateMeter(tx pgx.Tx, ctx context.Context, pid strin
mr.log.Error("创建表计信息失败", zap.Error(err))
return false, err
}
log.Println("555555555555", meterSql)
return ok.RowsAffected() > 0, nil
}
@ -304,6 +310,7 @@ func (mr _MeterRepository) CreateOrUpdateMeter(tx pgx.Tx, ctx context.Context, p
// 记录一条表计的抄表信息
func (mr _MeterRepository) RecordReading(tx pgx.Tx, ctx context.Context, pid, code string, meterType int16, ratio decimal.Decimal, reading *vo.MeterReadingForm) (bool, error) {
log.Println("记录一条表记的抄表信息22222222222222222222")
mr.log.Info("记录一条表计的抄表信息", zap.String("park id", pid), zap.String("meter code", code))
readAt := tools.DefaultTo(reading.ReadAt, types.Now())
readingSql, readingArgs, _ := mr.ds.
@ -315,6 +322,7 @@ func (mr _MeterRepository) RecordReading(tx pgx.Tx, ctx context.Context, pid, co
goqu.Vals{pid, code, readAt, meterType, ratio, reading.Overall, reading.Critical, reading.Peak, reading.Flat, reading.Valley},
).
Prepared(true).ToSQL()
log.Println("22222222222222222222", readingSql)
ok, err := tx.Exec(ctx, readingSql, readingArgs...)
if err != nil {
@ -390,6 +398,7 @@ func (mr _MeterRepository) ListMeterCodes(pid string) ([]string, error) {
// 解除指定园区中指定表计的使用
func (mr _MeterRepository) DetachMeter(tx pgx.Tx, ctx context.Context, pid, code string) (bool, error) {
log.Println("解除指定园区的指定表记使用33333333333333333333")
mr.log.Info("解除指定园区中指定表计的使用", zap.String("park id", pid), zap.String("meter code", code))
timeNow := types.Now()
meterSql, meterArgs, _ := mr.ds.
@ -405,7 +414,7 @@ func (mr _MeterRepository) DetachMeter(tx pgx.Tx, ctx context.Context, pid, code
goqu.I("code").Eq(code),
).
Prepared(true).ToSQL()
log.Println("3333333333333333", meterSql)
ok, err := tx.Exec(ctx, meterSql, meterArgs...)
if err != nil {
mr.log.Error("解除表计使用失败", zap.Error(err))
@ -467,6 +476,7 @@ func (mr _MeterRepository) BindMeter(tx pgx.Tx, ctx context.Context, pid, master
// 解除两个表计之间的关联
func (mr _MeterRepository) UnbindMeter(tx pgx.Tx, ctx context.Context, pid, masterMeter, slaveMeter string) (bool, error) {
log.Println("解除两个标记之间的关系》》》》》》》》》》》》》》》》》》》》》》》4444444444")
mr.log.Info("解除两个表计之间的关联", zap.String("master meter code", masterMeter), zap.String("slave meter code", slaveMeter))
relationSql, relationArgs, _ := mr.ds.
Update(goqu.T("meter_relations")).
@ -482,14 +492,14 @@ func (mr _MeterRepository) UnbindMeter(tx pgx.Tx, ctx context.Context, pid, mast
goqu.I("revoked_at").IsNull(),
).
Prepared(true).ToSQL()
log.Println("4444444444444444", relationSql)
ok, err := tx.Exec(ctx, relationSql, relationArgs...)
if err != nil {
mr.log.Error("解除表计关系失败", zap.Error(err))
return false, err
}
return ok.RowsAffected() > 0, nil
return ok.RowsAffected() >= 0, nil
}
// 列出指定公摊表计的所有关联表计关系
@ -553,7 +563,7 @@ func (mr _MeterRepository) ListMeterRelations(pid, code string) ([]*model.MeterR
var relations []*model.MeterRelation
relationsSql, relationsArgs, _ := mr.ds.
From(goqu.T("meter_relations")).
From(goqu.T("meter_relations").As("r")).
Select("*").
Where(
goqu.I("r.park_id").Eq(pid),
@ -777,25 +787,31 @@ func (mr _MeterRepository) ListUnboundTenementMeters(uid string, pid *string, ke
}
// 查询指定园区中的符合条件的抄表记录
func (mr _MeterRepository) ListMeterReadings(pid string, keyword *string, page uint, start, end *types.Date, buidling *string) ([]*model.MeterReading, int64, error) {
func (mr _MeterRepository) ListMeterReadings(pid string, keyword *string, page uint, start, end *types.Date, buidling *string, mtype uint) ([]*model.MeterReading, int64, error) {
mr.log.Info("查询指定园区中的符合条件的抄表记录", zap.String("park id", pid), zap.String("keyword", tools.DefaultTo(keyword, "")), zap.Uint("page", page), logger.DateFieldp("start", start), logger.DateFieldp("end", end), zap.String("building", tools.DefaultTo(buidling, "")))
ctx, cancel := global.TimeoutContext()
defer cancel()
readingQuery := mr.ds.
From(goqu.T("meter_reading").As("r")).
LeftJoin(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("r.meter_id").Eq(goqu.I("m.code")), goqu.I("m.park_id").Eq(goqu.I("r.park_id")))).
LeftJoin(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("r.meter_id").Eq(goqu.I("m.code")),
goqu.I("m.park_id").Eq(goqu.I("r.park_id")))).
Select("r.*").
Where(
goqu.I("r.park_id").Eq(pid),
)
countQuery := mr.ds.
From(goqu.T("meter_reading").As("r")).
LeftJoin(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("r.meter_id").Eq(goqu.I("m.code")), goqu.I("m.park_id").Eq(goqu.I("r.park_id")))).
LeftJoin(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("r.meter_id").Eq(goqu.I("m.code")),
goqu.I("m.park_id").Eq(goqu.I("r.park_id")))).
Select(goqu.COUNT("*")).
Where(
goqu.I("r.park_id").Eq(pid),
)
if mtype != 3 {
readingQuery = readingQuery.Where(goqu.I("m.meter_type").Eq(mtype))
countQuery = countQuery.Where(goqu.I("m.meter_type").Eq(mtype))
}
if keyword != nil && len(*keyword) > 0 {
pattern := fmt.Sprintf("%%%s%%", *keyword)
@ -859,7 +875,6 @@ func (mr _MeterRepository) ListMeterReadings(pid string, keyword *string, page u
mr.log.Error("查询抄表记录数量失败", zap.Error(err))
return make([]*model.MeterReading, 0), 0, err
}
return readings, total, nil
}

View File

@ -38,7 +38,7 @@ func (pr _ParkRepository) ListAllParks(uid string) ([]*model.Park, error) {
"id", "user_id", "name", "area", "tenement_quantity", "capacity", "category",
"meter_04kv_type", "region", "address", "contact", "phone", "enabled", "price_policy", "tax_rate",
"basic_pooled", "adjust_pooled", "loss_pooled", "public_pooled", "created_at", "last_modified_at",
"deleted_at",
"deleted_at","norm_authorized_loss_rate",
).
Where(
goqu.I("user_id").Eq(uid),

View File

@ -9,7 +9,11 @@ import (
"electricity_bill_calc/tools/serial"
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"encoding/json"
"errors"
"fmt"
"log"
"github.com/doug-martin/goqu/v9"
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
@ -124,8 +128,8 @@ func (rr _ReportRepository) CreateReport(form *vo.ReportCreationForm) (bool, str
createSql, createArgs, _ := rr.ds.
Insert(goqu.T("report")).
Cols(
"id", "park_id", "period", "category", "meter_o4kv_type", "price_policy",
"basic_pooled", "adjust_pooled", "loss_pooled", "public_pooled", "created_at",
"id", "park_id", "period", "category", "meter_04kv_type", "price_policy",
"basis_pooled", "adjust_pooled", "loss_pooled", "public_pooled", "created_at",
"last_modified_at",
).
Vals(goqu.Vals{
@ -134,38 +138,45 @@ func (rr _ReportRepository) CreateReport(form *vo.ReportCreationForm) (bool, str
createTime,
}).
Prepared(true).ToSQL()
summarySql, summaryArgs, _ := rr.ds.
critical := model.ConsumptionUnit{
Amount: form.Critical,
Fee: form.CriticalFee,
}
criticalData, _ := json.Marshal(critical)
overall := model.ConsumptionUnit{
Amount: form.Overall,
Fee: form.OverallFee,
}
overallData, _ := json.Marshal(overall)
peak := model.ConsumptionUnit{
Amount: form.Peak,
Fee: form.PeakFee,
}
peakData, _ := json.Marshal(peak)
flat := model.ConsumptionUnit{
Amount: form.Flat,
Fee: form.FlatFee,
}
flatData, _ := json.Marshal(flat)
valley := model.ConsumptionUnit{
Amount: form.Valley,
Fee: form.ValleyFee,
}
valleyData, _ := json.Marshal(valley)
summarySql, summaryArgs, err5 := rr.ds.
Insert(goqu.T("report_summary")).
Cols(
"report_id", "overall", "critical", "peak", "flat", "valley", "basic_fee",
"adjust_fee",
).
Vals(goqu.Vals{
reportId,
model.ConsumptionUnit{
Amount: form.Overall,
Fee: form.OverallFee,
},
model.ConsumptionUnit{
Amount: form.Critical,
Fee: form.CriticalFee,
},
model.ConsumptionUnit{
Amount: form.Peak,
Fee: form.PeakFee,
},
model.ConsumptionUnit{
Amount: form.Flat,
Fee: form.FlatFee,
},
model.ConsumptionUnit{
Amount: form.Valley,
Fee: form.ValleyFee,
},
form.BasicFee,
form.AdjustFee,
}).
Prepared(true).ToSQL()
//Cols("report_id", "overall", "critical", "peak", "flat", "valley", "basic_fee", "adjust_fee").
Rows(goqu.Record{
"report_id": reportId,
"overall": string(overallData),
"critical": string(criticalData),
"peak": string(peakData),
"flat": string(flatData),
"valley": string(valleyData),
"basic_fee": form.BasicFee,
"adjust_fee": form.AdjustFee,
}).Prepared(true).ToSQL()
log.Println("errrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr:", err5)
taskSql, taskArgs, _ := rr.ds.
Insert(goqu.T("report_task")).
Cols("id", "status", "last_modified_at").
@ -189,11 +200,14 @@ func (rr _ReportRepository) CreateReport(form *vo.ReportCreationForm) (bool, str
tx.Rollback(ctx)
return false, "", err
}
log.Println("?????????", summarySql, summaryArgs)
log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", resSummary.RowsAffected())
if resSummary.RowsAffected() == 0 {
rr.log.Error("保存核算报表汇总时出现错误", zap.Error(err))
tx.Rollback(ctx)
return false, "", exceptions.NewUnsuccessCreateError("创建核算报表汇总时出现错误")
}
resTask, err := tx.Exec(ctx, taskSql, taskArgs...)
if err != nil {
rr.log.Error("创建核算报表任务时出现错误", zap.Error(err))
@ -295,7 +309,6 @@ func (rr _ReportRepository) RetrieveReportSummary(rid string) (*model.ReportSumm
Select("*").
Where(goqu.I("report_id").Eq(rid)).
Prepared(true).ToSQL()
var summary model.ReportSummary
if err := pgxscan.Get(ctx, global.DB, &summary, querySql, queryParams...); err != nil {
rr.log.Error("获取指定报表的总览信息时出现错误", zap.Error(err))
@ -332,23 +345,31 @@ func (rr _ReportRepository) GetReportTaskStatus(uid string) ([]*model.ReportTask
}
// 检索指定核算报表中园区公共表计的核算记录
func (rr _ReportRepository) ListPublicMetersInReport(rid string, page uint, keyword *string) ([]*model.ReportDetailedPublicConsumption, int64, error) {
func (rr _ReportRepository) ListPublicMetersInReport(rid string, page uint, keyword *string) ([]*vo.ReportPublishResponse, int64, error) {
rr.log.Info("检索指定核算报表中园区公共表计的核算记录", zap.String("Report", rid))
ctx, cancel := global.TimeoutContext()
defer cancel()
reportQuery := rr.ds.
From(goqu.T("report_public_consumption").As("r")).
Join(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("m.code").Eq(goqu.I("r.park_meter_id")))).
Join(goqu.T("report").As("ri"), goqu.On(goqu.I("ri.id").Eq(goqu.I("r.report_id")))).
Join(goqu.T("meter_04kv").As("m"), goqu.On(
goqu.I("m.code").Eq(goqu.I("r.park_meter_id")),
goqu.I("m.park_id").Eq(goqu.I("ri.park_id")),
)).
Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("m.park_id")))).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("m.building")))).
Select(
goqu.I("r.*"), goqu.I("b.name").As("building_name"), goqu.I("p.public_pooled"),
goqu.I("r.*"), goqu.I("m.*"), goqu.I("b.name").As("building_name"),
).
Where(goqu.I("r.report_id").Eq(rid))
countQuery := rr.ds.
From(goqu.T("report_public_consumption").As("r")).
Join(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("m.code").Eq(goqu.I("r.park_meter_id")))).
Join(goqu.T("report").As("ri"), goqu.On(goqu.I("ri.id").Eq(goqu.I("r.report_id")))).
Join(goqu.T("meter_04kv").As("m"), goqu.On(
goqu.I("m.code").Eq(goqu.I("r.park_meter_id")),
goqu.I("m.park_id").Eq(goqu.I("ri.park_id")),
)).
Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("m.park_id")))).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("m.building")))).
Select(goqu.COUNT(goqu.I("r.*"))).
@ -372,7 +393,7 @@ func (rr _ReportRepository) ListPublicMetersInReport(rid string, page uint, keyw
Offset(startRow).Limit(config.ServiceSettings.ItemsPageSize)
var (
consumptions []*model.ReportDetailedPublicConsumption = make([]*model.ReportDetailedPublicConsumption, 0)
consumptions = make([]*vo.ReportPublishResponse, 0)
count int64
)
querySql, queryArgs, _ := reportQuery.Prepared(true).ToSQL()
@ -390,19 +411,23 @@ func (rr _ReportRepository) ListPublicMetersInReport(rid string, page uint, keyw
// 检索指定核算报表中公摊表计的核算记录
func (rr _ReportRepository) ListPooledMetersInReport(rid string, page uint, keyword *string) ([]*model.ReportDetailedPooledConsumption, int64, error) {
rr.log.Info("检索指定核算报表中公摊表计的核算记录", zap.String("Report", rid))
ctx, cancel := global.TimeoutContext()
defer cancel()
reportQuery := rr.ds.
From(goqu.T("report_pooled_consumption").As("r")).
Join(
goqu.T("report").As("ri"), goqu.On(goqu.I("ri.id").Eq(goqu.I("r.report_id")))).
Join(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("m.code").Eq(goqu.I("r.pooled_meter_id")))).
Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("m.park_id")))).
Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("ri.park_id")))).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("m.building")))).
Select(
goqu.I("r.*"), goqu.I("m.*"), goqu.I("b.name").As("building_name"), goqu.I("p.public_pooled"),
).
Where(goqu.I("r.report_id").Eq(rid))
reportQuery = reportQuery.Where(goqu.I("m.park_id").Eq(goqu.I("p.id")))
countQuery := rr.ds.
From(goqu.T("report_pooled_consumption").As("r")).
Join(goqu.T("meter_04kv").As("m"), goqu.On(goqu.I("m.code").Eq(goqu.I("r.pooled_meter_id")))).
@ -479,6 +504,10 @@ func (rr _ReportRepository) ListPooledMeterDetailInReport(rid, mid string) ([]*m
rr.log.Error("列出指定核算报表中指定公共表计下参与公共表计费用分摊的表计详细时出现错误", zap.Error(err))
return make([]*model.ReportDetailNestedMeterConsumption, 0), err
}
if len(meterDetails) <= 0 {
return make([]*model.ReportDetailNestedMeterConsumption, 0), errors.New("暂无分摊关系")
}
assembled := lo.Map(meter.Diluted, func(m model.NestedMeter, _ int) *model.ReportDetailNestedMeterConsumption {
meterDetail, _ := lo.Find(meterDetails, func(elem *model.MeterDetail) bool {
return elem.Code == m.MeterId
@ -534,15 +563,17 @@ func (rr _ReportRepository) ListTenementInReport(rid string, page uint, keyword
Offset(startRow).Limit(config.ServiceSettings.ItemsPageSize)
var (
tenements []*model.ReportTenement = make([]*model.ReportTenement, 0)
tenements = make([]*model.ReportTenement, 0)
count int64
)
querySql, queryArgs, _ := reportQuery.Prepared(true).ToSQL()
countSql, countArgs, _ := countQuery.Prepared(true).ToSQL()
fmt.Println(querySql, rid)
if err := pgxscan.Select(ctx, global.DB, &tenements, querySql, queryArgs...); err != nil {
rr.log.Error("查询指定核算报表下的商户简要计费信息时出现错误", zap.Error(err))
return tenements, 0, err
}
if err := pgxscan.Get(ctx, global.DB, &count, countSql, countArgs...); err != nil {
rr.log.Error("查询指定核算报表下的商户简要计费信息总数量时出现错误", zap.Error(err))
return tenements, 0, err
@ -618,7 +649,7 @@ func (rr _ReportRepository) ComprehensiveReportSearch(uid, pid *string, page uin
countQuery = countQuery.Where(goqu.I("ud.id").Eq(*uid))
}
if pid != nil && len(*pid) > 0 {
if pid != nil && *pid != "" {
reportQuery = reportQuery.Where(goqu.I("p.id").Eq(*pid))
countQuery = countQuery.Where(goqu.I("p.id").Eq(*pid))
}
@ -626,7 +657,8 @@ func (rr _ReportRepository) ComprehensiveReportSearch(uid, pid *string, page uin
queryDateRange := types.NewDateRange(start, end)
reportQuery = reportQuery.Where(goqu.L("r.period <@ ?", queryDateRange))
countQuery = countQuery.Where(goqu.L("r.period <@ ?", queryDateRange))
reportQuery = reportQuery.Where(goqu.I("r.published").Eq(true))
countQuery = countQuery.Where(goqu.I("r.published").Eq(true))
if keyword != nil && len(*keyword) > 0 {
pattern := fmt.Sprintf("%%%s%%", *keyword)
reportQuery = reportQuery.Where(goqu.Or(

View File

@ -226,7 +226,7 @@ func (tr _TenementRepository) AddTenement(tx pgx.Tx, ctx context.Context, pid st
Bank: tools.DefaultOrEmptyStr(tenement.Bank, ""),
Account: tools.DefaultOrEmptyStr(tenement.Account, ""),
},
currentTime,
tenement.MoveIn,
currentTime,
currentTime,
}...,
@ -238,7 +238,7 @@ func (tr _TenementRepository) AddTenement(tx pgx.Tx, ctx context.Context, pid st
}
// 向园区中指定商户下绑定一个新的表计
func (tr _TenementRepository) BindMeter(tx pgx.Tx, ctx context.Context, pid, tid, meter string) error {
func (tr _TenementRepository) BindMeter(tx pgx.Tx, ctx context.Context, pid, tid, meter string, form *vo.MeterReadingForm) error {
tr.log.Info("向园区中指定商户下绑定一个新的表计", zap.String("Park", pid), zap.String("Tenement", tid), zap.String("Meter", meter))
createSql, createArgs, _ := tr.ds.
@ -251,7 +251,7 @@ func (tr _TenementRepository) BindMeter(tx pgx.Tx, ctx context.Context, pid, tid
pid,
tid,
meter,
types.Now(),
form.ReadAt,
},
).
Prepared(true).ToSQL()

View File

@ -9,6 +9,7 @@ import (
"electricity_bill_calc/tools"
"electricity_bill_calc/types"
"fmt"
"log"
"time"
"github.com/doug-martin/goqu/v9"
@ -238,8 +239,11 @@ func (ur _UserRepository) FindUser(keyword *string, userType int16, state *bool,
}
if state != nil {
userQuery = userQuery.Where(goqu.Ex{"u.enabled": state})
countQuery = countQuery.Where(goqu.Ex{"u.enabled": state})
//userQuery = userQuery.Where(goqu.C("u.enabled").Eq(*state))
userQuery = userQuery.Where(goqu.Ex{"u.enabled": *state})
countQuery = countQuery.Where(goqu.Ex{"u.enabled": *state})
//countQuery = countQuery.Where(goqu.C("u.enabled").Eq(*state))
}
userQuery.Order(goqu.I("u.created_at").Desc())
@ -249,8 +253,9 @@ func (ur _UserRepository) FindUser(keyword *string, userType int16, state *bool,
userSql, userParams, _ := userQuery.Prepared(true).ToSQL()
countSql, countParams, _ := countQuery.Prepared(true).ToSQL()
log.Println(">>>>>>>>>>>", userSql)
if err := pgxscan.Select(ctx, global.DB, &userWithDetails, userSql, userParams...); err != nil {
ur.log.Error("从数据库查询用户列表失败。", zap.Error(err))
ur.log.Error("从数据库查询用户列表失败。》》》》》》》》》》》》》》", zap.Error(err))
return make([]*model.UserWithDetail, 0), 0, err
}
if err := pgxscan.Get(ctx, global.DB, &userCount, countSql, countParams...); err != nil {

View File

@ -3,10 +3,10 @@ package calculate
import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"errors"
"fmt"
"github.com/shopspring/decimal"
"log"
)
func CollectMeters(tenements []calculate.PrimaryTenementStatistics, poolings []calculate.Meter, publics []calculate.Meter) (MeterMap, error) {
@ -14,20 +14,27 @@ func CollectMeters(tenements []calculate.PrimaryTenementStatistics, poolings []c
// Collect tenement meters
for _, t := range tenements {
for _, m := range t.Meters {
log.Println("m000000000000000000000000000", m.Code)
key := Key{TenementID: t.Tenement.Id, Code: m.Code}
meters[key] = m
}
}
// Collect poolings
for _, m := range poolings {
log.Println("m111111111111111111111111", m.Code)
key := Key{TenementID: "", Code: m.Code}
meters[key] = m
}
// Collect publics
for _, m := range publics {
log.Println("m222222222222222222222222222", m.Code)
key := Key{TenementID: "", Code: m.Code}
meters[key] = m
}
log.Println("m33333333333333333333333333333333333333", meters[Key{Code: "yq00001"}])
return meters, nil
}
@ -144,9 +151,9 @@ func CalculateLossPooling(report model.ReportIndex, summary calculate.Summary, m
/// 计算所有商户类型表计的全周期电量。
func CalculateTenementConsumptions(meters MeterMap) (map[string]decimal.Decimal, error) {
func CalculateTenementConsumptions(meters *MeterMap) (map[string]decimal.Decimal, error) {
consumptions := make(map[string]decimal.Decimal)
for _, meter := range meters {
for _, meter := range *meters {
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
amount, ok := consumptions[meter.Code]
if !ok {
@ -156,7 +163,7 @@ func CalculateTenementConsumptions(meters MeterMap) (map[string]decimal.Decimal,
consumptions[meter.Code] = amount
}
}
for _, meter := range meters {
for _, meter := range *meters {
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
amount, ok := consumptions[meter.Code]
if !ok {
@ -176,273 +183,174 @@ func CalculateTenementConsumptions(meters MeterMap) (map[string]decimal.Decimal,
return consumptions, nil
}
/*
/// 计算商户表计的公摊分摊
func CalculateTenementPoolings(report model.ReportIndex, summary calculate.Summary, meters MeterMap, meterRelations []model.MeterRelation) error {
for _, meter := range meters {
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
switch report.PublicPooled {
case model.POOLING_MODE_AREA:
for _, relation := range meterRelations {
if relation.SlaveMeter == meter.Code {
key := Key{
Code: relation.MasterMeter,
}
parentMeter, ok := meters[key]
if !ok {
return errors.New("父级表记未找到")
}
poolingAmount := meter.Detail.Area.Decimal.Div(parentMeter.CoveredArea).
Mul(meter.SharedPoolingProportion).
Mul(parentMeter.Overall.Amount).Mul(summary.Overall.Price)
pooling := calculate.Pooling{
Code: parentMeter.Code,
Detail: model.ConsumptionUnit{
Amount: poolingAmount,
Fee: poolingAmount.Mul(summary.Overall.Price),
Price: summary.Overall.Price,
//后续debug此处需要判断
Proportion: poolingAmount.Div(parentMeter.Overall.Amount),
},
}
pooling := calculate.Pooling{
Code: parentMeter.Code,
Detail: model.ConsumptionUnit{
Amount: poolingAmount,
Fee: poolingAmount.Mul(summary.Overall.Price),
Price: summary.Overall.Price,
Proportion: poolingAmount.Div(parentMeter.Overall.Amount),
},
}
meter.PooledPublic = &ConsumptionUnit{
Amount: poolingAmount,
Fee: new(big.Rat).Mul(poolingAmount, summary.Overall.Price),
Price: summary.Overall.Price,
Proportion: new(big.Rat).Quo(poolingAmount, parentAmount),
}
meter.Poolings = append(meter.Poolings, pooling)
}
}
case Consumption:
for _, relation := range meterRelations {
if relation.SlaveMeter == meter.Code {
parentMeter, ok := meters[relation.MasterMeter]
if !ok {
return errors.New("parent meter not found")
}
if parentMeter.Overall.Amount.Cmp(new(big.Rat)) == 0 {
poolingAmount := new(big.Rat)
parentAmount := new(big.Rat)
pooling := &Pooling{
Code: parentMeter.Code,
Detail: &ConsumptionUnit{
Amount: poolingAmount,
Fee: new(big.Rat),
Price: summary.Overall.Price,
Proportion: new(big.Rat),
},
}
meter.PooledPublic = &ConsumptionUnit{
Amount: poolingAmount,
Fee: new(big.Rat),
Price: summary.Overall.Price,
Proportion: new(big.Rat),
}
meter.Poolings = append(meter.Poolings, pooling)
} else {
poolingAmount := new(big.Rat).Mul(meter.Overall.Amount, new(big.Rat).Quo(parentMeter.Overall.Amount, parentMeter.Overall.Amount))
parentAmount := parentMeter.Overall.Amount
pooling := &Pooling{
Code: parentMeter.Code,
Detail: &ConsumptionUnit{
Amount: poolingAmount,
Fee: new(big.Rat).Mul(poolingAmount, summary.Overall.Price),
Price: summary.Overall.Price,
Proportion: new(big.Rat).Quo(poolingAmount, parentAmount),
},
}
meter.PooledPublic = &ConsumptionUnit{
Amount: poolingAmount,
Fee: new(big.Rat).Mul(poolingAmount, summary.Overall.Price),
Price: summary.Overall.Price,
Proportion: new(big.Rat).Quo(poolingAmount, parentAmount),
}
meter.Poolings = append(meter.Poolings, pooling)
}
}
}
default:
// handle other pooling modes...
}
}
}
return nil
}
*/
// 计算商户表计的公摊分摊
func CalculateTenementPoolings(report model.ReportIndex, summary calculate.Summary, meters MeterMap, meterRelations []model.MeterRelation) error {
switch report.PublicPooled {
case model.POOLING_MODE_AREA:
for _, meter := range meters {
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
var pooleds []struct {
PooledAmount decimal.Decimal
ParentAmount decimal.Decimal
ParentCode string
}
pooleds := make([]struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}, 0)
for _, relation := range meterRelations {
if relation.SlaveMeter == meter.Code {
key := Key{
Code: relation.MasterMeter,
Code: relation.MasterMeter,
TenementID: "",
}
parentMeter, ok := meters[key]
if !ok {
// 处理未找到父级表计的情况
continue
}
// 计算分摊电量和父级表电量
pooledAmount := meter.Detail.Area.Decimal.Div(parentMeter.CoveredArea).Mul(parentMeter.Overall.Amount).Mul(meter.SharedPoolingProportion)
area := parentMeter.CoveredArea
coveredArea := area
overall := parentMeter.Overall
proportion := meter.SharedPoolingProportion
electricity := area.InexactFloat64() / coveredArea.InexactFloat64() * overall.Amount.InexactFloat64() * proportion.InexactFloat64()
pooleds = append(pooleds, struct {
PooledAmount decimal.Decimal
ParentAmount decimal.Decimal
ParentCode string
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}{
PooledAmount: pooledAmount,
ParentAmount: parentMeter.Overall.Amount,
ParentCode: parentMeter.Code,
Electricity: decimal.NewFromFloat(electricity),
ParentElectricity: overall.Amount,
Code: parentMeter.Code,
})
}
}
// 计算总分摊电量和总父级电量
var consumptions, total decimal.Decimal
for _, p := range pooleds {
consumptions = consumptions.Add(p.PooledAmount)
total = total.Add(p.ParentAmount)
}
consumptions := 0.00
total := 0.00
var pooled []*calculate.Pooling
// 计算并更新公摊分摊信息
for _, p := range pooleds {
poolingAmount := p.PooledAmount
proportion := p.PooledAmount.Div(p.ParentAmount)
fee := poolingAmount.Mul(summary.Overall.Price)
consumptions += p.Electricity.InexactFloat64()
total += p.ParentElectricity.InexactFloat64()
// 更新父级表计的公摊分摊信息
key := Key{
Code: p.ParentCode,
unit := model.ConsumptionUnit{
Amount: p.Electricity,
Fee: decimal.NewFromFloat(p.Electricity.InexactFloat64() * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.Zero,
}
parentMeter := meters[key]
parentMeter.PooledPublic.Amount = consumptions
parentMeter.PooledPublic.Fee = consumptions.Mul(summary.Overall.Price)
parentMeter.PooledPublic.Proportion = consumptions.Div(total)
meters[Key{Code: p.ParentCode}] = parentMeter
// 创建并更新分摊信息
if p.ParentElectricity != decimal.Zero {
unit.Proportion = decimal.NewFromFloat(p.Electricity.InexactFloat64() / p.ParentElectricity.InexactFloat64())
}
pooling := calculate.Pooling{
Code: p.ParentCode,
Detail: model.ConsumptionUnit{
Amount: poolingAmount,
Fee: fee,
Price: summary.Overall.Price,
Proportion: proportion,
},
Code: p.Code,
Detail: unit,
}
meter.Poolings = append(meter.Poolings, &pooling)
pooled = append(pooled, &pooling)
}
meter.PooledPublic = model.ConsumptionUnit{
Amount: decimal.NewFromFloat(consumptions),
Fee: decimal.NewFromFloat(consumptions * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.NewFromFloat(consumptions / total),
}
meter.Poolings = pooled
}
}
case model.POOLING_MODE_CONSUMPTION:
case model.PRICING_POLICY_CONSUMPTION:
for _, meter := range meters {
if meter.Detail.MeterType == model.METER_INSTALLATION_TENEMENT {
var pooled []struct {
PooledAmount decimal.Decimal
ParentAmount decimal.Decimal
ParentCode string
}
pooled := make([]struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}, 0)
for _, relation := range meterRelations {
if relation.SlaveMeter == meter.Code {
parentMeter, ok := meters[Key{Code: relation.MasterMeter}]
key := Key{
Code: relation.MasterMeter,
TenementID: "",
}
parentMeter, ok := meters[key]
if !ok {
// 处理未找到父级表计的情况
continue
}
// 计算分摊电量和父级电量
var pooledAmount decimal.Decimal
if parentMeter.Overall.Amount.IsZero() {
relations, err := repository.MeterRepository.ListPooledMeterRelations(report.Park, meter.Code)
if err != nil {
return err
}
//此处rust版本有误更新后的解决办法
pooledAmount = meter.Overall.Amount.Div(decimal.NewFromInt(int64(len(relations)))).Mul(parentMeter.Overall.Amount)
overall := parentMeter.Overall
if overall.Amount == decimal.Zero {
pooled = append(pooled, struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}{
Electricity: decimal.Zero,
ParentElectricity: decimal.Zero,
Code: parentMeter.Code,
})
} else { //TODO: 2023.08.11 计算处理流程修改到此处,以下问题未作修改还存在问题
electricity := meter.Overall.Amount.InexactFloat64() / overall.Amount.InexactFloat64() * overall.Amount.InexactFloat64()
pooled = append(pooled, struct {
Electricity decimal.Decimal
ParentElectricity decimal.Decimal
Code string
}{
Electricity: decimal.NewFromFloat(electricity),
ParentElectricity: overall.Amount,
Code: parentMeter.Code,
})
}
pooled = append(pooled, struct {
PooledAmount decimal.Decimal
ParentAmount decimal.Decimal
ParentCode string
}{
PooledAmount: pooledAmount,
ParentAmount: parentMeter.Overall.Amount,
ParentCode: parentMeter.Code,
})
}
}
// 计算总分摊电量和总父级表记电量
var consumptions, total decimal.Decimal
consumptions := decimal.Zero.InexactFloat64()
total := decimal.Zero.InexactFloat64()
var poolings []*calculate.Pooling
for _, p := range pooled {
consumptions = consumptions.Add(p.PooledAmount)
total = total.Add(p.ParentAmount)
}
consumptions += p.Electricity.InexactFloat64()
total += p.ParentElectricity.InexactFloat64()
// 计算并更新公摊分摊信息
for _, p := range pooled {
poolingAmount := p.PooledAmount
proportion := p.PooledAmount.Div(p.ParentAmount)
fee := poolingAmount.Mul(summary.Overall.Price)
unit := model.ConsumptionUnit{
Amount: p.Electricity,
Fee: decimal.NewFromFloat(p.Electricity.InexactFloat64() * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.Zero,
}
// 更新父级表计的公摊分摊信息
parentMeter := meters[Key{Code: p.ParentCode}]
parentMeter.PooledPublic.Amount = consumptions
parentMeter.PooledPublic.Fee = consumptions.Mul(summary.Overall.Price)
parentMeter.PooledPublic.Proportion = consumptions.Div(total)
meters[Key{Code: p.ParentCode}] = parentMeter
if p.ParentElectricity != decimal.Zero {
unit.Proportion = decimal.NewFromFloat(p.Electricity.InexactFloat64() / p.ParentElectricity.InexactFloat64())
}
// 创建并更新分摊信息
pooling := calculate.Pooling{
Code: p.ParentCode,
Detail: model.ConsumptionUnit{
Amount: poolingAmount,
Fee: fee,
Price: summary.Overall.Price,
Proportion: proportion,
},
Code: p.Code,
Detail: unit,
}
meter.Poolings = append(meter.Poolings, &pooling)
poolings = append(poolings, &pooling)
}
meter.PooledPublic = model.ConsumptionUnit{
Amount: decimal.NewFromFloat(consumptions),
Fee: decimal.NewFromFloat(consumptions * summary.Overall.Price.InexactFloat64()),
Price: summary.Overall.Price,
Proportion: decimal.Zero,
}
if total != decimal.Zero.InexactFloat64() {
meter.SharedPoolingProportion = decimal.NewFromFloat(consumptions / total)
}
meter.Poolings = poolings
}
}
default:
// 处理其他分摊模式
return nil
}
return nil
}

View File

@ -4,6 +4,7 @@ import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"fmt"
"time"
)
@ -22,6 +23,11 @@ func MetersParkCalculate(report model.ReportIndex, periodStart time.Time,
parkMeterReadings = append(parkMeterReadings, lastTermParkMeterReadings...)
if len(parkMeterReadings) <= 0 {
fmt.Println(parkMeterReadings)
return []calculate.Meter{}, nil
}
var parkMetersReports []calculate.Meter
for _, meter := range meterDetail {
if meter.MeterType == model.METER_INSTALLATION_PARK {

View File

@ -1,51 +1,44 @@
package calculate
import (
"electricity_bill_calc/global"
"context"
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"fmt"
"github.com/jackc/pgx/v5"
)
// 向数据库保存核算概况结果
func SaveSummary(tx pgx.Tx, summary calculate.Summary) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
func SaveSummary(tx pgx.Tx, ctx context.Context, summary calculate.Summary) error {
// 保存核算概况结果到数据库
err := repository.CalculateRepository.SaveReportSummary(tx, summary)
err := repository.CalculateRepository.SaveReportSummary(tx,ctx, summary)
if err != nil {
return err
}
tx.Commit(ctx)
return nil
}
// type MeterMap map[string]map[string]calculate.Meter
// 向数据库保存公共表计的计算结果
func SavePublics(tx pgx.Tx, report model.ReportIndex, meters MeterMap) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
func SavePublics(tx pgx.Tx, ctx context.Context, report model.ReportIndex, meters MeterMap) error {
var filteredMeters []calculate.Meter
for _, m := range meters {
if m.Detail.MeterType == model.METER_INSTALLATION_PARK {
filteredMeters = append(filteredMeters, m)
}
}
err := repository.CalculateRepository.SaveReportPublics(tx, report.Id, filteredMeters)
fmt.Println(tx)
err := repository.CalculateRepository.SaveReportPublics(tx, ctx, report.Id, filteredMeters)
if err != nil {
return err
}
tx.Commit(ctx)
return nil
}
func SavePoolings(tx pgx.Tx, report model.ReportIndex, meters MeterMap, relations []model.MeterRelation) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
var poolingMeters []calculate.Meter
var tenementMeters []calculate.Meter
// 根据条件筛选 Meter 并保存到对应的数组中
@ -60,13 +53,9 @@ func SavePoolings(tx pgx.Tx, report model.ReportIndex, meters MeterMap, relation
if err != nil {
return err
}
tx.Commit(ctx)
return nil
}
func SaveTenements(tx pgx.Tx, report model.ReportIndex, tenement []calculate.PrimaryTenementStatistics, tc []calculate.TenementCharge) error {
ctx, cancel := global.TimeoutContext()
defer cancel()
var ts []model.Tenement
for _, r := range tenement {
ts = append(ts, r.Tenement)
@ -75,7 +64,5 @@ func SaveTenements(tx pgx.Tx, report model.ReportIndex, tenement []calculate.Pri
if err != nil {
return err
}
tx.Commit(ctx)
return nil
}

View File

@ -4,12 +4,13 @@ import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"electricity_bill_calc/types"
"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) {
@ -24,6 +25,9 @@ func PooledMetersCalculate(report *model.ReportIndex, periodStart time.Time,
}
poolingMeterReadings = append(poolingMeterReadings, lastTermPoolingMeterReadings...)
if len(poolingMeterReadings) <= 0 {
return nil, nil
}
var poolingMetersReports []calculate.Meter
for _, meter := range meterDetails {
@ -36,10 +40,14 @@ func PooledMetersCalculate(report *model.ReportIndex, periodStart time.Time,
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) {
if meterDetail.DetachedAt == nil {
zeroTime := time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)
meterDetail.DetachedAt = &types.DateTime{Time: zeroTime}
}
startReading, err := DeterminePublicMeterStartReading(meterId, periodStart, meterDetail.DetachedAt.Time, readings)
if err != nil {
return calculate.Meter{}, err

View File

@ -36,13 +36,15 @@ func DeterminePublicMeterStartReading(meterId string, periodStart time.Time,
for _, reading := range meterReadings {
readingAt := ShiftToAsiaShanghai(reading.ReadAt.UTC())
for _, startTime := range startTimes {
if reading.Meter == meterId && readingAt.After(startTime) || readingAt.Equal(startTime) {
if reading.Meter == meterId && readingAt.Truncate(24*time.Hour).Equal(startTime.Truncate(24*time.Hour)) || readingAt.After(startTime) {
startReading = append(startReading, reading)
break
}
}
}
fmt.Println(startReading)
if len(startReading) <= 0 {
return nil, errors.New(fmt.Sprintf("无法确定表计 %s 的计量的起始读数", meterId))
}
@ -71,20 +73,20 @@ func DeterminePublicMeterEndReading(meterId string, periodEnd time.Time,
minReading = reading.ReadAt
}
}
startTimes := []time.Time{
endTimes := []time.Time{
minReading.Time,
periodEnding.Time,
ShiftToAsiaShanghai(detachedAt),
}
if len(startTimes) < 0 {
if len(endTimes) < 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) {
for _, endTime := range endTimes {
if reading.Meter == meterId && readingAt.Truncate(24*time.Hour).Equal(endTime.Truncate(24*time.Hour)) || readingAt.Before(endTime) {
startReading = append(startReading, reading)
break
}

View File

@ -13,6 +13,7 @@ import (
func TotalConsumptionCalculate(tenements []calculate.PrimaryTenementStatistics, summary calculate.Summary) decimal.Decimal {
var areaMaters []calculate.Meter
for _, t := range tenements {
fmt.Println(t.Meters)
areaMaters = append(areaMaters, t.Meters...)
}
@ -42,7 +43,7 @@ func removeDuplicates(meters []calculate.Meter) []calculate.Meter {
}
// 计算线损以及调整线损
func LossCalculate(report *model.ReportIndex, Public *[]calculate.Meter,
func LossCalculate(report *model.ReportIndex, Public []calculate.Meter,
publicTotal *decimal.Decimal, summary *calculate.Summary) error {
summary.Loss = summary.Overall.Amount.Sub(summary.TotalConsumption)
@ -56,7 +57,7 @@ func LossCalculate(report *model.ReportIndex, Public *[]calculate.Meter,
summary.LossProportion = summary.Loss.Div(summaryAmount)
var authorizedLossRate decimal.Decimal
//TODO: 2023.08.04 在此发现reportIndex结构体与数据库中的report表字段不对应缺少两个相应字段在此添加的如在其他地方有错误优先查找这里
// TODO: 2023.08.04 在此发现reportIndex结构体与数据库中的report表字段不对应缺少两个相应字段在此添加的如在其他地方有错误优先查找这里
if summary.LossProportion.InexactFloat64() > report.AuthorizedLossRate {
authorizedLossRate = summary.LossProportion
} else {
@ -72,11 +73,15 @@ func LossCalculate(report *model.ReportIndex, Public *[]calculate.Meter,
differentialLoss := summary.LossDilutedPrice.Sub(summary.AuthoizeLoss.Amount)
fmt.Println(publicTotal.InexactFloat64())
if publicTotal.InexactFloat64() <= decimal.Zero.InexactFloat64() {
return errors.New("园区公共表计的电量总和为非正值,或者园区未设置公共表计,无法计算核定线损")
}
for _, meter := range *Public {
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{

View File

@ -4,6 +4,7 @@ import (
"electricity_bill_calc/model"
"electricity_bill_calc/model/calculate"
"electricity_bill_calc/repository"
"electricity_bill_calc/types"
"errors"
"fmt"
"github.com/shopspring/decimal"
@ -42,7 +43,6 @@ func TenementMetersCalculate(report *model.ReportIndex,
}
var tenementReports []calculate.PrimaryTenementStatistics
for _, tenement := range tenements {
var meters []model.TenementMeter
@ -79,13 +79,24 @@ func determineTenementConsumptions(tenement model.Tenement,
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)
movedInAt := tenement.MovedInAt
if movedInAt == nil {
shiftedTime := ShiftToAsiaShanghai(time.Time{})
movedInAt = &types.DateTime{Time: shiftedTime}
}
startReading, err := determineTenementMeterStartReading(meter.MeterId, periodStart, ShiftToAsiaShanghai(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)
moveOutAt := tenement.MovedOutAt
if moveOutAt == nil {
shiftedTime := ShiftToAsiaShanghai(time.Time{})
moveOutAt = &types.DateTime{Time: shiftedTime} // 使用 types.DateTime 的零值表示时间的最大值
}
endReading, err := determineTenementMeterEndReading(meter.MeterId, periodEnd, ShiftToAsiaShanghai(moveOutAt.Time), meter, currentTermReadings)
if err != nil {
fmt.Println(err)
return calculate.PrimaryTenementStatistics{}, err
@ -142,7 +153,7 @@ func determineTenementConsumptions(tenement model.Tenement,
}
currentTermReadingPtr := &currentTermReading
meter := calculate.Meter{
m := calculate.Meter{
Code: meter.MeterId,
Detail: detail,
CoveredArea: decimal.NewFromFloat(detail.Area.Decimal.InexactFloat64()),
@ -165,7 +176,7 @@ func determineTenementConsumptions(tenement model.Tenement,
Poolings: nil,
}
meters = append(meters, meter)
meters = append(meters, m)
}
return calculate.PrimaryTenementStatistics{
@ -272,6 +283,7 @@ func ShiftToAsiaShanghai(t time.Time) time.Time {
func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
summary calculate.Summary, meters MeterMap) []calculate.TenementCharge {
result := make(map[string][]string)
var tc []calculate.TenementCharge
for _, t := range tenements {
meterCodes := make([]string, 0)
for _, m := range t.Meters {
@ -281,11 +293,10 @@ func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
result[t.Tenement.Id] = meterCodes
}
var Key Key
var tc []calculate.TenementCharge
for tCode, meterCodes := range result {
relatedMeters := make([]calculate.Meter, 0)
for _, code := range meterCodes {
Key.Code = code + "_" + tCode
Key.Code = code
meter, ok := meters[Key]
if ok {
relatedMeters = append(relatedMeters, meter)
@ -390,55 +401,77 @@ func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
}
var CriticalProportion decimal.Decimal
if summary.Critical.Amount == decimal.Zero {
if summary.Critical.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
CriticalProportion = decimal.Zero
} else {
CriticalProportion = decimal.NewFromFloat(critical.Amount.InexactFloat64() / summary.Critical.Amount.InexactFloat64())
}
var PeakProportion decimal.Decimal
if summary.Peak.Amount == decimal.Zero {
if summary.Peak.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
PeakProportion = decimal.Zero
} else {
PeakProportion = decimal.NewFromFloat(peak.Amount.InexactFloat64() / summary.Peak.Amount.InexactFloat64())
}
var FlatProportion decimal.Decimal
if summary.Flat.Amount == decimal.Zero {
if summary.Flat.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
FlatProportion = decimal.Zero
} else {
FlatProportion = decimal.NewFromFloat(flat.Amount.InexactFloat64() / summary.Flat.Amount.InexactFloat64())
}
var ValleyProportion decimal.Decimal
if summary.Valley.Amount == decimal.Zero {
if summary.Valley.Amount.InexactFloat64() == decimal.Zero.InexactFloat64() {
ValleyProportion = decimal.Zero
} else {
ValleyProportion = decimal.NewFromFloat(valley.Amount.InexactFloat64() / summary.Valley.Amount.InexactFloat64())
}
var lossProportion decimal.Decimal
if summary.AuthoizeLoss.Amount == decimal.Zero {
lossProportion = decimal.Zero
} else {
lossProportion = decimal.NewFromFloat(lossAmount.InexactFloat64() / summary.AuthoizeLoss.Amount.InexactFloat64())
}
tenementCharge := calculate.TenementCharge{
Tenement: tCode,
Overall: model.ConsumptionUnit{
Amount: overall.Amount,
Fee: overall.Fee,
Price: summary.Overall.Price,
Proportion: OverallProportion,
},
Critical: model.ConsumptionUnit{
Amount: critical.Amount,
Fee: critical.Fee,
Price: summary.Critical.Price,
Proportion: CriticalProportion,
},
Peak: model.ConsumptionUnit{
Price: summary.Overall.Price,
Amount: peak.Amount,
Fee: peak.Fee,
Price: summary.Peak.Price,
Proportion: PeakProportion,
},
Flat: model.ConsumptionUnit{
Price: summary.Overall.Price,
Amount: flat.Amount,
Fee: flat.Fee,
Price: summary.Flat.Price,
Proportion: FlatProportion,
},
Valley: model.ConsumptionUnit{
Price: summary.Overall.Price,
Amount: valley.Amount,
Fee: valley.Fee,
Price: summary.Valley.Price,
Proportion: ValleyProportion,
},
Loss: model.ConsumptionUnit{
Amount: lossAmount,
Fee: lossPooled,
Price: summary.AuthoizeLoss.Price,
Proportion: lossProportion,
},
BasicFee: basicPooled,
AdjustFee: adjustPooled,
LossPooled: lossPooled,
@ -450,9 +483,9 @@ func TenementChargeCalculate(tenements []calculate.PrimaryTenementStatistics,
Submeters: nil,
Poolings: nil,
}
tc = append(tc, tenementCharge)
}
}
//fmt.Println(len(tc))
return tc
}

View File

@ -20,6 +20,7 @@ func MainCalculateProcess(rid string) error {
return err
}
fmt.Println(report, reportSummary)
summary := calculate.FromReportSummary(reportSummary, report)
periodStart := report.Period.SafeLower()
@ -66,8 +67,8 @@ func MainCalculateProcess(rid string) error {
// 计算所有表计的总电量
parkTotal := TotalConsumptionCalculate(tenementReports, summary)
// 计算线损以及调整线损
err = LossCalculate(report, &parkMetersReports, &parkTotal, &summary)
//计算线损以及调整线损
err = LossCalculate(report, parkMetersReports, &parkTotal, &summary)
if err != nil {
fmt.Println("9", err)
return err
@ -79,15 +80,13 @@ func MainCalculateProcess(rid string) error {
fmt.Println("10", err)
return err
}
// 计算基本电费分摊、调整电费分摊、电费摊薄单价。
err = CalculatePrices(&summary)
if err != nil {
fmt.Println("11", err)
return err
}
//===========================================================================
// 计算基本电费分摊、调整电费分摊、电费摊薄单价。
err = CalculatePrices(&summary)
fmt.Println("计算数据读取完成=======================================================================================================================================================================================")
// 收集目前所有已经处理的表计,统一对其进行摊薄计算。
meters, err := CollectMeters(tenementReports, poolingMetersReports, parkMetersReports)
if err != nil {
@ -95,9 +94,6 @@ func MainCalculateProcess(rid string) error {
return err
}
// 计算商户的合计电费信息,并归总与商户相关联的表计记录
tenementCharges := TenementChargeCalculate(tenementReports, summary, meters)
// 根据核算报表中设置的摊薄内容,逐个表计进行计算
err = CalculateBasicPooling(report, &summary, &meters)
if err != nil {
@ -115,7 +111,7 @@ func MainCalculateProcess(rid string) error {
return err
}
// 计算所有商户类型表计的全周期电量,并根据全周期电量计算共用过同一表计的商户的二次分摊比例。
_, err = CalculateTenementConsumptions(meters)
_, err = CalculateTenementConsumptions(&meters)
if err != nil {
fmt.Println("16", err)
return err
@ -126,7 +122,7 @@ func MainCalculateProcess(rid string) error {
return err
}
// 计算商户的合计电费信息,并归总与商户相关联的表计记录
tenementCharges = TenementChargeCalculate(tenementReports, summary, meters)
tenementCharges := TenementChargeCalculate(tenementReports, summary, meters)
// 从此处开始向数据库保存全部计算结果。
ctx, cancel := global.TimeoutContext()
@ -134,35 +130,36 @@ func MainCalculateProcess(rid string) error {
tx, _ := global.DB.Begin(ctx)
err = repository.CalculateRepository.ClearReportContent(tx, report.Id)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("18", err)
return err
}
err = SaveSummary(tx, summary)
err = SaveSummary(tx, ctx, summary)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("19", err)
return err
}
err = SavePublics(tx, *report, meters)
err = SavePublics(tx, ctx, *report, meters)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("20", err)
return err
}
err = SavePoolings(tx, *report, meters, meterRelations)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("21", err)
return err
}
err = SaveTenements(tx, *report, tenementReports, tenementCharges)
if err != nil {
tx.Rollback(ctx)
_ = tx.Rollback(ctx)
fmt.Println("22", err)
return err
}
tx.Commit(ctx)
fmt.Println("商户分摊关系保存成功")
_ = tx.Commit(ctx)
return nil
}

View File

@ -49,7 +49,7 @@ func (ms _MeterService) CreateMeterRecord(pid string, form *vo.MeterCreationForm
return err
}
ok, err = repository.MeterRepository.RecordReading(tx, ctx, pid, form.Code, form.MeterType, form.Ratio, &form.MeterReadingForm)
ok, err = repository.MeterRepository.RecordReading(tx, ctx, pid, form.Code, form.MeterType, form.Ratio, &form.Reading)
if err != nil {
ms.log.Error("无法记录表计读数。", zap.Error(err))
tx.Rollback(ctx)
@ -222,7 +222,7 @@ func (ms _MeterService) BatchImportMeters(pid string, file *multipart.FileHeader
Building: element.Building,
OnFloor: element.OnFloor,
Area: element.Area,
MeterReadingForm: vo.MeterReadingForm{
Reading: vo.MeterReadingForm{
ReadAt: &element.ReadAt,
Overall: element.Overall,
Critical: element.Critical.Decimal,
@ -257,7 +257,7 @@ func (ms _MeterService) BatchImportMeters(pid string, file *multipart.FileHeader
}
// 步骤5将全部抄表信息保存进入数据库
for _, record := range meterCreationForms {
_, err := repository.MeterRepository.RecordReading(tx, ctx, pid, record.Code, record.MeterType, record.Ratio, &record.MeterReadingForm)
_, err := repository.MeterRepository.RecordReading(tx, ctx, pid, record.Code, record.MeterType, record.Ratio, &record.Reading)
if err != nil {
ms.log.Error("无法在数据插入阶段保存抄表信息。", zap.String("meter code", record.Code), zap.Error(err))
tx.Rollback(ctx)
@ -363,16 +363,16 @@ func (ms _MeterService) ReplaceMeter(
// 步骤6将旧表计的部分信息赋予新表计
newMeterCreationForm := vo.MeterCreationForm{
Code: newMeterCode,
Address: oldMeter.Address,
MeterType: oldMeter.MeterType,
Ratio: newMeterRatio,
Seq: oldMeter.Seq,
Enabled: oldMeter.Enabled,
Building: oldMeter.Building,
OnFloor: oldMeter.OnFloor,
Area: oldMeter.Area,
MeterReadingForm: *newMeterReading,
Code: newMeterCode,
Address: oldMeter.Address,
MeterType: oldMeter.MeterType,
Ratio: newMeterRatio,
Seq: oldMeter.Seq,
Enabled: oldMeter.Enabled,
Building: oldMeter.Building,
OnFloor: oldMeter.OnFloor,
Area: oldMeter.Area,
Reading: *newMeterReading,
}
// 步骤7将新表计写入系统
@ -389,7 +389,7 @@ func (ms _MeterService) ReplaceMeter(
}
// 步骤8将新表计的读数写入系统
ok, err = repository.MeterRepository.RecordReading(tx, ctx, pid, newMeterCode, newMeterCreationForm.MeterType, newMeterCreationForm.Ratio, &newMeterCreationForm.MeterReadingForm)
ok, err = repository.MeterRepository.RecordReading(tx, ctx, pid, newMeterCode, newMeterCreationForm.MeterType, newMeterCreationForm.Ratio, &newMeterCreationForm.Reading)
switch {
case err != nil:
ms.log.Error("无法将新表计的读数写入系统。", zap.Error(err))
@ -444,6 +444,118 @@ func (ms _MeterService) ReplaceMeter(
return nil
}
//func replaceMeter(
// pid string,
// oldMeterCode string,
// oldMeterReading *MeterReadingForm,
// newMeterCode string,
// newMeterRatio *big.Float,
// newMeterReading *MeterReadingForm,
//) (bool, error) {
// ctx := context.Background()
// tx, err := PostgresPool{}.begin(ctx)
// if err != nil {
// return false, err
// }
//
// // 步骤1获取旧表计的信息
// oldMeter, err := repositories{}.meter_fetch_meter_detail(pid, oldMeterCode)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
// if oldMeter == nil {
// tx.rollback(ctx)
// return false, fmt.Errorf("要替换的旧表计不存在")
// }
//
// // 步骤2将旧表计的读数写入读数表
// err = repositories{}.meter_record_reading(tx, pid, oldMeterCode, oldMeter.MeterType, oldMeter.Ratio, oldMeterReading)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
//
// // 步骤3: 将旧表计从系统中移除
// err = repositories{}.meter_detach_meter(tx, pid, oldMeterCode)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
//
// // 步骤4: 获取旧表计的关联信息
// var oldMeterAssociations []*MeterRelation
// if oldMeter.MeterType == Pooling {
// oldMeterAssociations, err = repositories{}.meter_list_pooled_meter_relations(pid, oldMeterCode)
// } else {
// oldMeterAssociations, err = repositories{}.meter_list_meter_relations(pid, oldMeterCode)
// }
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
//
// // 步骤5: 将旧表计的关联信息全部置为解除
// for _, relation := range oldMeterAssociations {
// err = repositories{}.meter_unbind_meter(tx, pid, relation.MasterMeter, relation.SlaveMeter)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
// }
//
// // 步骤6: 将旧表计的部分信息赋予新表计
// newMeterCreationForm := &MeterCreationForm{
// Code: newMeterCode,
// Address: oldMeter.Address,
// MeterType: oldMeter.MeterType,
// Ratio: newMeterRatio,
// Seq: oldMeter.Seq,
// // Assign other fields
// Reading: newMeterReading,
// }
//
// // 步骤7: 将新表计写入系统
// err = repositories{}.meter_create_meter(tx, pid, newMeterCreationForm)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
//
// // 步骤8: 将新表计的读数写入读数表
// err = repositories{}.meter_record_reading(tx, pid, newMeterCode, oldMeter.MeterType, newMeterRatio, newMeterReading)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
//
// // 步骤9: 将旧表计的关联信息复制一份并赋予新表计
// if oldMeter.MeterType == Pooling {
// for _, relation := range oldMeterAssociations {
// err = repositories{}.meter_bind_meter(tx, pid, newMeterCode, relation.SlaveMeter)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
// }
// } else {
// for _, relation := range oldMeterAssociations {
// err = repositories{}.meter_bind_meter(tx, pid, relation.MasterMeter, newMeterCode)
// if err != nil {
// tx.rollback(ctx)
// return false, err
// }
// }
// }
//
// err = tx.commit(ctx)
// if err != nil {
// return false, err
// }
//
// return true, nil
//}
// 列出园区中指定公摊表计下的所有关联表计
func (ms _MeterService) ListPooledMeterRelations(pid, masterMeter string) ([]*model.MeterDetail, error) {
ms.log.Info("列出园区中指定公摊表计下的所有关联表计", zap.String("park id", pid), zap.String("meter code", masterMeter))
@ -587,7 +699,7 @@ func (ms _MeterService) UnbindMeter(pid, masterMeter string, slaveMeters []strin
}
// 查询符合条件的表计读数记录
func (ms _MeterService) SearchMeterReadings(pid string, building *string, start, end *types.Date, page uint, keyword *string) ([]*model.DetailedMeterReading, int64, error) {
func (ms _MeterService) SearchMeterReadings(pid string, building *string, start, end *types.Date, page uint, keyword *string, mtype uint) ([]*model.DetailedMeterReading, int64, error) {
ms.log.Info(
"查询符合条件的表计读数记录",
zap.String("park id", pid),
@ -597,7 +709,7 @@ func (ms _MeterService) SearchMeterReadings(pid string, building *string, start,
zap.Uint("page", page),
zap.Stringp("keyword", keyword),
)
readings, total, err := repository.MeterRepository.ListMeterReadings(pid, keyword, page, start, end, building)
readings, total, err := repository.MeterRepository.ListMeterReadings(pid, keyword, page, start, end, building, mtype)
if err != nil {
ms.log.Error("无法查询符合条件的表计读数记录。", zap.Error(err))
return make([]*model.DetailedMeterReading, 0), 0, err
@ -777,3 +889,10 @@ func (ms _MeterService) BatchImportReadings(pid string, file *multipart.FileHead
}
return make([]excel.ExcelAnalysisError, 0), nil
}
//// 更换系统中的表计
//func (ms _MeterService) ReplaceMeter(pid string, oldMeterCode string, oldMeterReading vo.MeterReadingForm,
// newMeterCode string, newMeterRatio decimal.Decimal, newMeterDisplayRatio decimal.Decimal,
// newMeterReading vo.NewMeterForReplacingForm) {
//
//}

View File

@ -9,6 +9,7 @@ import (
"electricity_bill_calc/types"
"electricity_bill_calc/vo"
"github.com/pkg/errors"
"log"
"sync"
"github.com/doug-martin/goqu/v9"
@ -209,30 +210,35 @@ func (rs _ReportService) ReportCalcuateDispatch(rid string) error {
return nil
}
//创建一个新的核算报表,并同时完成核算报表的计算
// 创建一个新的核算报表,并同时完成核算报表的计算
func (rs _ReportService) CreateNewReport(createFrom *vo.ReportCreationForm) (bool, error) {
state, report, err := repository.ReportRepository.CreateReport(createFrom)
if err != nil {
rs.log.Error("创建核算报表错误", zap.Error(err))
return false, err
}
if !state {
status, err := repository.CalculateRepository.UpdateReportCalculateStatus(report, "InsufficientData", "创建报表时发生错误,需手动再次计算")
status, err := repository.CalculateRepository.UpdateReportCalculateStatus(report, "InsufficientData",
"创建报表时发生错误,需手动再次计算")
if err != nil {
rs.log.Error("创建报表时发生错误,需手动再次计算", zap.Error(err))
return false, err
}
return status, nil
}
err = rs.CalculateReport(report)
if err != nil {
rs.log.Error("计算时出错", zap.Error(err))
return false, err
}
return true, nil
}
//更新一个核算报表中的数据,并同时完成计算
// 更新一个核算报表中的数据,并同时完成计算
func (rs _ReportService) UpdateRepoet(rid string, updateForm *vo.ReportModifyForm) (bool, error) {
state, err := repository.ReportRepository.UpdateReportSummary(rid, updateForm)
if err != nil {
@ -258,10 +264,10 @@ var CALCULATE_TASK_PARALLEL_CONTROL = func() *sync.Mutex {
// 执行一个核算报表的计算任务
func (rs _ReportService) CalculateReport(rid string) error {
semaphore := CALCULATE_TASK_PARALLEL_CONTROL
semaphore.Lock()
defer semaphore.Unlock()
//semaphore := CALCULATE_TASK_PARALLEL_CONTROL
//
//semaphore.Lock()
//defer semaphore.Unlock()
errs := calculate.MainCalculateProcess(rid)

View File

@ -7,7 +7,6 @@ import (
"electricity_bill_calc/repository"
"electricity_bill_calc/vo"
"fmt"
"github.com/samber/lo"
"go.uber.org/zap"
)
@ -82,7 +81,7 @@ func (ts _TenementService) BindMeter(pid, tid, meterCode string, reading *vo.Met
tx.Rollback(ctx)
return fmt.Errorf("未能获取表计详细信息,%w", err)
}
err = repository.TenementRepository.BindMeter(tx, ctx, pid, tid, meterCode)
err = repository.TenementRepository.BindMeter(tx, ctx, pid, tid, meterCode, reading)
if err != nil {
ts.log.Error("向商户绑定一个新表计失败,未能绑定表计", zap.Error(err))
tx.Rollback(ctx)
@ -201,7 +200,7 @@ func (ts _TenementService) MoveOutTenement(pid, tid string, reading []*vo.MeterR
tx.Rollback(ctx)
return fmt.Errorf("找不到指定表计[%s]的抄表信息,%w", meterCode, err)
}
if reading.Validate() {
if !reading.Validate() {
ts.log.Error("迁出指定商户失败,表计读数不能正确配平,尖锋电量、峰电量、谷电量之和超过总电量。", zap.String("Meter", meterCode))
tx.Rollback(ctx)
return fmt.Errorf("表计[%s]读数不能正确配平,尖锋电量、峰电量、谷电量之和超过总电量。", meterCode)

View File

@ -1,22 +1,24 @@
package vo
import (
"electricity_bill_calc/model"
"electricity_bill_calc/types"
"time"
"github.com/shopspring/decimal"
)
type MeterCreationForm struct {
Code string `json:"code"`
Address *string `json:"address"`
Ratio decimal.Decimal `json:"ratio"`
Seq int64 `json:"seq"`
MeterType int16 `json:"type"`
Building *string `json:"building"`
OnFloor *string `json:"onFloor"`
Area decimal.NullDecimal `json:"area"`
Enabled bool `json:"enabled"`
MeterReadingForm `json:"-"`
Code string `json:"code"`
Address *string `json:"address"`
Ratio decimal.Decimal `json:"ratio"`
Seq int64 `json:"seq"`
MeterType int16 `json:"type"`
Building *string `json:"building"`
OnFloor *string `json:"onFloor"`
Area decimal.NullDecimal `json:"area"`
Enabled bool `json:"enabled"`
Reading MeterReadingForm `json:"reading"`
}
type MeterModificationForm struct {
@ -59,7 +61,7 @@ type SimplifiedMeterDetailResponse struct {
Area decimal.Decimal `json:"area"`
Enabled bool `json:"enabled"`
MeterType int16 `json:"type"`
AttachedAt types.DateTime `json:"attachedAt"`
AttachedAt *types.DateTime `json:"attachedAt"`
DetachedAt *types.DateTime `json:"detachedAt"`
}
type ReadableMeterQueryResponse struct {
@ -67,3 +69,54 @@ type ReadableMeterQueryResponse struct {
Address *string `json:"address"`
Park string `json:"park"`
}
type ReportPublishResponse struct {
//ID string
ReportID string `json:"report_id" db:"report_id"` // 报告ID
ParkMeterID string `json:"park_meter_id" db:"park_meter_id"` // 停车计费ID
Overall model.ConsumptionUnit `json:"overall" db:"overall"` // 总体信息
Critical model.ConsumptionUnit `json:"critical" db:"critical"` // 关键信息
Peak model.ConsumptionUnit `json:"peak" db:"peak"` // 高峰信息
Flat model.ConsumptionUnit `json:"flat" db:"flat"` // 平峰信息
Valley model.ConsumptionUnit `json:"valley" db:"valley"` // 谷峰信息
LossAdjust model.ConsumptionUnit `json:"loss_adjust" db:"loss_adjust"` // 损耗调整信息
ConsumptionTotal float64 `json:"consumption_total" db:"consumption_total"` // 总消费量
LossAdjustTotal float64 `json:"loss_adjust_total" db:"loss_adjust_total"` // 总损耗调整
FinalTotal float64 `json:"final_total" db:"final_total"` // 最终总量
CreatedAt time.Time `json:"created_at" db:"created_at"` // 创建时间
LastModifiedAt time.Time `json:"last_modified_at" db:"last_modified_at"` // 最后修改时间
Code string `json:"code" db:"code"` // 代码
ParkID string `json:"park_id" db:"park_id"` // 停车场ID
Address *string `json:"address" db:"address"` // 地址
Ratio decimal.Decimal `json:"ratio" db:"ratio"` // 比率
Seq int64 `json:"seq" db:"seq"` // 序列号
Enabled bool `json:"enabled" db:"enabled"` // 是否启用
MeterType int16 `json:"meter_type" db:"meter_type"` // 计量类型
Building *string `json:"building" db:"building"` // 建筑物
OnFloor *string `json:"on_floor" db:"on_floor"` // 楼层
Area decimal.NullDecimal `json:"area" db:"area"` // 面积
AttachedAt *types.DateTime `json:"attached_at" db:"attached_at"` // 附加时间
DetachedAt *types.DateTime `json:"detached_at" db:"detached_at"` // 分离时间
DisplayRatio float64 `json:"display_ratio" db:"display_ratio"` // 显示比例
BuildingName *string `json:"building_name" db:"building_name"` // 建筑物名称
PublicPooled int16 `json:"public_pooled" db:"public_pooled"` // 公共汇总
}
type Public struct {
Address *string `json:"address"` // 户址
AdjustLoss model.ConsumptionUnit `json:"adjustLoss"` // 调整线损数据,仅运维可见,仅使用其中`amount`内容
Area string `json:"area"` // 所辖面积
AttachedAt *types.DateTime `json:"attachedAt"` // 接入系统时间,挂表
Building *string `json:"building"` // 所在建筑ID
BuildingName *string `json:"buildingName"` // 所在建筑名称
Code string `json:"code"` // 表计表号
DetachedAt *types.DateTime `json:"detachedAt"` // 从系统移除时间,拆表
DisplayRatio string `json:"displayRatio"` // 表计表显倍率,仅用于展示。
Enabled bool `json:"enabled"` // 是否可用
OnFloor *string `json:"onFloor"` // 所在楼层
Overall model.ConsumptionUnit `json:"overall"` // 总电量部分
ParkID string `json:"parkId"` // 所属园区ID
Ratio string `json:"ratio"` // 表计计算倍率,参与表计读数计算。
Seq int64 `json:"seq"` // 抄表序号
Type float64 `json:"type"` // 表计类型0商户电表1园区电表2公摊电表
}

View File

@ -4,7 +4,6 @@ import (
"electricity_bill_calc/model"
"electricity_bill_calc/types"
"fmt"
"github.com/shopspring/decimal"
)
@ -19,7 +18,8 @@ type MeterReadingForm struct {
func (r MeterReadingForm) Validate() bool {
flat := r.Overall.Sub(r.Critical).Sub(r.Peak).Sub(r.Valley)
return flat.GreaterThanOrEqual(decimal.Zero)
b := flat.GreaterThanOrEqual(decimal.Zero)
return b
}
type MeterReadingFormWithCode struct {

View File

@ -18,6 +18,7 @@ type TenementCreationForm struct {
InvoicePhone *string `json:"invoicePhone"`
Bank *string `json:"bank"`
Account *string `json:"bankAccount"`
MoveIn *string `json:"moveIn"`
}
type TenementQueryResponse struct {

View File

@ -22,4 +22,5 @@ type TopUpDetailQueryResponse struct {
Amount decimal.Decimal `json:"amount"`
PaymentType int16 `json:"paymentType"`
SyncStatus int16 `json:"syncStatus" copier:"SyncStatus"`
CancelledAt *types.DateTime `json:"cancelledAt"` // TODO: 2023.08.11 在查询充值记录的时候发现缺少该字段(已添加)
}