feat: 凭证生成、成本分析、AI问答、前端页面、集成测试与E2E测试
- 后端: 凭证生成引擎、金蝶导出器、凭证模板服务 - 后端: 成本分析服务、AI问答服务 - 后端: 科目映射CRUD API、分析API、QA API - 后端: 集成测试(认证/任务/凭证) 49个测试全部通过 - 前端: 凭证管理、成本分析、导出中心、知识库、系统设置页面 - 前端: AuthGuard认证守卫、Dashboard AI聊天功能 - 前端: Playwright E2E测试 16 passed, 1 skipped - 基础设施: Docker Compose、Nginx反向代理、.env.example - 文档: 用户手册、管理员手册、发布检查清单
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
from app.models.base import BaseModel
|
||||
from app.models.company import Company
|
||||
from app.models.user import User
|
||||
from app.models.uploaded_file import UploadedFile
|
||||
from app.models.field_mapping import FieldMapping
|
||||
from app.models.company_rule import CompanyRule
|
||||
from app.models.reconciliation_task import ReconciliationTask
|
||||
from app.models.exception_item import ExceptionItem
|
||||
from app.models.standard_field import StandardField
|
||||
from app.models.parsed_file_record import ParsedFileRecord
|
||||
from app.models.audit_log import AuditLog
|
||||
from app.models.cost_analysis import CostAnalysis
|
||||
from app.models.account_mapping import AccountMapping
|
||||
from app.models.voucher import Voucher
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""
|
||||
科目映射模型
|
||||
|
||||
存储标准字段到会计科目的映射关系
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import ForeignKey, Integer, String, Float, Boolean, JSON
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class AccountMapping(BaseModel):
|
||||
"""
|
||||
科目映射模型
|
||||
|
||||
将标准字段(如基本工资、社保等)映射到会计科目
|
||||
|
||||
Attributes:
|
||||
company_id: 企业ID
|
||||
standard_field: 标准字段名
|
||||
debit_account: 借方科目代码
|
||||
debit_account_name: 借方科目名称
|
||||
credit_account: 贷方科目代码
|
||||
credit_account_name: 贷方科目名称
|
||||
cost_center: 成本中心(可选)
|
||||
is_active: 是否启用
|
||||
"""
|
||||
|
||||
__tablename__ = "account_mappings"
|
||||
|
||||
company_id: Mapped[int] = mapped_column(Integer, ForeignKey("companies.id"), nullable=False, index=True)
|
||||
standard_field: Mapped[str] = mapped_column(String(100), nullable=False, index=True, comment="标准字段名")
|
||||
debit_account: Mapped[str] = mapped_column(String(50), nullable=False, comment="借方科目代码")
|
||||
debit_account_name: Mapped[str] = mapped_column(String(200), nullable=False, comment="借方科目名称")
|
||||
credit_account: Mapped[str] = mapped_column(String(50), nullable=False, comment="贷方科目代码")
|
||||
credit_account_name: Mapped[str] = mapped_column(String(200), nullable=False, comment="贷方科目名称")
|
||||
cost_center: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="成本中心")
|
||||
is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="是否启用")
|
||||
|
||||
# 关系
|
||||
company = relationship("Company", backref="account_mappings")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<AccountMapping(field='{self.standard_field}', debit='{self.debit_account}', credit='{self.credit_account}')>"
|
||||
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
成本分析模型
|
||||
|
||||
存储人工成本分析结果,包括总额、部门拆分、费用科目拆分、环比变化等
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import ForeignKey, Integer, String, Float, JSON, DateTime
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class CostAnalysis(BaseModel):
|
||||
"""
|
||||
成本分析模型
|
||||
|
||||
记录一次成本分析的计算结果
|
||||
|
||||
Attributes:
|
||||
task_id: 关联的对账任务ID
|
||||
company_id: 企业ID
|
||||
total_cost: 人工成本总额
|
||||
salary_cost: 工资成本
|
||||
social_security_cost: 社保成本(公司部分)
|
||||
fund_cost: 公积金成本(公司部分)
|
||||
department_breakdown: 部门成本拆分(JSON)
|
||||
expense_breakdown: 费用科目拆分(JSON)
|
||||
month_over_month: 环比变化数据(JSON)
|
||||
ai_summary: AI 生成的分析摘要
|
||||
"""
|
||||
|
||||
__tablename__ = "cost_analyses"
|
||||
|
||||
task_id: Mapped[int] = mapped_column(Integer, ForeignKey("reconciliation_tasks.id"), nullable=False, index=True)
|
||||
company_id: Mapped[int] = mapped_column(Integer, ForeignKey("companies.id"), nullable=False, index=True)
|
||||
|
||||
total_cost: Mapped[float] = mapped_column(Float, nullable=False, default=0.0, comment="人工成本总额")
|
||||
salary_cost: Mapped[float] = mapped_column(Float, nullable=False, default=0.0, comment="工资成本")
|
||||
social_security_cost: Mapped[float] = mapped_column(Float, nullable=False, default=0.0, comment="社保成本(公司部分)")
|
||||
fund_cost: Mapped[float] = mapped_column(Float, nullable=False, default=0.0, comment="公积金成本(公司部分)")
|
||||
|
||||
department_breakdown: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True, comment="部门成本拆分")
|
||||
expense_breakdown: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True, comment="费用科目拆分")
|
||||
month_over_month: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True, comment="环比变化数据")
|
||||
|
||||
ai_summary: Mapped[Optional[str]] = mapped_column(String(2000), nullable=True, comment="AI 生成的分析摘要")
|
||||
|
||||
# 关系
|
||||
task = relationship("ReconciliationTask", backref="cost_analyses")
|
||||
company = relationship("Company", backref="cost_analyses")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<CostAnalysis(task_id={self.task_id}, total_cost={self.total_cost})>"
|
||||
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
凭证模型
|
||||
|
||||
存储生成的会计凭证
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import ForeignKey, Integer, String, Float, DateTime, JSON, Text
|
||||
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
||||
|
||||
from app.models.base import BaseModel
|
||||
|
||||
|
||||
class VoucherStatus:
|
||||
"""凭证状态"""
|
||||
DRAFT = "DRAFT"
|
||||
CONFIRMED = "CONFIRMED"
|
||||
EXPORTED = "EXPORTED"
|
||||
|
||||
|
||||
class Voucher(BaseModel):
|
||||
"""
|
||||
会计凭证模型
|
||||
|
||||
Attributes:
|
||||
company_id: 企业ID
|
||||
task_id: 对账任务ID
|
||||
voucher_number: 凭证编号
|
||||
voucher_date: 凭证日期
|
||||
period: 会计期间
|
||||
summary: 摘要
|
||||
entries: 凭证分录(JSON)
|
||||
total_debit: 借方合计
|
||||
total_credit: 贷方合计
|
||||
status: 状态
|
||||
confirmed_by: 确认人
|
||||
confirmed_at: 确认时间
|
||||
"""
|
||||
|
||||
__tablename__ = "vouchers"
|
||||
|
||||
company_id: Mapped[int] = mapped_column(Integer, ForeignKey("companies.id"), nullable=False, index=True)
|
||||
task_id: Mapped[int] = mapped_column(Integer, ForeignKey("reconciliation_tasks.id"), nullable=False, index=True)
|
||||
|
||||
voucher_number: Mapped[str] = mapped_column(String(50), nullable=False, index=True, comment="凭证编号")
|
||||
voucher_date: Mapped[str] = mapped_column(String(20), nullable=False, comment="凭证日期 YYYY-MM-DD")
|
||||
period: Mapped[str] = mapped_column(String(20), nullable=False, index=True, comment="会计期间 YYYY-MM")
|
||||
|
||||
summary: Mapped[str] = mapped_column(String(500), nullable=False, comment="摘要")
|
||||
entries: Mapped[dict] = mapped_column(JSON, nullable=False, comment="凭证分录列表")
|
||||
|
||||
total_debit: Mapped[float] = mapped_column(Float, nullable=False, default=0.0, comment="借方合计")
|
||||
total_credit: Mapped[float] = mapped_column(Float, nullable=False, default=0.0, comment="贷方合计")
|
||||
|
||||
status: Mapped[str] = mapped_column(String(20), nullable=False, default=VoucherStatus.DRAFT, index=True, comment="状态")
|
||||
confirmed_by: Mapped[Optional[int]] = mapped_column(Integer, ForeignKey("users.id"), nullable=True)
|
||||
confirmed_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
|
||||
|
||||
# 关系
|
||||
company = relationship("Company", backref="vouchers")
|
||||
task = relationship("ReconciliationTask", backref="vouchers")
|
||||
confirmer = relationship("User", foreign_keys=[confirmed_by])
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Voucher(number='{self.voucher_number}', period='{self.period}', status='{self.status}')>"
|
||||
Reference in New Issue
Block a user