electricity_bill_calc_service/repository/tenement.go
2023-08-04 17:11:10 +08:00

459 lines
15 KiB
Go

package repository
import (
"context"
"electricity_bill_calc/config"
"electricity_bill_calc/global"
"electricity_bill_calc/logger"
"electricity_bill_calc/model"
"electricity_bill_calc/tools"
"electricity_bill_calc/tools/serial"
"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"
"go.uber.org/zap"
)
type _TenementRepository struct {
log *zap.Logger
ds goqu.DialectWrapper
}
var TenementRepository = _TenementRepository{
log: logger.Named("Repository", "Tenement"),
ds: goqu.Dialect("postgres"),
}
// 判断指定商户是否属于指定用户的管辖
func (tr _TenementRepository) IsTenementBelongs(tid, uid string) (bool, error) {
tr.log.Info("检查指定商户是否属于指定企业管辖", zap.String("Tenement", tid), zap.String("Enterprise", uid))
ctx, cancel := global.TimeoutContext()
defer cancel()
countSql, countArgs, _ := tr.ds.
From(goqu.T("tenement").As("t")).
Join(goqu.T("park").As("p"), goqu.On(goqu.I("t.park_id").Eq(goqu.I("p.id")))).
Select(goqu.COUNT("t.*")).
Where(
goqu.I("t.id").Eq(tid),
goqu.I("p.user_id").Eq(uid),
).
Prepared(true).ToSQL()
var count int
if err := pgxscan.Get(ctx, global.DB, &count, countSql, countArgs...); err != nil {
tr.log.Error("检查指定商户是否属于指定企业管辖失败", zap.Error(err))
return false, err
}
return count > 0, nil
}
// 列出指定园区中的所有商户
func (tr _TenementRepository) ListTenements(pid string, page uint, keyword, building *string, startDate, endDate *types.Date, state int) ([]*model.Tenement, int64, error) {
tr.log.Info(
"检索查询指定园区中符合条件的商户",
zap.String("Park", pid),
zap.Uint("Page", page),
zap.Stringp("Keyword", keyword),
zap.Stringp("Building", building),
logger.DateFieldp("StartDate", startDate),
logger.DateFieldp("EndDate", endDate),
zap.Int("State", state),
)
ctx, cancel := global.TimeoutContext()
defer cancel()
tenementQuery := tr.ds.
From(goqu.T("tenement").As("t")).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("t.building")))).
Select("t.*", goqu.I("b.name").As("building_name")).
Where(goqu.I("t.park_id").Eq(pid))
countQuery := tr.ds.
From(goqu.T("tenement").As("t")).
Select(goqu.COUNT("t.*")).
Where(goqu.I("t.park_id").Eq(pid))
if keyword != nil && len(*keyword) > 0 {
pattern := fmt.Sprintf("%%%s%%", *keyword)
tenementQuery = tenementQuery.Where(
goqu.Or(
goqu.I("t.full_name").ILike(pattern),
goqu.I("t.short_name").ILike(pattern),
goqu.I("t.abbr").ILike(pattern),
goqu.I("t.contact_name").ILike(pattern),
goqu.I("t.contact_phone").ILike(pattern),
goqu.I("t.address").ILike(pattern),
),
)
countQuery = countQuery.Where(
goqu.Or(
goqu.I("t.full_name").ILike(pattern),
goqu.I("t.short_name").ILike(pattern),
goqu.I("t.abbr").ILike(pattern),
goqu.I("t.contact_name").ILike(pattern),
goqu.I("t.contact_phone").ILike(pattern),
goqu.I("t.address").ILike(pattern),
),
)
}
if building != nil && len(*building) > 0 {
tenementQuery = tenementQuery.Where(goqu.I("t.building").Eq(*building))
countQuery = countQuery.Where(goqu.I("t.building").Eq(*building))
}
if startDate != nil {
tenementQuery = tenementQuery.Where(
goqu.Or(
goqu.I("t.moved_in_at").Gte(startDate.ToBeginningOfDate()),
goqu.I("t.moved_out_at").Gte(startDate.ToBeginningOfDate()),
),
)
countQuery = countQuery.Where(
goqu.Or(
goqu.I("t.moved_in_at").Gte(startDate.ToBeginningOfDate()),
goqu.I("t.moved_out_at").Gte(startDate.ToBeginningOfDate()),
),
)
}
if endDate != nil {
tenementQuery = tenementQuery.Where(
goqu.Or(
goqu.I("t.moved_in_at").Lte(endDate.ToEndingOfDate()),
goqu.I("t.moved_out_at").Lte(endDate.ToEndingOfDate()),
),
)
countQuery = countQuery.Where(
goqu.Or(
goqu.I("t.moved_in_at").Lte(endDate.ToEndingOfDate()),
goqu.I("t.moved_out_at").Lte(endDate.ToEndingOfDate()),
),
)
}
if state == 0 {
tenementQuery = tenementQuery.Where(
goqu.I("t.moved_out_at").IsNull(),
)
countQuery = countQuery.Where(
goqu.I("t.moved_out_at").IsNull(),
)
} else {
tenementQuery = tenementQuery.Where(
goqu.I("t.moved_out_at").IsNotNull(),
)
countQuery = countQuery.Where(
goqu.I("t.moved_out_at").IsNotNull(),
)
}
startRow := (page - 1) * config.ServiceSettings.ItemsPageSize
tenementQuery = tenementQuery.Order(goqu.I("t.created_at").Desc()).Limit(config.ServiceSettings.ItemsPageSize).Offset(startRow)
tenementSql, tenementArgs, _ := tenementQuery.Prepared(true).ToSQL()
countSql, countArgs, _ := countQuery.Prepared(true).ToSQL()
var (
tenements []*model.Tenement = make([]*model.Tenement, 0)
total int64
)
if err := pgxscan.Select(ctx, global.DB, &tenements, tenementSql, tenementArgs...); err != nil {
tr.log.Error("检索查询指定园区中符合条件的商户失败", zap.Error(err))
return tenements, 0, err
}
if err := pgxscan.Get(ctx, global.DB, &total, countSql, countArgs...); err != nil {
tr.log.Error("检索查询指定园区中符合条件的商户总数量失败", zap.Error(err))
return tenements, 0, err
}
return tenements, total, nil
}
// 查询指定园区中某一商户下的所有表计编号,不包含公摊表计
func (tr _TenementRepository) ListMeterCodesBelongsTo(pid, tid string) ([]string, error) {
tr.log.Info("查询指定商户下所有的表计编号", zap.String("Park", pid), zap.String("Tenement", tid))
ctx, cancel := global.TimeoutContext()
defer cancel()
sql, args, _ := tr.ds.
From("tenement_meter").
Select("meter_id").
Where(
goqu.I("park_id").Eq(pid),
goqu.I("tenement_id").Eq(tid),
goqu.I("disassociated_at").IsNull(),
).
Prepared(true).ToSQL()
var meterCodes []string = make([]string, 0)
if err := pgxscan.Select(ctx, global.DB, &meterCodes, sql, args...); err != nil {
tr.log.Error("查询指定商户下所有的表计编号失败", zap.Error(err))
return meterCodes, err
}
return meterCodes, nil
}
// 在指定园区中创建一个新的商户
func (tr _TenementRepository) AddTenement(tx pgx.Tx, ctx context.Context, pid string, tenement *vo.TenementCreationForm) error {
tr.log.Info("在指定园区中创建一个新的商户", zap.String("Park", pid))
serial.StringSerialRequestChan <- 1
tenementId := serial.Prefix("T", <-serial.StringSerialResponseChan)
currentTime := types.Now()
if _, err := tx.Exec(
ctx,
"INSERT INTO tenement (id, park_id, full_name, short_name, abbr, address, contact_name, contact_phone, building, on_floor, invoice_info, moved_in_at, created_at, last_modified_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)",
[]interface{}{
tenementId,
pid,
tenement.Name,
tenement.ShortName,
tools.PinyinAbbr(tenement.Name),
tenement.Address,
tenement.Contact,
tenement.Phone,
tenement.Building,
tenement.OnFloor,
&model.InvoiceTitle{
Name: tenement.Name,
USCI: tenement.USCI,
Address: tools.DefaultOrEmptyStr(tenement.InvoiceAddress, ""),
Phone: tools.DefaultOrEmptyStr(tenement.InvoicePhone, ""),
Bank: tools.DefaultOrEmptyStr(tenement.Bank, ""),
Account: tools.DefaultOrEmptyStr(tenement.Account, ""),
},
currentTime,
currentTime,
currentTime,
}...,
); err != nil {
tr.log.Error("在指定园区中创建一个新的商户失败", zap.Error(err))
return err
}
return nil
}
// 向园区中指定商户下绑定一个新的表计
func (tr _TenementRepository) BindMeter(tx pgx.Tx, ctx context.Context, pid, tid, meter string) error {
tr.log.Info("向园区中指定商户下绑定一个新的表计", zap.String("Park", pid), zap.String("Tenement", tid), zap.String("Meter", meter))
createSql, createArgs, _ := tr.ds.
Insert("tenement_meter").
Cols(
"park_id", "tenement_id", "meter_id", "associated_at",
).
Vals(
goqu.Vals{
pid,
tid,
meter,
types.Now(),
},
).
Prepared(true).ToSQL()
if _, err := tx.Exec(ctx, createSql, createArgs...); err != nil {
tr.log.Error("向园区中指定商户下绑定一个新的表计失败", zap.Error(err))
return err
}
return nil
}
// 将指定商户与指定表计解绑
func (tr _TenementRepository) UnbindMeter(tx pgx.Tx, ctx context.Context, pid, tid, meter string) error {
tr.log.Info("将指定商户与指定表计解绑", zap.String("Park", pid), zap.String("Tenement", tid), zap.String("Meter", meter))
updateSql, updateArgs, _ := tr.ds.
Update("tenement_meter").
Set(
goqu.Record{
"disassociated_at": types.Now(),
},
).
Where(
goqu.I("park_id").Eq(pid),
goqu.I("tenement_id").Eq(tid),
goqu.I("meter_id").Eq(meter),
).
Prepared(true).ToSQL()
if _, err := tx.Exec(ctx, updateSql, updateArgs...); err != nil {
tr.log.Error("将指定商户与指定表计解绑失败", zap.Error(err))
return err
}
return nil
}
// 修改指定商户的信息
func (tr _TenementRepository) UpdateTenement(pid, tid string, tenement *vo.TenementCreationForm) error {
tr.log.Info("修改指定商户的信息", zap.String("Park", pid), zap.String("Tenement", tid))
ctx, cancel := global.TimeoutContext()
defer cancel()
updateSql, updateArgs, _ := tr.ds.
Update("tenement").
Set(
goqu.Record{
"full_name": tenement.Name,
"short_name": tenement.ShortName,
"abbr": tools.PinyinAbbr(tenement.Name),
"address": tenement.Address,
"contact_name": tenement.Contact,
"contact_phone": tenement.Phone,
"building": tenement.Building,
"on_floor": tenement.OnFloor,
"invoice_info": &model.InvoiceTitle{
Name: tenement.Name,
USCI: tenement.USCI,
Address: tools.DefaultOrEmptyStr(tenement.InvoiceAddress, ""),
Phone: tools.DefaultOrEmptyStr(tenement.InvoicePhone, ""),
Bank: tools.DefaultOrEmptyStr(tenement.Bank, ""),
Account: tools.DefaultOrEmptyStr(tenement.Account, ""),
},
"last_modified_at": types.Now(),
},
).
Where(
goqu.I("id").Eq(tid),
goqu.I("park_id").Eq(pid),
).
Prepared(true).ToSQL()
if _, err := global.DB.Exec(ctx, updateSql, updateArgs...); err != nil {
tr.log.Error("修改指定商户的信息失败", zap.Error(err))
return err
}
return nil
}
// 迁出指定商户
func (tr _TenementRepository) MoveOut(tx pgx.Tx, ctx context.Context, pid, tid string) error {
tr.log.Info("迁出指定商户", zap.String("Park", pid), zap.String("Tenement", tid))
updateSql, updateArgs, _ := tr.ds.
Update("tenement").
Set(
goqu.Record{
"moved_out_at": types.Now(),
},
).
Where(
goqu.I("id").Eq(tid),
goqu.I("park_id").Eq(pid),
).
Prepared(true).ToSQL()
if _, err := tx.Exec(ctx, updateSql, updateArgs...); err != nil {
tr.log.Error("迁出指定商户失败", zap.Error(err))
return err
}
return nil
}
// 列出用于下拉列表的符合指定条件的商户信息
func (tr _TenementRepository) ListForSelect(uid string, pid, keyword *string, limit *uint) ([]*model.Tenement, error) {
tr.log.Info("列出用于下拉列表的符合指定条件的商户信息", zap.String("Ent", uid), zap.String("Park", tools.DefaultOrEmptyStr(pid, "All")), zap.Stringp("Keyword", keyword), zap.Uintp("Limit", limit))
ctx, cancel := global.TimeoutContext()
defer cancel()
tenementQuery := tr.ds.
From(goqu.T("tenement").As("t")).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("t.building")))).
Join(goqu.T("park").As("p"), goqu.On(goqu.I("p.id").Eq(goqu.I("t.park_id")))).
Select(
"t.*", goqu.I("b.name").As("building_name"),
).
Where(
goqu.I("p.user_id").Eq(uid),
goqu.I("t.moved_out_at").IsNull(),
)
if pid != nil && len(*pid) > 0 {
tenementQuery = tenementQuery.Where(goqu.I("p.id").Eq(*pid))
}
if keyword != nil && len(*keyword) > 0 {
pattern := fmt.Sprintf("%%%s%%", *keyword)
tenementQuery = tenementQuery.Where(
goqu.Or(
goqu.I("t.full_name").ILike(pattern),
goqu.I("t.short_name").ILike(pattern),
goqu.I("t.abbr").ILike(pattern),
),
)
}
tenementQuery = tenementQuery.Order(goqu.I("t.created_at").Desc())
if limit != nil && *limit > 0 {
tenementQuery = tenementQuery.Limit(*limit)
}
tenementSql, tenementArgs, _ := tenementQuery.Prepared(true).ToSQL()
var tenements = make([]*model.Tenement, 0)
if err := pgxscan.Select(ctx, global.DB, &tenements, tenementSql, tenementArgs...); err != nil {
tr.log.Error("列出用于下拉列表的符合指定条件的商户信息失败", zap.Error(err))
return tenements, err
}
return tenements, nil
}
// 列出指定园区中在指定时间区间内存在过入住的商户
func (tr _TenementRepository) ListTenementsInTimeRange(pid string, start, end types.Date) ([]*model.Tenement, error) {
tr.log.Info("列出指定园区中在指定时间区间内存在过入住的商户", zap.String("Park", pid), logger.DateField("Start", start), logger.DateField("End", end))
ctx, cancel := global.TimeoutContext()
defer cancel()
tenementQuery := tr.ds.
From(goqu.T("tenement").As("t")).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("t.building")))).
Select(
"t.*", goqu.I("b.name").As("building_name"),
).
Where(
goqu.I("t.park_id").Eq(pid),
goqu.I("t.moved_in_at").Lte(end.ToEndingOfDate()),
goqu.Or(
goqu.I("t.moved_out_at").IsNull(),
goqu.I("t.moved_out_at").Gte(start.ToBeginningOfDate()),
),
).
Order(goqu.I("t.created_at").Desc())
tenementSql, tenementArgs, _ := tenementQuery.Prepared(true).ToSQL()
var tenements = make([]*model.Tenement, 0)
if err := pgxscan.Select(ctx, global.DB, &tenements, tenementSql, tenementArgs...); err != nil {
tr.log.Error("列出指定园区中在指定时间区间内存在过入住的商户失败", zap.Error(err))
return tenements, err
}
return tenements, nil
}
// 获取指定园区中指定商户的详细信息
func (tr _TenementRepository) RetrieveTenementDetail(pid, tid string) (*model.Tenement, error) {
tr.log.Info("获取指定园区中指定商户的详细信息", zap.String("Park", pid), zap.String("Tenement", tid))
ctx, cancel := global.TimeoutContext()
defer cancel()
tenementSql, tenementArgs, _ := tr.ds.
From(goqu.T("tenement").As("t")).
LeftJoin(goqu.T("park_building").As("b"), goqu.On(goqu.I("b.id").Eq(goqu.I("t.building")))).
Select(
"t.*", goqu.I("b.name").As("building_name"),
).
Where(
goqu.I("t.id").Eq(tid),
goqu.I("t.park_id").Eq(pid),
).
Prepared(true).ToSQL()
var tenement model.Tenement
if err := pgxscan.Get(ctx, global.DB, &tenement, tenementSql, tenementArgs...); err != nil {
tr.log.Error("获取指定园区中指定商户的详细信息失败", zap.Error(err))
return nil, err
}
return &tenement, nil
}