feat: 财务看板口径重构与半年模拟数据及报销状态注册表
- 重构 finance_dashboard 口径计算,新增模拟公司画像数据生成与筛选 - 引入 expense_claim_status_registry 统一报销状态流转 - 完善报销草稿流程、Item Sync 与本体解析器 - 优化总览页趋势图、分页组件与请求进度步骤 - 增强报销申请快速预览、本体工具与详情展示 - 新增半年报销模拟数据种子脚本与状态审计工具 - 补充财务看板、报销状态注册与模拟数据测试覆盖
This commit is contained in:
111
server/scripts/seed_half_year_expense_demo.py
Normal file
111
server/scripts/seed_half_year_expense_demo.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
SERVER_DIR = Path(__file__).resolve().parents[1]
|
||||
SRC_DIR = SERVER_DIR / "src"
|
||||
if str(SRC_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SRC_DIR))
|
||||
|
||||
from app.db.session import get_session_factory # noqa: E402
|
||||
from app.models.employee import Employee # noqa: E402
|
||||
from app.services.demo_company_simulation_filters import is_admin_employee_like # noqa: E402
|
||||
from app.services.demo_company_simulation_seed import ( # noqa: E402
|
||||
HalfYearExpenseSimulationSeeder,
|
||||
SimulationConfig,
|
||||
)
|
||||
from app.services.employee_behavior_profile_service import ( # noqa: E402
|
||||
EmployeeBehaviorProfileService,
|
||||
)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Seed half-year simulated reimbursement, budget, and employee data.",
|
||||
)
|
||||
parser.add_argument("--target-employees", type=int, default=100)
|
||||
parser.add_argument("--start-date", type=date.fromisoformat, default=date(2026, 1, 1))
|
||||
parser.add_argument("--months", type=int, default=6)
|
||||
parser.add_argument("--seed", type=int, default=20260602)
|
||||
parser.add_argument("--apply", action="store_true", help="Write data. Default is dry-run only.")
|
||||
parser.add_argument(
|
||||
"--refresh-profiles",
|
||||
action="store_true",
|
||||
help="After --apply, refresh employee behavior profile snapshots for simulated employees.",
|
||||
)
|
||||
parser.add_argument("--profile-limit", type=int, default=120)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
config = SimulationConfig(
|
||||
target_employees=args.target_employees,
|
||||
start_date=args.start_date,
|
||||
months=args.months,
|
||||
seed=args.seed,
|
||||
)
|
||||
session_factory = get_session_factory()
|
||||
with session_factory() as db:
|
||||
seeder = HalfYearExpenseSimulationSeeder(db, config)
|
||||
try:
|
||||
summary = seeder.apply() if args.apply else seeder.preview()
|
||||
profile_refresh = None
|
||||
if args.apply and args.refresh_profiles:
|
||||
profile_refresh = refresh_company_profiles(db, limit=args.profile_limit)
|
||||
elif args.apply:
|
||||
db.commit()
|
||||
payload = summary.to_dict()
|
||||
if profile_refresh is not None:
|
||||
payload["profile_refresh"] = profile_refresh
|
||||
print(json.dumps(payload, ensure_ascii=False, indent=2))
|
||||
if not args.apply:
|
||||
print("dry-run only; pass --apply after confirmation to write simulated data.")
|
||||
elif not args.refresh_profiles:
|
||||
print("pass --refresh-profiles to generate employee behavior profile snapshots.")
|
||||
except Exception:
|
||||
db.rollback()
|
||||
raise
|
||||
|
||||
|
||||
def refresh_company_profiles(db, *, limit: int) -> dict[str, object]:
|
||||
capped_limit = max(1, min(int(limit or 120), 500))
|
||||
employees = list(
|
||||
db.scalars(select(Employee).order_by(Employee.employee_no.asc())).all()
|
||||
)
|
||||
employee_ids = [
|
||||
employee.id
|
||||
for employee in employees
|
||||
if not is_admin_employee_like(employee)
|
||||
][:capped_limit]
|
||||
service = EmployeeBehaviorProfileService(db)
|
||||
snapshot_count = 0
|
||||
for employee_id in employee_ids:
|
||||
snapshots = service.refresh_employee_profiles(
|
||||
employee_id=employee_id,
|
||||
window_days=(30, 90, 180),
|
||||
expense_type_scope="overall",
|
||||
source_task_type="half_year_expense_demo_seed",
|
||||
commit=False,
|
||||
)
|
||||
snapshot_count += len(snapshots)
|
||||
|
||||
db.commit()
|
||||
return {
|
||||
"target_employee_count": len(employee_ids),
|
||||
"snapshot_count": snapshot_count,
|
||||
"window_days": [30, 90, 180],
|
||||
"source_task_type": "half_year_expense_demo_seed",
|
||||
"scope": "all_non_admin_employees",
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user