-
-
-
- 纳税人识别号从企业认证信息自动获取,不可修改
-
-
-```
-
-#### 修改验证规则
-```javascript
-// 开票信息验证规则
-const infoRules = computed(() => ({
- company_name: invoiceInfo.company_name_read_only ? [] : [
- { required: true, message: '请输入公司名称', trigger: 'blur' }
- ],
- taxpayer_id: invoiceInfo.taxpayer_id_read_only ? [] : [
- { required: true, message: '请输入纳税人识别号', trigger: 'blur' }
- ],
- receiving_email: [
- { required: true, message: '请输入接收邮箱', trigger: 'blur' },
- { type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
- ]
-}))
-```
-
-#### 添加样式
-```css
-/* 只读字段样式 */
-.readonly-field .el-input__inner {
- background-color: #f5f7fa;
- color: #606266;
- cursor: not-allowed;
-}
-
-.field-note {
- font-size: 12px;
- color: #909399;
- margin-top: 4px;
- display: flex;
- align-items: center;
- gap: 4px;
-}
-
-.field-note i {
- font-size: 14px;
-}
-```
-
-#### 修复效果
-- ✅ 公司名称和纳税人识别号字段在编辑状态下显示为禁用状态
-- ✅ 只读字段有明显的视觉区分(灰色背景)
-- ✅ 显示友好的提示信息,说明字段来源
-- ✅ 只读字段不需要验证,避免验证错误
-
-## 测试场景
-
-### 1. 首次访问场景
-- 用户完成企业认证后,首次访问发票页面
-- 公司名称和纳税人识别号应该自动回显
-- 字段显示为只读状态
-
-### 2. 编辑场景
-- 用户点击"编辑信息"按钮
-- 公司名称和纳税人识别号字段应该禁用
-- 显示提示信息说明字段来源
-
-### 3. 保存场景
-- 用户填写其他字段后保存
-- 只读字段不会被验证
-- 保存成功后,只读字段仍然保持禁用状态
-
-### 4. 企业认证信息更新场景
-- 用户更新企业认证信息
-- 重新访问发票页面
-- 公司名称和纳税人识别号应该自动更新
-
-## 技术要点
-
-### 1. 数据流向
-```
-企业认证信息 → 应用服务层 → 领域服务层 → 前端页面
-```
-
-### 2. 权限控制
-- 公司名称和纳税人识别号只能从企业认证信息获取
-- 用户不能手动修改这些字段
-- 前端和后端都有相应的权限控制
-
-### 3. 用户体验
-- 清晰的视觉反馈(禁用状态、提示信息)
-- 友好的错误提示
-- 自动数据回显,减少用户输入
-
-## 总结
-
-通过这次修复,我们实现了:
-
-1. ✅ **数据回显**:公司名称和纳税人识别号自动从企业认证信息回显
-2. ✅ **权限控制**:只读字段不能被用户修改
-3. ✅ **用户体验**:清晰的视觉反馈和友好的提示信息
-4. ✅ **数据一致性**:确保发票信息与企业认证信息保持一致
-
-这个修复既解决了用户反馈的问题,又提升了整体的用户体验。
\ No newline at end of file
diff --git a/发票功能实现完成总结.md b/发票功能实现完成总结.md
deleted file mode 100644
index b98a0be..0000000
--- a/发票功能实现完成总结.md
+++ /dev/null
@@ -1,221 +0,0 @@
-# 发票功能实现完成总结
-
-## 概述
-
-发票功能已经完全实现,包括后端服务、前端页面、数据库仓储和依赖注入配置。所有功能都遵循DDD架构,实现了完整的发票申请和管理流程。
-
-## 已完成的实现
-
-### 1. 领域层 (Domain Layer)
-
-#### 实体和值对象
-- ✅ `entities/invoice_application.go` - 发票申请聚合根
-- ✅ `value_objects/invoice_type.go` - 发票类型值对象
-- ✅ `value_objects/invoice_info.go` - 发票信息值对象
-
-#### 领域服务
-- ✅ `services/invoice_domain_service.go` - 发票领域服务(接口+实现)
-- ✅ `services/invoice_aggregate_service.go` - 发票聚合服务(接口+实现)
-
-#### 仓储接口
-- ✅ `repositories/invoice_application_repository.go` - 发票申请仓储接口
-
-#### 领域事件
-- ✅ `events/invoice_events.go` - 发票相关领域事件
-
-### 2. 应用层 (Application Layer)
-
-#### 应用服务
-- ✅ `invoice_application_service.go` - 发票应用服务(合并用户端和管理员端)
- - 用户端:申请开票、获取发票信息、更新发票信息、获取开票记录、下载发票文件、获取可开票金额
- - 管理员端:获取待处理申请列表、通过发票申请、拒绝发票申请
-
-#### DTO
-- ✅ `dto/invoice_responses.go` - 发票相关响应DTO
-
-### 3. 基础设施层 (Infrastructure Layer)
-
-#### 仓储实现
-- ✅ `repositories/finance/invoice_application_repository_impl.go` - 发票申请仓储GORM实现
-
-#### HTTP接口
-- ✅ `handlers/finance_handler.go` - 财务处理器(包含发票相关方法)
-- ✅ `routes/finance_routes.go` - 财务路由(包含发票相关路由)
-
-### 4. 前端实现
-
-#### 用户端页面
-- ✅ `pages/finance/Invoice.vue` - 用户发票申请页面
- - 可开票金额显示
- - 发票申请表单(支持普票和专票)
- - 申请记录列表(支持状态筛选、分页、下载)
-
-#### 管理员端页面
-- ✅ `pages/admin/invoices/index.vue` - 管理员发票管理页面
- - 申请列表(支持筛选、分页、搜索)
- - 统计信息
- - 审批操作(通过/拒绝)
- - 文件上传功能
-
-#### API集成
-- ✅ `api/invoice.js` - 发票API客户端
-- ✅ `router/index.js` - 路由配置
-- ✅ `constants/menu.js` - 菜单配置
-
-### 5. 依赖注入配置
-
-- ✅ `container/container.go` - 完整的依赖注入配置
- - 发票仓储注册
- - 发票应用服务注册
- - 领域服务注册
-
-### 6. 数据库
-
-- ✅ `migrations/000001_create_invoice_tables.sql` - 发票表结构
-
-## 功能特性
-
-### 用户端功能
-1. **可开票金额计算**
- - 基于充值金额(排除赠送)
- - 减去已开票金额
- - 实时显示可用金额
-
-2. **发票申请**
- - 支持普票和专票
- - 完整的发票信息填写
- - 金额验证和业务规则检查
-
-3. **申请记录管理**
- - 分页显示申请记录
- - 状态筛选(待处理、已通过、已拒绝)
- - 发票文件下载
-
-4. **发票信息管理**
- - 保存和更新发票信息
- - 支持公司信息、税号、银行账户等
-
-### 管理员端功能
-1. **申请列表管理**
- - 分页显示待处理申请
- - 多维度筛选(状态、发票类型、日期范围、关键词搜索)
- - 统计信息展示
-
-2. **审批操作**
- - 通过申请(上传发票文件)
- - 拒绝申请(填写拒绝原因)
- - 管理员备注功能
-
-3. **文件管理**
- - 发票文件上传
- - 文件下载链接生成
- - 文件信息记录
-
-## 技术架构
-
-### DDD架构实现
-- **聚合根**: `InvoiceApplication` - 管理发票申请的生命周期
-- **值对象**: `InvoiceType`, `InvoiceInfo` - 封装业务概念
-- **领域服务**: 处理跨聚合的业务规则
-- **聚合服务**: 协调发票相关的业务流程
-- **仓储模式**: 数据访问抽象
-
-### 事件驱动
-- 发票申请创建事件
-- 发票申请通过事件
-- 发票申请拒绝事件
-- 发票文件上传事件
-
-### 依赖注入
-- 使用fx框架进行依赖管理
-- 接口和实现分离
-- 服务生命周期管理
-
-## API接口
-
-### 用户端接口
-- `POST /api/v1/invoices/apply` - 申请开票
-- `GET /api/v1/invoices/info` - 获取发票信息
-- `PUT /api/v1/invoices/info` - 更新发票信息
-- `GET /api/v1/invoices/records` - 获取开票记录
-- `GET /api/v1/invoices/available-amount` - 获取可开票金额
-- `GET /api/v1/invoices/{id}/download` - 下载发票文件
-
-### 管理员端接口
-- `GET /api/v1/admin/invoices/pending` - 获取待处理申请
-- `POST /api/v1/admin/invoices/{id}/approve` - 通过申请
-- `POST /api/v1/admin/invoices/{id}/reject` - 拒绝申请
-
-## 业务规则
-
-### 开票金额计算
-```
-可开票金额 = 总充值金额 - 总赠送金额 - 已开票金额
-```
-
-### 发票类型验证
-- 普票:基础信息验证
-- 专票:完整信息验证(税号、银行账户等)
-
-### 状态流转
-- `pending` → `approved` (管理员通过)
-- `pending` → `rejected` (管理员拒绝)
-
-## 待完善功能
-
-### 外部服务集成
-- [ ] SMS服务集成(申请通知管理员)
-- [ ] 邮件服务集成(发票发送给用户)
-- [ ] 文件存储服务集成(发票文件上传)
-
-### 事件处理
-- [ ] 事件发布器实现
-- [ ] 事件处理器实现
-- [ ] 异步事件处理
-
-### 数据库迁移
-- [ ] 执行数据库迁移脚本
-- [ ] 验证表结构
-
-## 测试建议
-
-### 单元测试
-- 领域服务测试
-- 应用服务测试
-- 仓储测试
-
-### 集成测试
-- API接口测试
-- 数据库集成测试
-- 前端功能测试
-
-### 端到端测试
-- 完整业务流程测试
-- 用户端和管理员端交互测试
-
-## 部署说明
-
-### 环境要求
-- Go 1.21+
-- Node.js 18+
-- MySQL 8.0+
-- Redis 6.0+
-
-### 配置项
-- 数据库连接配置
-- Redis连接配置
-- 文件存储配置
-- 短信服务配置
-- 邮件服务配置
-
-## 总结
-
-发票功能已经完全实现,包括:
-1. **完整的DDD架构** - 领域驱动设计,清晰的层次结构
-2. **用户端功能** - 申请开票、记录管理、文件下载
-3. **管理员端功能** - 审批管理、文件上传、统计分析
-4. **前端界面** - 现代化的Vue 3界面,良好的用户体验
-5. **API接口** - RESTful API设计,完整的文档
-6. **依赖注入** - 完整的服务注册和依赖管理
-
-后续只需要集成外部服务(短信、邮件、文件存储)和实现事件处理,就可以投入生产使用。
\ No newline at end of file
diff --git a/发票应用服务修复完成总结.md b/发票应用服务修复完成总结.md
deleted file mode 100644
index 7dcd2dc..0000000
--- a/发票应用服务修复完成总结.md
+++ /dev/null
@@ -1,137 +0,0 @@
-# 发票应用服务修复完成总结
-
-## 修复概述
-
-成功修复了`invoice_application_service.go`中的所有编译错误,并将用户端和管理员端的应用服务合并到一个文件中,同时使用`*storage.QiNiuStorageService`替换了`interfaces.StorageService`。
-
-## 主要修复内容
-
-### 1. 存储服务替换
-- **问题**: 使用了未定义的`interfaces.StorageService`
-- **解决方案**: 替换为`*storage.QiNiuStorageService`
-- **影响文件**:
- - `InvoiceApplicationServiceImpl.storageService`
- - `AdminInvoiceApplicationServiceImpl.storageService`
- - 构造函数参数
-
-### 2. 仓储接口更新
-- **问题**: 仓储接口缺少必要的方法
-- **解决方案**: 在`InvoiceApplicationRepository`接口中添加了以下方法:
- - `Save(ctx, application)`
- - `FindByUserID(ctx, userID, page, pageSize)`
- - `FindPendingApplications(ctx, page, pageSize)`
- - `FindByUserIDAndStatus(ctx, userID, status, page, pageSize)`
- - `GetUserInvoiceInfo(ctx, userID)`
- - `UpdateUserInvoiceInfo(ctx, userID, invoiceInfo)`
- - `GetUserTotalInvoicedAmount(ctx, userID)`
- - `GetUserTotalAppliedAmount(ctx, userID)`
-
-### 3. 用户验证修复
-- **问题**: `s.userRepo.FindByID`方法不存在
-- **解决方案**: 改为使用`s.userRepo.GetByID`
-- **问题**: 用户对象比较错误
-- **解决方案**: 改为检查`user.ID == ""`
-
-### 4. 发票信息字段修复
-- **问题**: 使用了错误的字段名(如`TaxNumber`、`PhoneNumber`、`Email`)
-- **解决方案**: 使用正确的字段名:
- - `TaxpayerID`(纳税人识别号)
- - `CompanyPhone`(企业注册电话)
- - `ReceivingEmail`(发票接收邮箱)
- - `BankName`(银行名称)
-
-### 5. 聚合服务调用修复
-- **问题**: 聚合服务方法参数不匹配
-- **解决方案**:
- - 创建正确的`services.ApplyInvoiceRequest`结构
- - 创建正确的`services.ApproveInvoiceRequest`结构
- - 创建正确的`services.RejectInvoiceRequest`结构
-
-### 6. DTO字段映射修复
-- **问题**: DTO结构体字段不匹配
-- **解决方案**:
- - 修复`InvoiceInfoResponse`字段映射
- - 修复`InvoiceRecordResponse`字段映射
- - 修复`PendingApplicationResponse`字段映射
- - 修复`FileDownloadResponse`字段映射
-
-### 7. 状态枚举修复
-- **问题**: 使用了不存在的`ApplicationStatusApproved`
-- **解决方案**: 改为使用`ApplicationStatusCompleted`
-
-### 8. 文件信息处理修复
-- **问题**: 文件字段为指针类型,需要正确处理
-- **解决方案**: 添加空指针检查和正确的解引用
-
-### 9. 用户信息获取修复
-- **问题**: `s.userRepo.FindByIDs`方法不存在
-- **解决方案**: 改为循环调用`GetByID`方法
-
-### 10. 可开票金额计算修复
-- **问题**: 领域服务返回参数数量不匹配
-- **解决方案**: 重新实现计算逻辑,直接调用仓储方法
-
-## 修复后的架构特点
-
-### 1. 服务合并
-- 用户端和管理员端的应用服务合并到一个文件
-- 接口和实现都在同一个文件中
-- 保持了清晰的职责分离
-
-### 2. 依赖注入
-- 使用`*storage.QiNiuStorageService`进行文件存储
-- 完整的依赖注入配置
-- 服务生命周期管理
-
-### 3. 错误处理
-- 完整的参数验证
-- 友好的错误信息
-- 权限验证(用户只能访问自己的数据)
-
-### 4. 业务逻辑
-- 完整的发票申请流程
-- 状态验证和转换
-- 文件上传和下载功能
-
-## 编译状态
-
-✅ **编译成功** - 所有Go编译错误已修复
-
-## 功能完整性
-
-### 用户端功能
-- ✅ 申请开票
-- ✅ 获取发票信息
-- ✅ 更新发票信息
-- ✅ 获取开票记录
-- ✅ 下载发票文件
-- ✅ 获取可开票金额
-
-### 管理员端功能
-- ✅ 获取待处理申请列表
-- ✅ 通过发票申请
-- ✅ 拒绝发票申请
-
-## 后续工作
-
-### 1. 外部服务集成
-- [ ] SMS服务集成(申请通知管理员)
-- [ ] 邮件服务集成(发票发送给用户)
-- [ ] 文件存储服务集成(发票文件上传)
-
-### 2. 事件处理
-- [ ] 事件发布器实现
-- [ ] 事件处理器实现
-
-### 3. 数据库迁移
-- [ ] 执行数据库迁移脚本
-- [ ] 验证表结构
-
-### 4. 测试验证
-- [ ] 单元测试
-- [ ] 集成测试
-- [ ] 端到端测试
-
-## 总结
-
-发票应用服务的修复工作已经完成,所有编译错误都已解决,功能架构完整,可以支持完整的发票申请和管理流程。后续只需要集成外部服务和实现事件处理,就可以投入生产使用。
\ No newline at end of file
diff --git a/发票模块架构重新整理总结.md b/发票模块架构重新整理总结.md
deleted file mode 100644
index 09d8433..0000000
--- a/发票模块架构重新整理总结.md
+++ /dev/null
@@ -1,366 +0,0 @@
-# 发票模块架构重新整理总结
-
-## 概述
-
-根据DDD(领域驱动设计)架构规范,重新整理了发票模块的架构,明确了各层的职责分工和写法规范。通过这次重新整理,实现了更清晰的架构分层、更规范的代码组织和更好的可维护性。
-
-## 架构分层和职责
-
-### 1. 领域服务层(Domain Service Layer)
-
-#### 职责定位
-- **纯业务规则处理**:只处理领域内的业务规则和计算逻辑
-- **无外部依赖**:不依赖仓储、外部服务或其他领域
-- **可测试性强**:纯函数式设计,易于单元测试
-
-#### `InvoiceDomainService` 接口设计
-```go
-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
-}
-```
-
-#### 实现特点
-- **无状态设计**:不保存任何状态,所有方法都是纯函数
-- **参数化输入**:所有需要的数据都通过参数传入
-- **业务规则集中**:所有业务规则都在领域服务中定义
-- **可复用性强**:可以在不同场景下复用
-
-### 2. 聚合服务层(Aggregate Service Layer)
-
-#### 职责定位
-- **聚合根生命周期管理**:协调聚合根的创建、更新、删除
-- **业务流程编排**:按照业务规则编排操作流程
-- **领域事件发布**:发布领域事件,实现事件驱动架构
-- **状态转换控制**:控制聚合根的状态转换
-
-#### `InvoiceAggregateService` 接口设计
-```go
-type InvoiceAggregateService interface {
- // 申请开票
- ApplyInvoice(ctx context.Context, userID string, req ApplyInvoiceRequest) (*entities.InvoiceApplication, error)
-
- // 通过发票申请(上传发票)
- ApproveInvoiceApplication(ctx context.Context, applicationID string, file multipart.File, req ApproveInvoiceRequest) error
-
- // 拒绝发票申请
- RejectInvoiceApplication(ctx context.Context, applicationID string, req RejectInvoiceRequest) error
-}
-```
-
-#### 实现特点
-- **依赖领域服务**:调用领域服务进行业务规则验证
-- **依赖仓储**:通过仓储进行数据持久化
-- **发布事件**:发布领域事件,实现松耦合
-- **事务边界**:每个方法都是一个事务边界
-
-### 3. 应用服务层(Application Service Layer)
-
-#### 职责定位
-- **跨域协调**:协调不同领域之间的交互
-- **数据聚合**:聚合来自不同领域的数据
-- **事务管理**:管理跨领域的事务
-- **外部服务调用**:调用外部服务(如文件存储、邮件服务等)
-
-#### `InvoiceApplicationService` 接口设计
-```go
-type InvoiceApplicationService interface {
- // ApplyInvoice 申请开票
- ApplyInvoice(ctx context.Context, userID string, req ApplyInvoiceRequest) (*dto.InvoiceApplicationResponse, error)
-
- // GetUserInvoiceInfo 获取用户发票信息
- GetUserInvoiceInfo(ctx context.Context, userID string) (*dto.InvoiceInfoResponse, error)
-
- // UpdateUserInvoiceInfo 更新用户发票信息
- UpdateUserInvoiceInfo(ctx context.Context, userID string, req UpdateInvoiceInfoRequest) error
-
- // GetUserInvoiceRecords 获取用户开票记录
- GetUserInvoiceRecords(ctx context.Context, userID string, req GetInvoiceRecordsRequest) (*dto.InvoiceRecordsResponse, error)
-
- // DownloadInvoiceFile 下载发票文件
- DownloadInvoiceFile(ctx context.Context, userID string, applicationID string) (*dto.FileDownloadResponse, error)
-
- // GetAvailableAmount 获取可开票金额
- GetAvailableAmount(ctx context.Context, userID string) (*dto.AvailableAmountResponse, error)
-}
-```
-
-#### 实现特点
-- **跨域协调**:协调User领域和Finance领域的交互
-- **数据聚合**:聚合用户信息、企业认证信息、开票信息等
-- **业务编排**:按照业务流程编排各个步骤
-- **错误处理**:统一处理跨域错误和业务异常
-
-## 架构优势
-
-### 1. 职责分离清晰
-- **领域服务**:专注于业务规则,无外部依赖
-- **聚合服务**:专注于聚合根生命周期,发布领域事件
-- **应用服务**:专注于跨域协调,数据聚合
-
-### 2. 可测试性强
-- **领域服务**:纯函数设计,易于单元测试
-- **聚合服务**:可以Mock依赖,进行集成测试
-- **应用服务**:可以Mock外部服务,进行端到端测试
-
-### 3. 可维护性高
-- **单一职责**:每个服务都有明确的职责
-- **依赖清晰**:依赖关系明确,易于理解
-- **扩展性好**:新增功能时只需要修改相应的服务层
-
-### 4. 符合DDD规范
-- **领域边界**:严格遵循领域边界
-- **依赖方向**:依赖方向正确,从外到内
-- **聚合根设计**:聚合根设计合理,状态转换清晰
-
-## 代码示例
-
-### 1. 领域服务实现
-```go
-// 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.NewFromInt(100) // 最小100元
- if amount.LessThan(minAmount) {
- return fmt.Errorf("开票金额不能少于%s元", minAmount.String())
- }
-
- return nil
-}
-```
-
-### 2. 聚合服务实现
-```go
-// ApplyInvoice 申请开票
-func (s *InvoiceAggregateServiceImpl) ApplyInvoice(ctx context.Context, userID string, req ApplyInvoiceRequest) (*entities.InvoiceApplication, error) {
- // 1. 解析金额
- amount, err := decimal.NewFromString(req.Amount)
- if err != nil {
- return nil, fmt.Errorf("无效的金额格式: %w", err)
- }
-
- // 2. 验证发票信息
- if err := s.domainService.ValidateInvoiceInfo(ctx, req.InvoiceInfo, req.InvoiceType); err != nil {
- return nil, fmt.Errorf("发票信息验证失败: %w", err)
- }
-
- // 3. 获取用户开票信息
- userInvoiceInfo, err := s.userInvoiceInfoRepo.FindByUserID(ctx, userID)
- if err != nil {
- return nil, fmt.Errorf("获取用户开票信息失败: %w", err)
- }
- if userInvoiceInfo == nil {
- return nil, fmt.Errorf("用户开票信息不存在")
- }
-
- // 4. 创建发票申请聚合根
- application := entities.NewInvoiceApplication(userID, req.InvoiceType, amount, userInvoiceInfo.ID)
-
- // 5. 设置开票信息快照
- application.SetInvoiceInfoSnapshot(req.InvoiceInfo)
-
- // 6. 验证聚合根业务规则
- if err := s.domainService.ValidateInvoiceApplication(ctx, application); err != nil {
- return nil, fmt.Errorf("发票申请业务规则验证失败: %w", err)
- }
-
- // 7. 保存聚合根
- if err := s.applicationRepo.Create(ctx, application); err != nil {
- return nil, fmt.Errorf("保存发票申请失败: %w", err)
- }
-
- // 8. 发布领域事件
- event := events.NewInvoiceApplicationCreatedEvent(
- application.ID,
- application.UserID,
- application.InvoiceType,
- application.Amount,
- application.CompanyName,
- application.ReceivingEmail,
- )
-
- if err := s.eventPublisher.PublishInvoiceApplicationCreated(ctx, event); err != nil {
- fmt.Printf("发布发票申请创建事件失败: %v\n", err)
- }
-
- return application, nil
-}
-```
-
-### 3. 应用服务实现
-```go
-// ApplyInvoice 申请开票
-func (s *InvoiceApplicationServiceImpl) ApplyInvoice(ctx context.Context, userID string, req ApplyInvoiceRequest) (*dto.InvoiceApplicationResponse, error) {
- // 1. 验证用户是否存在
- user, err := s.userRepo.GetByID(ctx, userID)
- if err != nil {
- return nil, err
- }
- if user.ID == "" {
- return nil, fmt.Errorf("用户不存在")
- }
-
- // 2. 验证发票类型
- invoiceType := value_objects.InvoiceType(req.InvoiceType)
- if !invoiceType.IsValid() {
- return nil, fmt.Errorf("无效的发票类型")
- }
-
- // 3. 获取用户企业认证信息
- userWithEnterprise, err := s.userAggregateService.GetUserWithEnterpriseInfo(ctx, userID)
- if err != nil {
- return nil, fmt.Errorf("获取用户企业认证信息失败: %w", err)
- }
-
- // 4. 检查用户是否有企业认证信息
- if userWithEnterprise.EnterpriseInfo == nil {
- return nil, fmt.Errorf("用户未完成企业认证,无法申请开票")
- }
-
- // 5. 获取用户开票信息
- userInvoiceInfo, err := s.userInvoiceInfoService.GetUserInvoiceInfoWithEnterpriseInfo(
- ctx,
- userID,
- userWithEnterprise.EnterpriseInfo.CompanyName,
- userWithEnterprise.EnterpriseInfo.UnifiedSocialCode,
- )
- if err != nil {
- return nil, err
- }
-
- // 6. 验证开票信息完整性
- invoiceInfo := value_objects.NewInvoiceInfo(
- userInvoiceInfo.CompanyName,
- userInvoiceInfo.TaxpayerID,
- userInvoiceInfo.BankName,
- userInvoiceInfo.BankAccount,
- userInvoiceInfo.CompanyAddress,
- userInvoiceInfo.CompanyPhone,
- userInvoiceInfo.ReceivingEmail,
- )
-
- if err := s.userInvoiceInfoService.ValidateInvoiceInfo(ctx, invoiceInfo, invoiceType); err != nil {
- return nil, err
- }
-
- // 7. 计算可开票金额
- availableAmount, err := s.calculateAvailableAmount(ctx, userID)
- if err != nil {
- return nil, fmt.Errorf("计算可开票金额失败: %w", err)
- }
-
- // 8. 验证开票金额
- amount, err := decimal.NewFromString(req.Amount)
- if err != nil {
- return nil, fmt.Errorf("无效的金额格式: %w", err)
- }
-
- if err := s.invoiceDomainService.ValidateInvoiceAmount(ctx, amount, availableAmount); err != nil {
- return nil, err
- }
-
- // 9. 调用聚合服务申请开票
- aggregateReq := services.ApplyInvoiceRequest{
- InvoiceType: invoiceType,
- Amount: req.Amount,
- InvoiceInfo: invoiceInfo,
- }
-
- application, err := s.invoiceAggregateService.ApplyInvoice(ctx, userID, aggregateReq)
- if err != nil {
- return nil, err
- }
-
- // 10. 构建响应DTO
- return &dto.InvoiceApplicationResponse{
- ID: application.ID,
- UserID: application.UserID,
- InvoiceType: application.InvoiceType,
- Amount: application.Amount,
- Status: application.Status,
- InvoiceInfo: invoiceInfo,
- CreatedAt: application.CreatedAt,
- }, nil
-}
-```
-
-## 依赖注入配置
-
-### 1. 领域服务配置
-```go
-// 发票领域服务
-fx.Annotate(
- finance_service.NewInvoiceDomainService,
- fx.ResultTags(`name:"domainService"`),
-),
-```
-
-### 2. 聚合服务配置
-```go
-// 发票聚合服务
-fx.Annotate(
- finance_service.NewInvoiceAggregateService,
- fx.ParamTags(
- `name:"invoiceRepo"`,
- `name:"userInvoiceInfoRepo"`,
- `name:"domainService"`,
- `name:"eventPublisher"`,
- ),
- fx.ResultTags(`name:"aggregateService"`),
-),
-```
-
-### 3. 应用服务配置
-```go
-// 发票应用服务
-fx.Annotate(
- finance.NewInvoiceApplicationService,
- fx.As(new(finance.InvoiceApplicationService)),
- fx.ParamTags(
- `name:"invoiceRepo"`,
- `name:"userInvoiceInfoRepo"`,
- `name:"userRepo"`,
- `name:"userAggregateService"`,
- `name:"rechargeRecordRepo"`,
- `name:"walletRepo"`,
- `name:"domainService"`,
- `name:"aggregateService"`,
- `name:"userInvoiceInfoService"`,
- `name:"storageService"`,
- `name:"logger"`,
- ),
-),
-```
-
-## 总结
-
-通过这次重新整理,我们实现了:
-
-1. ✅ **架构规范**:严格遵循DDD架构规范,职责分离清晰
-2. ✅ **代码质量**:代码结构清晰,易于理解和维护
-3. ✅ **可测试性**:各层都可以独立测试,测试覆盖率高
-4. ✅ **可扩展性**:新增功能时只需要修改相应的服务层
-5. ✅ **业务逻辑**:业务逻辑清晰,流程明确
-
-这种架构设计既满足了业务需求,又符合DDD架构规范,是一个优秀的架构实现。
\ No newline at end of file
diff --git a/可开票金额计算逻辑更新说明.md b/可开票金额计算逻辑更新说明.md
deleted file mode 100644
index d3bef1b..0000000
--- a/可开票金额计算逻辑更新说明.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# 可开票金额计算逻辑更新说明
-
-## 更新概述
-
-本次更新修改了可开票金额的计算逻辑,从原来的"总充值金额 - 总赠送金额"改为"支付宝充值金额 + 对公转账金额"。
-
-## 修改内容
-
-### 1. 计算逻辑变更
-
-**原逻辑:**
-```
-可开票金额 = 总充值金额 - 总赠送金额 - 已开票金额 - 待处理申请金额
-```
-
-**新逻辑:**
-```
-可开票金额 = 真实充值金额(支付宝充值 + 对公转账) - 已开票金额 - 待处理申请金额
-```
-
-### 2. 代码修改位置
-
-#### 文件:`internal/application/finance/invoice_application_service.go`
-
-**方法:`getAmountSummary`**
-- 修改了充值金额的计算逻辑
-- 只统计 `RechargeTypeAlipay`(支付宝充值)和 `RechargeTypeTransfer`(对公转账)的金额
-- 赠送金额(`RechargeTypeGift`)不再计入可开票金额
-
-**方法:`calculateAvailableAmount`**
-- 更新了注释和变量名
-- 移除了对赠送金额的扣除逻辑
-- 直接使用真实充值金额进行计算
-
-**方法:`GetAvailableAmount`**
-- 更新了响应DTO中的 `TotalRecharged` 字段
-- 现在返回的是真实充值金额(支付宝充值+对公转账)
-
-### 3. 充值类型说明
-
-根据 `internal/domains/finance/entities/recharge_record.go` 中的定义:
-
-```go
-const (
- RechargeTypeAlipay RechargeType = "alipay" // 支付宝充值
- RechargeTypeTransfer RechargeType = "transfer" // 对公转账
- RechargeTypeGift RechargeType = "gift" // 赠送
-)
-```
-
-**计入可开票金额的类型:**
-- `alipay` - 支付宝充值
-- `transfer` - 对公转账
-
-**不计入可开票金额的类型:**
-- `gift` - 赠送金额
-
-### 4. 影响范围
-
-#### 后端影响
-- 可开票金额计算逻辑变更
-- 前端显示的"总充值"字段现在显示的是真实充值金额
-- 赠送金额不再影响可开票金额
-
-#### 前端影响
-- 用户端发票页面显示的"总充值"金额会发生变化
-- 可开票金额的计算结果会发生变化
-- 赠送金额不再从可开票金额中扣除
-
-### 5. 业务逻辑
-
-**为什么这样修改?**
-1. **合规性**:只有真实的充值金额才能开具发票
-2. **准确性**:赠送金额不应该计入可开票金额
-3. **清晰性**:明确区分真实充值和赠送金额
-
-**计算示例:**
-```
-用户充值记录:
-- 支付宝充值:1000元
-- 对公转账:500元
-- 赠送金额:200元
-
-原逻辑可开票金额:1000 + 500 + 200 - 200 = 1500元
-新逻辑可开票金额:1000 + 500 = 1500元
-
-结果相同,但逻辑更清晰
-```
-
-### 6. 注意事项
-
-1. **历史数据**:此修改会影响所有用户的可开票金额计算
-2. **前端显示**:前端显示的"总充值"字段含义发生变化
-3. **业务验证**:需要验证新的计算逻辑是否符合业务需求
-4. **测试建议**:建议在测试环境充分验证后再部署到生产环境
-
-## 部署建议
-
-1. 在测试环境验证新的计算逻辑
-2. 确认前端显示正确
-3. 通知相关业务人员了解变更
-4. 监控生产环境的可开票金额计算
\ No newline at end of file
diff --git a/开票信息快照模式实现总结.md b/开票信息快照模式实现总结.md
deleted file mode 100644
index 92c2dc8..0000000
--- a/开票信息快照模式实现总结.md
+++ /dev/null
@@ -1,309 +0,0 @@
-# 开票信息快照模式实现总结
-
-## 概述
-
-根据用户反馈,原来的实现存在数据一致性和业务逻辑问题。用户修改开票信息后,历史申请记录会显示新的信息,而不是申请时的信息。这不符合业务需求,因为:
-
-1. **数据一致性问题**:历史申请记录应该保持申请时的信息不变
-2. **业务逻辑问题**:用户可能针对不同业务场景需要不同的开票信息
-3. **审计追踪问题**:无法准确追踪申请时的实际开票信息
-
-因此,我们实现了**快照模式**来解决这些问题。
-
-## 核心设计思路
-
-### 1. 双表设计
-- **`user_invoice_info`表**:存储用户的开票信息模板,支持随时修改
-- **`invoice_applications`表**:存储申请记录,包含开票信息快照
-
-### 2. 快照机制
-- 用户申请开票时,系统将当前的`user_invoice_info`信息快照到`invoice_applications`表中
-- 历史申请记录永远保持申请时的信息不变
-- 支持用户修改开票信息模板,不影响历史记录
-
-## 主要变更
-
-### 1. 数据库表结构更新
-
-#### `user_invoice_info`表(用户开票信息模板)
-```sql
-CREATE TABLE IF NOT EXISTS user_invoice_info (
- id VARCHAR(36) PRIMARY KEY,
- user_id VARCHAR(36) NOT NULL UNIQUE,
- company_name VARCHAR(200) NOT NULL COMMENT '公司名称',
- taxpayer_id VARCHAR(50) NOT NULL COMMENT '纳税人识别号',
- bank_name VARCHAR(100) COMMENT '开户银行',
- bank_account VARCHAR(50) COMMENT '银行账号',
- company_address VARCHAR(500) COMMENT '企业地址',
- company_phone VARCHAR(20) COMMENT '企业电话',
- receiving_email VARCHAR(100) NOT NULL COMMENT '发票接收邮箱',
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- deleted_at TIMESTAMP NULL,
- INDEX idx_user_id (user_id),
- INDEX idx_created_at (created_at),
- INDEX idx_updated_at (updated_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户开票信息模板表';
-```
-
-#### `invoice_applications`表(发票申请记录)
-```sql
-CREATE TABLE IF NOT EXISTS invoice_applications (
- id VARCHAR(36) PRIMARY KEY,
- user_id VARCHAR(36) NOT NULL,
- invoice_type VARCHAR(20) NOT NULL,
- amount DECIMAL(20,8) NOT NULL,
- status VARCHAR(20) NOT NULL DEFAULT 'pending',
-
- -- 开票信息快照(申请时的信息,用于历史记录追踪)
- company_name VARCHAR(200) NOT NULL COMMENT '公司名称',
- taxpayer_id VARCHAR(50) NOT NULL COMMENT '纳税人识别号',
- bank_name VARCHAR(100) COMMENT '开户银行',
- bank_account VARCHAR(50) COMMENT '银行账号',
- company_address VARCHAR(500) COMMENT '企业地址',
- company_phone VARCHAR(20) COMMENT '企业电话',
- receiving_email VARCHAR(100) NOT NULL COMMENT '发票接收邮箱',
-
- -- 开票信息引用(关联到用户开票信息表,用于模板功能)
- user_invoice_info_id VARCHAR(36) NOT NULL COMMENT '用户开票信息ID',
-
- -- 文件信息(申请通过后才有)
- file_id VARCHAR(36) COMMENT '文件ID',
- file_name VARCHAR(200) COMMENT '文件名',
- file_size BIGINT COMMENT '文件大小',
- file_url VARCHAR(500) COMMENT '文件URL',
-
- -- 处理信息
- processed_by VARCHAR(36) COMMENT '处理人ID',
- processed_at TIMESTAMP COMMENT '处理时间',
- reject_reason VARCHAR(500) COMMENT '拒绝原因',
- admin_notes VARCHAR(500) COMMENT '管理员备注',
-
- -- 时间戳
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- deleted_at TIMESTAMP NULL,
-
- -- 索引
- INDEX idx_user_id (user_id),
- INDEX idx_status (status),
- INDEX idx_user_invoice_info_id (user_invoice_info_id),
- INDEX idx_created_at (created_at)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='发票申请表';
-```
-
-### 2. 实体更新
-
-#### `InvoiceApplication`实体
-```go
-type InvoiceApplication struct {
- // 基础标识
- ID string `gorm:"primaryKey;type:varchar(36)" json:"id"`
- UserID string `gorm:"type:varchar(36);not null;index" json:"user_id"`
-
- // 申请信息
- InvoiceType value_objects.InvoiceType `gorm:"type:varchar(20);not null" json:"invoice_type"`
- Amount decimal.Decimal `gorm:"type:decimal(20,8);not null" json:"amount"`
- Status ApplicationStatus `gorm:"type:varchar(20);not null;default:'pending';index" json:"status"`
-
- // 开票信息快照(申请时的信息,用于历史记录追踪)
- CompanyName string `gorm:"type:varchar(200);not null" json:"company_name"`
- TaxpayerID string `gorm:"type:varchar(50);not null" json:"taxpayer_id"`
- BankName string `gorm:"type:varchar(100)" json:"bank_name"`
- BankAccount string `gorm:"type:varchar(50)" json:"bank_account"`
- CompanyAddress string `gorm:"type:varchar(500)" json:"company_address"`
- CompanyPhone string `gorm:"type:varchar(20)" json:"company_phone"`
- ReceivingEmail string `gorm:"type:varchar(100);not null" json:"receiving_email"`
-
- // 开票信息引用(关联到用户开票信息表,用于模板功能)
- UserInvoiceInfoID string `gorm:"type:varchar(36);not null" json:"user_invoice_info_id"`
-
- // 文件信息
- FileID *string `gorm:"type:varchar(36)" json:"file_id,omitempty"`
- FileName *string `gorm:"type:varchar(200)" json:"file_name,omitempty"`
- FileSize *int64 `json:"file_size,omitempty"`
- FileURL *string `gorm:"type:varchar(500)" json:"file_url,omitempty"`
-
- // 处理信息
- ProcessedBy *string `gorm:"type:varchar(36)" json:"processed_by,omitempty"`
- ProcessedAt *time.Time `json:"processed_at,omitempty"`
- RejectReason *string `gorm:"type:varchar(500)" json:"reject_reason,omitempty"`
- AdminNotes *string `gorm:"type:varchar(500)" json:"admin_notes,omitempty"`
-
- // 时间戳字段
- CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
- UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
- DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
-}
-```
-
-#### 新增快照方法
-```go
-// 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,
- )
-}
-```
-
-### 3. 业务逻辑更新
-
-#### 申请开票流程
-```go
-func (s *InvoiceAggregateServiceImpl) ApplyInvoice(ctx context.Context, userID string, req ApplyInvoiceRequest) (*entities.InvoiceApplication, error) {
- // 1. 验证开票信息
- if err := s.domainService.ValidateInvoiceInfo(ctx, req.InvoiceInfo, req.InvoiceType); err != nil {
- return nil, fmt.Errorf("发票信息验证失败: %w", err)
- }
-
- // 2. 验证开票金额
- if err := s.domainService.ValidateInvoiceAmount(ctx, userID, amount); err != nil {
- return nil, fmt.Errorf("开票金额验证失败: %w", err)
- }
-
- // 3. 获取用户开票信息模板
- userInvoiceInfo, err := s.userInvoiceInfoRepo.FindByUserID(ctx, userID)
- if err != nil {
- return nil, fmt.Errorf("获取用户开票信息失败: %w", err)
- }
-
- // 4. 创建发票申请
- application := entities.NewInvoiceApplication(userID, req.InvoiceType, amount, userInvoiceInfo.ID)
-
- // 5. 设置开票信息快照(保存申请时的信息)
- application.SetInvoiceInfoSnapshot(req.InvoiceInfo)
-
- // 6. 保存申请
- if err := s.applicationRepo.Create(ctx, application); err != nil {
- return nil, fmt.Errorf("保存发票申请失败: %w", err)
- }
-
- // 7. 发布事件
- // ...
-
- return application, nil
-}
-```
-
-#### 查询申请记录
-```go
-func (s *InvoiceApplicationServiceImpl) GetUserInvoiceRecords(ctx context.Context, userID string, req GetInvoiceRecordsRequest) (*dto.InvoiceRecordsResponse, error) {
- // 获取申请记录
- applications, total, err := s.invoiceRepo.FindByUserIDAndStatus(ctx, userID, status, req.Page, req.PageSize)
- if err != nil {
- return nil, err
- }
-
- records := make([]*dto.InvoiceRecordResponse, len(applications))
- for i, app := range applications {
- // 使用快照信息(申请时的开票信息)
- records[i] = &dto.InvoiceRecordResponse{
- ID: app.ID,
- UserID: app.UserID,
- InvoiceType: app.InvoiceType,
- Amount: app.Amount,
- Status: app.Status,
- CompanyName: app.CompanyName, // 使用快照的公司名称
- FileName: app.FileName,
- FileSize: app.FileSize,
- FileURL: app.FileURL,
- ProcessedAt: app.ProcessedAt,
- CreatedAt: app.CreatedAt,
- }
- }
-
- return &dto.InvoiceRecordsResponse{
- Records: records,
- Total: total,
- Page: req.Page,
- PageSize: req.PageSize,
- TotalPages: (int(total) + req.PageSize - 1) / req.PageSize,
- }, nil
-}
-```
-
-## 业务优势
-
-### 1. 数据一致性
-- **历史记录不变**:申请记录永远保持申请时的开票信息
-- **审计追踪**:可以准确追踪每次申请时的实际信息
-- **数据完整性**:即使模板被删除,申请记录仍然完整
-
-### 2. 业务灵活性
-- **模板管理**:用户可以维护多个开票信息模板
-- **信息修改**:用户可以随时修改开票信息,不影响历史记录
-- **场景适配**:支持不同业务场景使用不同的开票信息
-
-### 3. 系统稳定性
-- **数据隔离**:模板和申请记录数据隔离,降低耦合
-- **性能优化**:查询申请记录时无需关联查询
-- **扩展性**:支持未来添加更多开票信息字段
-
-## 工作流程
-
-### 1. 用户开票信息管理
-```
-用户进入发票页面 → 显示当前开票信息模板 → 点击编辑 → 修改信息 → 保存到user_invoice_info表
-```
-
-### 2. 申请开票流程
-```
-用户点击申请开票 → 验证user_invoice_info信息完整性 → 创建申请记录 → 快照开票信息到invoice_applications表 → 保存申请
-```
-
-### 3. 查询申请记录
-```
-用户查看申请记录 → 直接使用invoice_applications表中的快照信息 → 显示申请时的开票信息
-```
-
-### 4. 管理员处理
-```
-管理员查看待处理申请 → 显示快照的开票信息 → 处理申请 → 发送邮件到快照的邮箱地址
-```
-
-## 技术实现要点
-
-### 1. 快照时机
-- 在申请开票时立即创建快照
-- 使用`SetInvoiceInfoSnapshot`方法设置快照信息
-- 快照信息与申请记录一起保存
-
-### 2. 查询优化
-- 查询申请记录时直接使用快照字段
-- 无需关联查询`user_invoice_info`表
-- 提高查询性能
-
-### 3. 事件发布
-- 使用快照信息发布事件
-- 确保邮件发送到申请时的邮箱地址
-- 保持事件数据的一致性
-
-## 总结
-
-通过实现开票信息快照模式,我们成功解决了以下问题:
-
-1. ✅ **数据一致性问题**:历史申请记录保持申请时的信息不变
-2. ✅ **业务逻辑问题**:支持用户修改开票信息模板,不影响历史记录
-3. ✅ **审计追踪问题**:可以准确追踪每次申请时的实际开票信息
-4. ✅ **系统性能**:查询申请记录时无需关联查询,提高性能
-5. ✅ **扩展性**:支持未来功能扩展和字段添加
-
-这种设计既满足了业务需求,又保证了系统的稳定性和可维护性,是一个优秀的DDD架构实践。
\ No newline at end of file
diff --git a/开票信息模板重构完成总结.md b/开票信息模板重构完成总结.md
deleted file mode 100644
index 65efb98..0000000
--- a/开票信息模板重构完成总结.md
+++ /dev/null
@@ -1,170 +0,0 @@
-# 开票信息模板重构完成总结
-
-## 概述
-
-成功创建了专门的开票信息模板表,将开票信息与开票申请进行了完全隔离,实现了更清晰的数据架构和更好的维护性。
-
-## 主要变更
-
-### 1. 数据库表结构
-
-#### 新增表:`user_invoice_info`
-```sql
-CREATE TABLE IF NOT EXISTS user_invoice_info (
- id VARCHAR(36) PRIMARY KEY,
- user_id VARCHAR(36) NOT NULL UNIQUE,
-
- -- 开票信息字段
- company_name VARCHAR(200) NOT NULL COMMENT '公司名称',
- taxpayer_id VARCHAR(50) NOT NULL COMMENT '纳税人识别号',
- bank_name VARCHAR(100) COMMENT '开户银行',
- bank_account VARCHAR(50) COMMENT '银行账号',
- company_address VARCHAR(500) COMMENT '企业地址',
- company_phone VARCHAR(20) COMMENT '企业电话',
- receiving_email VARCHAR(100) NOT NULL COMMENT '发票接收邮箱',
-
- -- 元数据
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- deleted_at TIMESTAMP NULL,
-
- -- 索引
- INDEX idx_user_id (user_id),
- INDEX idx_created_at (created_at),
- INDEX idx_updated_at (updated_at)
-);
-```
-
-#### 修改表:`invoice_applications`
-- 移除了所有开票信息字段(`company_name`, `taxpayer_id`, `bank_name`, `bank_account`, `company_address`, `company_phone`, `receiving_email`)
-- 新增了 `user_invoice_info_id` 字段,用于关联用户开票信息
-
-### 2. 实体层变更
-
-#### 新增实体:`UserInvoiceInfo`
-- 位置:`internal/domains/finance/entities/user_invoice_info.go`
-- 包含完整的开票信息字段
-- 提供验证方法:`IsComplete()`, `IsCompleteForSpecialInvoice()`, `GetMissingFields()`
-
-#### 修改实体:`InvoiceApplication`
-- 移除了开票信息相关字段
-- 新增 `UserInvoiceInfoID` 字段
-- 更新了工厂方法 `NewInvoiceApplication`
-
-### 3. 仓储层变更
-
-#### 新增仓储接口:`UserInvoiceInfoRepository`
-- 位置:`internal/domains/finance/repositories/user_invoice_info_repository.go`
-- 提供基本的CRUD操作
-
-#### 新增仓储实现:`GormUserInvoiceInfoRepository`
-- 位置:`internal/infrastructure/database/repositories/finance/user_invoice_info_repository_impl.go`
-- 基于GORM的实现
-
-#### 修改仓储:`InvoiceApplicationRepository`
-- 移除了 `GetUserInvoiceInfo` 和 `UpdateUserInvoiceInfo` 方法
-- 这些功能现在由专门的 `UserInvoiceInfoRepository` 处理
-
-### 4. 服务层变更
-
-#### 新增服务:`UserInvoiceInfoService`
-- 位置:`internal/domains/finance/services/user_invoice_info_service.go`
-- 接口和实现放在同一个文件中
-- 提供开票信息的管理功能
-
-#### 修改服务:`InvoiceAggregateService`
-- 添加了 `UserInvoiceInfoRepository` 依赖
-- 更新了 `ApplyInvoice` 方法,使用用户开票信息ID
-- 修改了事件发布逻辑,通过关联查询获取邮箱信息
-
-### 5. 应用服务层变更
-
-#### 修改:`InvoiceApplicationService`
-- 添加了 `UserInvoiceInfoService` 依赖
-- 更新了 `ApplyInvoice` 方法,从用户开票信息获取数据
-- 更新了 `GetUserInvoiceInfo` 和 `UpdateUserInvoiceInfo` 方法
-- 更新了 `GetUserInvoiceRecords` 方法,通过关联查询获取公司名称
-
-#### 修改:`AdminInvoiceApplicationService`
-- 添加了 `UserInvoiceInfoRepository` 依赖
-- 更新了 `GetPendingApplications` 方法,通过关联查询获取公司名称和邮箱
-
-### 6. 依赖注入配置
-
-#### 更新容器配置:`container.go`
-- 添加了 `UserInvoiceInfoRepository` 的依赖注入
-- 添加了 `UserInvoiceInfoService` 的依赖注入
-- 更新了 `InvoiceAggregateService` 的依赖注入
-- 更新了 `InvoiceApplicationService` 和 `AdminInvoiceApplicationService` 的依赖注入
-- 为所有相关服务添加了正确的标签(`fx.ResultTags` 和 `fx.ParamTags`)
-
-## 架构优势
-
-### 1. 数据隔离
-- 开票信息与申请记录完全分离
-- 避免了数据冗余和不一致问题
-- 提高了数据完整性
-
-### 2. 更好的维护性
-- 开票信息的变更不会影响历史申请记录
-- 可以独立管理开票信息的生命周期
-- 便于后续功能扩展
-
-### 3. 性能优化
-- 减少了数据冗余
-- 提高了查询效率
-- 更好的索引策略
-
-### 4. 业务逻辑清晰
-- 开票信息管理有专门的服务
-- 申请流程更加清晰
-- 便于实现复杂的业务规则
-
-## 数据流程
-
-### 1. 用户设置开票信息
-```
-用户填写开票信息 → UserInvoiceInfoService.CreateOrUpdateUserInvoiceInfo → UserInvoiceInfoRepository.Save
-```
-
-### 2. 用户申请开票
-```
-用户申请开票 → InvoiceApplicationService.ApplyInvoice → 获取用户开票信息 → 创建申请记录(关联开票信息ID)
-```
-
-### 3. 管理员处理申请
-```
-管理员处理申请 → 通过关联查询获取开票信息 → 处理申请 → 发送邮件
-```
-
-## 兼容性
-
-### 1. API接口保持不变
-- 前端API调用方式无需修改
-- 响应数据结构保持一致
-- 向后兼容
-
-### 2. 数据库迁移
-- 需要执行新的迁移脚本创建 `user_invoice_info` 表
-- 需要迁移现有数据(如果有的话)
-- 需要更新 `invoice_applications` 表结构
-
-## 后续工作
-
-### 1. 数据库迁移
-- 执行 `000002_create_user_invoice_info_table.sql` 创建新表
-- 编写数据迁移脚本(如果需要)
-
-### 2. 测试验证
-- 单元测试
-- 集成测试
-- 端到端测试
-
-### 3. 文档更新
-- API文档更新
-- 数据库设计文档更新
-- 开发指南更新
-
-## 总结
-
-通过这次重构,我们成功实现了开票信息与开票申请的完全隔离,建立了更清晰的数据架构。新的设计具有更好的可维护性、扩展性和性能,同时保持了API的向后兼容性。这为后续的功能扩展和优化奠定了良好的基础。
\ No newline at end of file