```
refactor(core,ai): 调整模块导入路径并移除废弃文件 - 修复 scheduler.py 中的导入路径错误,将 reports.service 改为 reports.services - 移除废弃的 app/core/background/task_queue.py 文件 - 移除废弃的 app/modules/ai_agent/adapters.py 文件 - 修复 ai_memory/service.py 中的导入路径错误,将 events.service 改为 events.services ```
This commit is contained in:
131
app/modules/reports/services/summaries.py
Normal file
131
app/modules/reports/services/summaries.py
Normal file
@@ -0,0 +1,131 @@
|
||||
from datetime import date
|
||||
from decimal import Decimal
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import func, select
|
||||
|
||||
from app.modules.business.constants import (
|
||||
ATTENDANCE_ABNORMAL_STATUSES,
|
||||
PROJECT_CLOSED_STATUSES,
|
||||
PENDING_APPROVAL_STATUSES,
|
||||
StatusValue,
|
||||
)
|
||||
from app.modules.business.models import (
|
||||
AttendanceRecord,
|
||||
Expense,
|
||||
FundAccount,
|
||||
Procurement,
|
||||
Project,
|
||||
WorkTask,
|
||||
)
|
||||
from app.modules.reports.constants import (
|
||||
ReportResponseKey,
|
||||
ReportTitle,
|
||||
)
|
||||
from app.modules.risk.constants import RiskSummaryKey
|
||||
|
||||
from app.modules.reports.services.common import _money
|
||||
|
||||
|
||||
class ReportSummaryMixin:
|
||||
def daily_brief(self) -> dict:
|
||||
project_count = self._count(Project)
|
||||
task_count = self._count(WorkTask)
|
||||
procurement_pending = self._count(
|
||||
Procurement,
|
||||
Procurement.approval_status.in_(PENDING_APPROVAL_STATUSES),
|
||||
)
|
||||
expense_pending = self._count(
|
||||
Expense,
|
||||
Expense.approval_status.in_(PENDING_APPROVAL_STATUSES),
|
||||
)
|
||||
fund_total = (
|
||||
self.db.execute(select(func.sum(FundAccount.current_balance))).scalar()
|
||||
or Decimal("0")
|
||||
)
|
||||
risk_summary = self.risks.summary()
|
||||
attendance = self.attendance_summary()
|
||||
lines = [
|
||||
f"- 项目总数:{project_count}",
|
||||
f"- 任务总数:{task_count}",
|
||||
f"- 待处理采购:{procurement_pending}",
|
||||
f"- 待处理费用:{expense_pending}",
|
||||
f"- 当前账户总余额:{_money(fund_total)}",
|
||||
(
|
||||
f"- 今日打卡记录:{attendance[ReportResponseKey.TOTAL]},"
|
||||
f"异常:{attendance[ReportResponseKey.ABNORMAL_TOTAL]}"
|
||||
),
|
||||
f"- 逾期任务:{len(risk_summary[RiskSummaryKey.OVERDUE_TASKS])}",
|
||||
f"- 延期项目:{len(risk_summary[RiskSummaryKey.DELAYED_PROJECTS])}",
|
||||
f"- 超预算项目:{len(risk_summary[RiskSummaryKey.OVER_BUDGET_PROJECTS])}",
|
||||
f"- 资金风险账户:{len(risk_summary[RiskSummaryKey.FUND_RISKS])}",
|
||||
f"- 供应商风险:{len(risk_summary[RiskSummaryKey.SUPPLIER_RISKS])}",
|
||||
f"- 打开风险事件:{len(risk_summary[RiskSummaryKey.OPEN_EVENTS])}",
|
||||
f"- 综合风险等级:{risk_summary[RiskSummaryKey.RISK_LEVEL]}",
|
||||
]
|
||||
return {
|
||||
ReportResponseKey.TITLE: ReportTitle.DAILY_BRIEF,
|
||||
ReportResponseKey.LINES: lines,
|
||||
ReportResponseKey.CONTENT: "\n".join(lines),
|
||||
}
|
||||
|
||||
def project_weekly(self) -> dict:
|
||||
active = self._count(
|
||||
Project,
|
||||
Project.status.notin_(PROJECT_CLOSED_STATUSES),
|
||||
)
|
||||
delayed = self.risks.delayed_projects()
|
||||
over_budget = self.risks.over_budget_projects()
|
||||
open_risks = self.risks.list_events(status_filter=StatusValue.OPEN)
|
||||
lines = [
|
||||
f"- 活跃项目:{active}",
|
||||
f"- 延期项目:{len(delayed)}",
|
||||
f"- 超预算项目:{len(over_budget)}",
|
||||
f"- 打开风险事件:{len(open_risks)}",
|
||||
"- 需要管理层关注:",
|
||||
]
|
||||
for item in delayed[:10]:
|
||||
lines.append(
|
||||
f" - 延期:{item.get('code')} {item.get('name')},"
|
||||
f"负责人 {item.get('owner')}"
|
||||
)
|
||||
for item in over_budget[:10]:
|
||||
lines.append(f" - 超预算:{item.get('code')} {item.get('name')}")
|
||||
return {
|
||||
ReportResponseKey.TITLE: ReportTitle.PROJECT_WEEKLY,
|
||||
ReportResponseKey.LINES: lines,
|
||||
ReportResponseKey.CONTENT: "\n".join(lines),
|
||||
}
|
||||
|
||||
def attendance_summary(self, work_date: date | None = None) -> dict[str, Any]:
|
||||
"""Summarize attendance records for one business day."""
|
||||
|
||||
target_date = work_date or date.today()
|
||||
rows = self.db.execute(
|
||||
select(AttendanceRecord.status, func.count())
|
||||
.where(AttendanceRecord.work_date == target_date)
|
||||
.group_by(AttendanceRecord.status)
|
||||
).all()
|
||||
status_counts = {str(status): int(count) for status, count in rows}
|
||||
abnormal_total = sum(
|
||||
count
|
||||
for status, count in status_counts.items()
|
||||
if status in ATTENDANCE_ABNORMAL_STATUSES
|
||||
)
|
||||
total = sum(status_counts.values())
|
||||
lines = [
|
||||
f"- 日期:{target_date.isoformat()}",
|
||||
f"- 打卡记录:{total}",
|
||||
f"- 异常记录:{abnormal_total}",
|
||||
]
|
||||
for status, count in sorted(status_counts.items()):
|
||||
lines.append(f"- {status}:{count}")
|
||||
return {
|
||||
ReportResponseKey.TITLE: ReportTitle.ATTENDANCE_SUMMARY,
|
||||
ReportResponseKey.WORK_DATE: target_date.isoformat(),
|
||||
ReportResponseKey.TOTAL: total,
|
||||
ReportResponseKey.ABNORMAL_TOTAL: abnormal_total,
|
||||
ReportResponseKey.STATUS_COUNTS: status_counts,
|
||||
ReportResponseKey.LINES: lines,
|
||||
ReportResponseKey.CONTENT: "\n".join(lines),
|
||||
}
|
||||
Reference in New Issue
Block a user