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,113 @@
|
||||
"""
|
||||
凭证生成引擎单元测试
|
||||
|
||||
测试 VoucherGeneratorService 的核心逻辑
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from app.services.voucher.generator import VoucherGeneratorService, VoucherEntry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_db():
|
||||
return AsyncMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def generator(mock_db):
|
||||
return VoucherGeneratorService(mock_db)
|
||||
|
||||
|
||||
class TestVoucherEntry:
|
||||
"""凭证分录测试"""
|
||||
|
||||
def test_entry_creation(self):
|
||||
"""测试创建借方分录"""
|
||||
entry = VoucherEntry(
|
||||
account_code="6601.01",
|
||||
account_name="管理费用-工资",
|
||||
debit_amount=10000,
|
||||
summary="基本工资",
|
||||
)
|
||||
assert entry.account_code == "6601.01"
|
||||
assert entry.debit_amount == 10000
|
||||
assert entry.credit_amount == 0
|
||||
|
||||
def test_entry_to_dict(self):
|
||||
"""测试分录转字典"""
|
||||
entry = VoucherEntry(
|
||||
account_code="2211.01",
|
||||
account_name="应付职工薪酬",
|
||||
credit_amount=10000,
|
||||
summary="基本工资",
|
||||
department="技术部",
|
||||
)
|
||||
d = entry.to_dict()
|
||||
assert d["account_code"] == "2211.01"
|
||||
assert d["credit_amount"] == 10000
|
||||
assert d["department"] == "技术部"
|
||||
|
||||
|
||||
class TestVoucherGeneratorService:
|
||||
"""凭证生成引擎测试"""
|
||||
|
||||
def test_aggregate_by_field(self, generator):
|
||||
"""测试按字段汇总"""
|
||||
records = [
|
||||
{"基本工资": 10000, "奖金": 2000, "养老保险(公司)": 2000},
|
||||
{"基本工资": 8000, "奖金": 1000, "养老保险(公司)": 1600},
|
||||
]
|
||||
totals = generator._aggregate_by_field(records)
|
||||
assert totals["基本工资"] == 18000
|
||||
assert totals["奖金"] == 3000
|
||||
assert totals["养老保险(公司)"] == 3600
|
||||
|
||||
def test_aggregate_empty(self, generator):
|
||||
"""测试空数据汇总"""
|
||||
totals = generator._aggregate_by_field([])
|
||||
assert totals == {}
|
||||
|
||||
def test_generate_entries_basic(self, generator):
|
||||
"""测试基本分录生成"""
|
||||
field_totals = {"基本工资": 18000}
|
||||
mappings = {
|
||||
"基本工资": {
|
||||
"debit_account": "6601.01",
|
||||
"debit_account_name": "管理费用-工资",
|
||||
"credit_account": "2211.01",
|
||||
"credit_account_name": "应付职工薪酬-工资",
|
||||
}
|
||||
}
|
||||
entries = generator._generate_entries(field_totals, mappings)
|
||||
assert len(entries) >= 2
|
||||
total_debit = sum(e.debit_amount for e in entries)
|
||||
total_credit = sum(e.credit_amount for e in entries)
|
||||
assert total_debit == 18000
|
||||
assert total_credit == 18000
|
||||
|
||||
def test_generate_entries_skip_missing_mapping(self, generator):
|
||||
"""测试跳过无映射的字段"""
|
||||
field_totals = {"基本工资": 18000, "未知字段": 5000}
|
||||
mappings = {
|
||||
"基本工资": {
|
||||
"debit_account": "6601.01",
|
||||
"debit_account_name": "管理费用-工资",
|
||||
"credit_account": "2211.01",
|
||||
"credit_account_name": "应付职工薪酬-工资",
|
||||
}
|
||||
}
|
||||
entries = generator._generate_entries(field_totals, mappings)
|
||||
total_debit = sum(e.debit_amount for e in entries)
|
||||
assert total_debit == 18000
|
||||
|
||||
def test_merge_entries_same_account(self, generator):
|
||||
"""测试合并相同科目"""
|
||||
entries = [
|
||||
VoucherEntry("6601.01", "管理费用-工资", debit_amount=10000, summary="基本工资"),
|
||||
VoucherEntry("6601.01", "管理费用-工资", debit_amount=8000, summary="奖金"),
|
||||
]
|
||||
merged = generator._merge_entries(entries)
|
||||
assert len(merged) == 1
|
||||
assert merged[0].debit_amount == 18000
|
||||
Reference in New Issue
Block a user