v1.0.0
This commit is contained in:
152
internal/domains/finance/services/invoice_domain_service.go
Normal file
152
internal/domains/finance/services/invoice_domain_service.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"tyapi-server/internal/domains/finance/entities"
|
||||
"tyapi-server/internal/domains/finance/value_objects"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// InvoiceDomainService 发票领域服务接口
|
||||
// 职责:处理发票领域的业务规则和计算逻辑,不涉及外部依赖
|
||||
type InvoiceDomainService interface {
|
||||
// 验证发票信息完整性
|
||||
ValidateInvoiceInfo(ctx context.Context, info *value_objects.InvoiceInfo, invoiceType value_objects.InvoiceType) error
|
||||
|
||||
// 验证开票金额是否合法(基于业务规则)
|
||||
ValidateInvoiceAmount(ctx context.Context, amount decimal.Decimal, availableAmount decimal.Decimal) error
|
||||
|
||||
// 计算可开票金额(纯计算逻辑)
|
||||
CalculateAvailableAmount(totalRecharged decimal.Decimal, totalGifted decimal.Decimal, totalInvoiced decimal.Decimal) decimal.Decimal
|
||||
|
||||
// 验证发票申请状态转换
|
||||
ValidateStatusTransition(currentStatus entities.ApplicationStatus, targetStatus entities.ApplicationStatus) error
|
||||
|
||||
// 验证发票申请业务规则
|
||||
ValidateInvoiceApplication(ctx context.Context, application *entities.InvoiceApplication) error
|
||||
}
|
||||
|
||||
// InvoiceDomainServiceImpl 发票领域服务实现
|
||||
type InvoiceDomainServiceImpl struct {
|
||||
// 领域服务不依赖仓储,只处理业务规则
|
||||
}
|
||||
|
||||
// NewInvoiceDomainService 创建发票领域服务
|
||||
func NewInvoiceDomainService() InvoiceDomainService {
|
||||
return &InvoiceDomainServiceImpl{}
|
||||
}
|
||||
|
||||
// ValidateInvoiceInfo 验证发票信息完整性
|
||||
func (s *InvoiceDomainServiceImpl) ValidateInvoiceInfo(ctx context.Context, info *value_objects.InvoiceInfo, invoiceType value_objects.InvoiceType) error {
|
||||
if info == nil {
|
||||
return errors.New("发票信息不能为空")
|
||||
}
|
||||
|
||||
switch invoiceType {
|
||||
case value_objects.InvoiceTypeGeneral:
|
||||
return info.ValidateForGeneralInvoice()
|
||||
case value_objects.InvoiceTypeSpecial:
|
||||
return info.ValidateForSpecialInvoice()
|
||||
default:
|
||||
return errors.New("无效的发票类型")
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateInvoiceAmount 验证开票金额是否合法(基于业务规则)
|
||||
func (s *InvoiceDomainServiceImpl) ValidateInvoiceAmount(ctx context.Context, amount decimal.Decimal, availableAmount decimal.Decimal) error {
|
||||
if amount.LessThanOrEqual(decimal.Zero) {
|
||||
return errors.New("开票金额必须大于0")
|
||||
}
|
||||
|
||||
if amount.GreaterThan(availableAmount) {
|
||||
return fmt.Errorf("开票金额不能超过可开票金额,可开票金额:%s", availableAmount.String())
|
||||
}
|
||||
|
||||
// 最小开票金额限制
|
||||
minAmount := decimal.NewFromFloat(0.01) // 最小0.01元
|
||||
if amount.LessThan(minAmount) {
|
||||
return fmt.Errorf("开票金额不能少于%s元", minAmount.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalculateAvailableAmount 计算可开票金额(纯计算逻辑)
|
||||
func (s *InvoiceDomainServiceImpl) CalculateAvailableAmount(totalRecharged decimal.Decimal, totalGifted decimal.Decimal, totalInvoiced decimal.Decimal) decimal.Decimal {
|
||||
// 可开票金额 = 充值金额 - 已开票金额(不包含赠送金额)
|
||||
availableAmount := totalRecharged.Sub(totalInvoiced)
|
||||
if availableAmount.LessThan(decimal.Zero) {
|
||||
availableAmount = decimal.Zero
|
||||
}
|
||||
return availableAmount
|
||||
}
|
||||
|
||||
// ValidateStatusTransition 验证发票申请状态转换
|
||||
func (s *InvoiceDomainServiceImpl) ValidateStatusTransition(currentStatus entities.ApplicationStatus, targetStatus entities.ApplicationStatus) error {
|
||||
// 定义允许的状态转换
|
||||
allowedTransitions := map[entities.ApplicationStatus][]entities.ApplicationStatus{
|
||||
entities.ApplicationStatusPending: {
|
||||
entities.ApplicationStatusCompleted,
|
||||
entities.ApplicationStatusRejected,
|
||||
},
|
||||
entities.ApplicationStatusCompleted: {
|
||||
// 已完成状态不能再转换
|
||||
},
|
||||
entities.ApplicationStatusRejected: {
|
||||
// 已拒绝状态不能再转换
|
||||
},
|
||||
}
|
||||
|
||||
allowedTargets, exists := allowedTransitions[currentStatus]
|
||||
if !exists {
|
||||
return fmt.Errorf("无效的当前状态:%s", currentStatus)
|
||||
}
|
||||
|
||||
for _, allowed := range allowedTargets {
|
||||
if allowed == targetStatus {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("不允许从状态 %s 转换到状态 %s", currentStatus, targetStatus)
|
||||
}
|
||||
|
||||
// ValidateInvoiceApplication 验证发票申请业务规则
|
||||
func (s *InvoiceDomainServiceImpl) ValidateInvoiceApplication(ctx context.Context, application *entities.InvoiceApplication) error {
|
||||
if application == nil {
|
||||
return errors.New("发票申请不能为空")
|
||||
}
|
||||
|
||||
// 验证基础字段
|
||||
if application.UserID == "" {
|
||||
return errors.New("用户ID不能为空")
|
||||
}
|
||||
|
||||
if application.Amount.LessThanOrEqual(decimal.Zero) {
|
||||
return errors.New("申请金额必须大于0")
|
||||
}
|
||||
|
||||
// 验证发票类型
|
||||
if !application.InvoiceType.IsValid() {
|
||||
return errors.New("无效的发票类型")
|
||||
}
|
||||
|
||||
// 验证开票信息
|
||||
if application.CompanyName == "" {
|
||||
return errors.New("公司名称不能为空")
|
||||
}
|
||||
|
||||
if application.TaxpayerID == "" {
|
||||
return errors.New("纳税人识别号不能为空")
|
||||
}
|
||||
|
||||
if application.ReceivingEmail == "" {
|
||||
return errors.New("发票接收邮箱不能为空")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user