Files
tyapi-server/internal/domains/finance/entities/invoice_application.go
2025-08-02 02:54:21 +08:00

163 lines
5.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package entities
import (
"time"
"github.com/google/uuid"
"github.com/shopspring/decimal"
"gorm.io/gorm"
"tyapi-server/internal/domains/finance/value_objects"
)
// ApplicationStatus 申请状态枚举
type ApplicationStatus string
const (
ApplicationStatusPending ApplicationStatus = "pending" // 待处理
ApplicationStatusCompleted ApplicationStatus = "completed" // 已完成(已上传发票)
ApplicationStatusRejected ApplicationStatus = "rejected" // 已拒绝
)
// InvoiceApplication 发票申请聚合根
type InvoiceApplication struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"申请唯一标识"`
UserID string `gorm:"type:varchar(36);not null;index" json:"user_id" comment:"申请用户ID"`
// 申请信息
InvoiceType value_objects.InvoiceType `gorm:"type:varchar(20);not null" json:"invoice_type" comment:"发票类型"`
Amount decimal.Decimal `gorm:"type:decimal(20,8);not null" json:"amount" comment:"申请金额"`
Status ApplicationStatus `gorm:"type:varchar(20);not null;default:'pending';index" json:"status" comment:"申请状态"`
// 开票信息快照(申请时的信息,用于历史记录追踪)
CompanyName string `gorm:"type:varchar(200);not null" json:"company_name" comment:"公司名称"`
TaxpayerID string `gorm:"type:varchar(50);not null" json:"taxpayer_id" comment:"纳税人识别号"`
BankName string `gorm:"type:varchar(100)" json:"bank_name" comment:"开户银行"`
BankAccount string `gorm:"type:varchar(50)" json:"bank_account" comment:"银行账号"`
CompanyAddress string `gorm:"type:varchar(500)" json:"company_address" comment:"企业地址"`
CompanyPhone string `gorm:"type:varchar(20)" json:"company_phone" comment:"企业电话"`
ReceivingEmail string `gorm:"type:varchar(100);not null" json:"receiving_email" comment:"发票接收邮箱"`
// 开票信息引用(关联到用户开票信息表,用于模板功能)
UserInvoiceInfoID string `gorm:"type:varchar(36);not null" json:"user_invoice_info_id" comment:"用户开票信息ID"`
// 文件信息(申请通过后才有)
FileID *string `gorm:"type:varchar(200)" json:"file_id,omitempty" comment:"文件ID"`
FileName *string `gorm:"type:varchar(200)" json:"file_name,omitempty" comment:"文件名"`
FileSize *int64 `json:"file_size,omitempty" comment:"文件大小"`
FileURL *string `gorm:"type:varchar(500)" json:"file_url,omitempty" comment:"文件URL"`
// 处理信息
ProcessedBy *string `gorm:"type:varchar(36)" json:"processed_by,omitempty" comment:"处理人ID"`
ProcessedAt *time.Time `json:"processed_at,omitempty" comment:"处理时间"`
RejectReason *string `gorm:"type:varchar(500)" json:"reject_reason,omitempty" comment:"拒绝原因"`
AdminNotes *string `gorm:"type:varchar(500)" json:"admin_notes,omitempty" comment:"管理员备注"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
}
// TableName 指定数据库表名
func (InvoiceApplication) TableName() string {
return "invoice_applications"
}
// BeforeCreate GORM钩子创建前自动生成UUID
func (ia *InvoiceApplication) BeforeCreate(tx *gorm.DB) error {
if ia.ID == "" {
ia.ID = uuid.New().String()
}
return nil
}
// IsPending 检查是否为待处理状态
func (ia *InvoiceApplication) IsPending() bool {
return ia.Status == ApplicationStatusPending
}
// IsCompleted 检查是否为已完成状态
func (ia *InvoiceApplication) IsCompleted() bool {
return ia.Status == ApplicationStatusCompleted
}
// IsRejected 检查是否为已拒绝状态
func (ia *InvoiceApplication) IsRejected() bool {
return ia.Status == ApplicationStatusRejected
}
// CanProcess 检查是否可以处理
func (ia *InvoiceApplication) CanProcess() bool {
return ia.IsPending()
}
// CanReject 检查是否可以拒绝
func (ia *InvoiceApplication) CanReject() bool {
return ia.IsPending()
}
// MarkCompleted 标记为已完成
func (ia *InvoiceApplication) MarkCompleted(processedBy string) {
ia.Status = ApplicationStatusCompleted
ia.ProcessedBy = &processedBy
now := time.Now()
ia.ProcessedAt = &now
}
// MarkRejected 标记为已拒绝
func (ia *InvoiceApplication) MarkRejected(reason string, processedBy string) {
ia.Status = ApplicationStatusRejected
ia.RejectReason = &reason
ia.ProcessedBy = &processedBy
now := time.Now()
ia.ProcessedAt = &now
}
// SetFileInfo 设置文件信息
func (ia *InvoiceApplication) SetFileInfo(fileID, fileName, fileURL string, fileSize int64) {
ia.FileID = &fileID
ia.FileName = &fileName
ia.FileURL = &fileURL
ia.FileSize = &fileSize
}
// NewInvoiceApplication 工厂方法
func NewInvoiceApplication(userID string, invoiceType value_objects.InvoiceType, amount decimal.Decimal, userInvoiceInfoID string) *InvoiceApplication {
return &InvoiceApplication{
UserID: userID,
InvoiceType: invoiceType,
Amount: amount,
Status: ApplicationStatusPending,
UserInvoiceInfoID: userInvoiceInfoID,
}
}
// SetInvoiceInfoSnapshot 设置开票信息快照
func (ia *InvoiceApplication) SetInvoiceInfoSnapshot(info *value_objects.InvoiceInfo) {
ia.CompanyName = info.CompanyName
ia.TaxpayerID = info.TaxpayerID
ia.BankName = info.BankName
ia.BankAccount = info.BankAccount
ia.CompanyAddress = info.CompanyAddress
ia.CompanyPhone = info.CompanyPhone
ia.ReceivingEmail = info.ReceivingEmail
}
// GetInvoiceInfoSnapshot 获取开票信息快照
func (ia *InvoiceApplication) GetInvoiceInfoSnapshot() *value_objects.InvoiceInfo {
return value_objects.NewInvoiceInfo(
ia.CompanyName,
ia.TaxpayerID,
ia.BankName,
ia.BankAccount,
ia.CompanyAddress,
ia.CompanyPhone,
ia.ReceivingEmail,
)
}