feat(invoice):基本完成发票相关功能的服务操作函数。
This commit is contained in:
parent
11bd661e79
commit
e88477a710
180
service/invoice.go
Normal file
180
service/invoice.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"electricity_bill_calc/exceptions"
|
||||
"electricity_bill_calc/global"
|
||||
"electricity_bill_calc/logger"
|
||||
"electricity_bill_calc/model"
|
||||
"electricity_bill_calc/repository"
|
||||
"electricity_bill_calc/types"
|
||||
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
|
||||
"github.com/samber/lo"
|
||||
"github.com/shopspring/decimal"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type _InvoiceSerivce struct {
|
||||
log *zap.Logger
|
||||
ds goqu.DialectWrapper
|
||||
}
|
||||
|
||||
var InvoiceService = _InvoiceSerivce{
|
||||
log: logger.Named("Service", "Invoice"),
|
||||
ds: goqu.Dialect("postgres"),
|
||||
}
|
||||
|
||||
// 获取指定的发票信息,包括发票覆盖的商户核算信息
|
||||
func (is _InvoiceSerivce) GetInvoice(invoiceNo string) (*model.Invoice, []*model.SimplifiedTenementCharge, error) {
|
||||
is.log.Info("获取指定发票的信息", zap.String("InvoiceNo", invoiceNo))
|
||||
invoice, err := repository.InvoiceRepository.GetInvoiceDetail(invoiceNo)
|
||||
if err != nil || invoice == nil {
|
||||
is.log.Error("获取指定发票的信息失败", zap.Error(err))
|
||||
return nil, nil, exceptions.NewNotFoundError("指定发票信息不存在。")
|
||||
}
|
||||
|
||||
charges, err := repository.InvoiceRepository.GetSimplifiedTenementCharges(invoice.Tenement, invoice.Covers)
|
||||
if err != nil {
|
||||
is.log.Error("获取指定发票的信息失败", zap.Error(err))
|
||||
return nil, nil, err
|
||||
}
|
||||
return invoice, charges, nil
|
||||
}
|
||||
|
||||
// 根据给定的商户核算记录和发票基本信息,计算发票中的货物信息
|
||||
func (is _InvoiceSerivce) CalculateInvoiceAmount(method int16, rate decimal.Decimal, reports []*model.SimplifiedTenementCharge) (decimal.Decimal, []*model.InvoiceCargo, error) {
|
||||
is.log.Info("计算指定商户发票中的货物信息", zap.Int16("Method", method), logger.DecimalField("Rate", rate))
|
||||
tenementConsumptionTotal := lo.Reduce(reports, func(agg decimal.Decimal, r *model.SimplifiedTenementCharge, _ int) decimal.Decimal {
|
||||
return agg.Add(r.TotalConsumption)
|
||||
}, decimal.Zero)
|
||||
tenementChargeTotal := lo.Reduce(reports, func(agg decimal.Decimal, r *model.SimplifiedTenementCharge, _ int) decimal.Decimal {
|
||||
return agg.Add(r.FinalCharge)
|
||||
}, decimal.Zero)
|
||||
if tenementConsumptionTotal.IsZero() {
|
||||
err := exceptions.NewInsufficientDataError("TotalConsumption", "商户核算记录中没有电量消耗数据。")
|
||||
is.log.Warn("计算指定商户发票中的货物信息失败", zap.Error(err))
|
||||
return decimal.Zero, nil, err
|
||||
}
|
||||
var tenementTaxTotal, chargePrice, cargoTotal decimal.Decimal
|
||||
switch method {
|
||||
case model.TAX_METHOD_INCLUSIVE:
|
||||
tenementTaxTotal = tenementChargeTotal.Div(rate.Add(decimal.NewFromInt(1))).Mul(rate)
|
||||
chargePrice = (tenementChargeTotal.Sub(tenementTaxTotal)).Div(tenementConsumptionTotal)
|
||||
cargoTotal = tenementChargeTotal
|
||||
case model.TAX_METHOD_EXCLUSIVE:
|
||||
tenementTaxTotal = tenementChargeTotal.Mul(rate)
|
||||
chargePrice = tenementChargeTotal.Div(tenementConsumptionTotal)
|
||||
cargoTotal = tenementChargeTotal.Add(tenementTaxTotal)
|
||||
default:
|
||||
return decimal.Zero, make([]*model.InvoiceCargo, 0), exceptions.NewIllegalArgumentsError("不支持的税率计算方式。")
|
||||
}
|
||||
cargos := []*model.InvoiceCargo{
|
||||
{
|
||||
Name: "电费",
|
||||
Unit: "千瓦时",
|
||||
Quantity: tenementConsumptionTotal,
|
||||
Price: chargePrice.RoundBank(2),
|
||||
Total: tenementChargeTotal.RoundBank(2),
|
||||
TaxRate: rate.RoundBank(2),
|
||||
Tax: tenementTaxTotal.RoundBank(2),
|
||||
},
|
||||
}
|
||||
return cargoTotal.RoundBank(2), cargos, nil
|
||||
}
|
||||
|
||||
// 利用用户提供的内容对发票数据进行试计算
|
||||
func (is _InvoiceSerivce) TestCalculateInvoice(pid, tid string, method int16, rate decimal.NullDecimal, covers []string) (decimal.Decimal, []*model.InvoiceCargo, error) {
|
||||
is.log.Info("试计算发票票面数据", zap.String("Park", pid), zap.String("Tenement", tid), zap.Int16("Method", method), logger.DecimalField("Rate", rate.Decimal))
|
||||
park, err := repository.ParkRepository.RetrieveParkDetail(pid)
|
||||
if err != nil || park == nil {
|
||||
is.log.Error("试计算发票票面数据失败,未能获取到指定园区的信息", zap.Error(err))
|
||||
return decimal.Zero, nil, exceptions.NewNotFoundError("指定的园区不存在。")
|
||||
}
|
||||
if !rate.Valid && !park.TaxRate.Valid {
|
||||
is.log.Error("试计算发票票面数据失败,必须要设定发票税率")
|
||||
return decimal.Zero, nil, exceptions.NewIllegalArgumentsError("必须要设定发票税率。")
|
||||
}
|
||||
taxRate := park.TaxRate.Decimal
|
||||
if rate.Valid {
|
||||
taxRate = rate.Decimal
|
||||
}
|
||||
reports, err := repository.InvoiceRepository.GetSimplifiedTenementCharges(tid, covers)
|
||||
if err != nil {
|
||||
is.log.Error("试计算发票票面数据失败,未能获取到指定商户的核算记录", zap.Error(err))
|
||||
return decimal.Zero, nil, err
|
||||
}
|
||||
return is.CalculateInvoiceAmount(method, taxRate, reports)
|
||||
}
|
||||
|
||||
// 记录一个新的发票信息
|
||||
func (is _InvoiceSerivce) SaveInvoice(pid, tid, invoiceNo string, invoiceType *string, method int16, rate decimal.NullDecimal, covers []string) error {
|
||||
is.log.Info("记录一个新的发票信息", zap.String("Park", pid), zap.String("Tenement", tid), zap.String("InvoiceNo", invoiceNo))
|
||||
park, err := repository.ParkRepository.RetrieveParkDetail(pid)
|
||||
if err != nil || park == nil {
|
||||
is.log.Error("记录一个新的发票信息失败,未能获取到指定园区的信息", zap.Error(err))
|
||||
return exceptions.NewNotFoundError("指定的园区不存在。")
|
||||
}
|
||||
if !rate.Valid && park.TaxRate.Valid {
|
||||
is.log.Error("记录一个新的发票信息失败,必须要设定发票税率")
|
||||
return exceptions.NewIllegalArgumentsError("必须要设定发票税率。")
|
||||
}
|
||||
taxRate := park.TaxRate.Decimal
|
||||
if rate.Valid {
|
||||
taxRate = rate.Decimal
|
||||
}
|
||||
reports, err := repository.InvoiceRepository.GetSimplifiedTenementCharges(tid, covers)
|
||||
if err != nil {
|
||||
is.log.Error("记录一个新的发票信息失败,未能获取到指定商户的核算记录", zap.Error(err))
|
||||
return exceptions.NewUnsuccessQueryError("未能获取到指定商户的核算记录。")
|
||||
}
|
||||
total, cargos, err := is.CalculateInvoiceAmount(method, taxRate, reports)
|
||||
if err != nil {
|
||||
is.log.Error("记录一个新的发票信息失败,未能计算发票票面数据", zap.Error(err))
|
||||
return exceptions.NewUnsuccessCalculateError("未能计算发票票面数据。")
|
||||
}
|
||||
issuedAt := types.Now()
|
||||
|
||||
err = repository.InvoiceRepository.Create(pid, tid, invoiceNo, invoiceType, total, issuedAt, method, taxRate, &cargos, &covers)
|
||||
if err != nil {
|
||||
is.log.Error("记录一个新的发票信息失败,未能保存发票信息", zap.Error(err))
|
||||
return exceptions.NewUnsuccessCreateError("未能保存发票信息。")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 删除指定的发票信息
|
||||
func (is _InvoiceSerivce) DeleteInvoice(invoiceNo string) error {
|
||||
is.log.Info("删除指定的发票信息", zap.String("InvoiceNo", invoiceNo))
|
||||
invoice, err := repository.InvoiceRepository.GetInvoiceDetail(invoiceNo)
|
||||
if err != nil || invoice == nil {
|
||||
is.log.Error("删除指定的发票信息失败,未能获取到指定发票的信息", zap.Error(err))
|
||||
return exceptions.NewNotFoundError("指定的发票信息不存在。")
|
||||
}
|
||||
ctx, cancel := global.TimeoutContext()
|
||||
defer cancel()
|
||||
tx, err := global.DB.Begin(ctx)
|
||||
if err != nil {
|
||||
is.log.Error("删除指定的发票信息失败,未能开启事务", zap.Error(err))
|
||||
return exceptions.NewUnsuccessDBTransactionError("未能开启事务。")
|
||||
}
|
||||
err = repository.InvoiceRepository.Delete(tx, ctx, invoiceNo)
|
||||
if err != nil {
|
||||
is.log.Error("删除指定的发票信息失败,未能删除发票信息", zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return exceptions.NewUnsuccessDeleteError("未能删除发票信息。")
|
||||
}
|
||||
err = repository.InvoiceRepository.DeleteInvoiceTenementRelation(tx, ctx, invoiceNo)
|
||||
if err != nil {
|
||||
is.log.Error("删除指定的发票信息失败,未能删除发票与商户核算记录之间的关联", zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return exceptions.NewUnsuccessDeleteError("未能删除发票与商户核算记录之间的关联。")
|
||||
}
|
||||
err = tx.Commit(ctx)
|
||||
if err != nil {
|
||||
is.log.Error("删除指定的发票信息失败,未能提交事务", zap.Error(err))
|
||||
tx.Rollback(ctx)
|
||||
return exceptions.NewUnsuccessDBTransactionError("未能提交事务。")
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user