DFiP_Budget_planing/api/src/services/project_service.py

280 lines
9.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from sqlalchemy.ext.asyncio import AsyncSession
from src.db.models.project import Project
from src.db.models.app_user import AppUser
from src.db.models.role import UserRoleEnum
from src.core.errors import AccessDeniedException, ValidationException
from src.domain.schemas import placement_type_to_db
from src.repository.project_repository import ProjectRepository
from src.repository.user_repository import UserRepository
class ProjectService:
def __init__(self, db: AsyncSession):
self.db = db
self.project_repo = ProjectRepository(db)
self.user_repo = UserRepository(db)
async def get_list(
self,
user: AppUser,
year: int | None = None,
branch_id: int | None = None,
offset: int | None = None,
limit: int | None = None,
with_count: bool = False,
with_org_unit: bool = False,
) -> list[dict] | tuple[int, list[dict]]:
org_unit_ids = await self._allowed_org_unit_ids(user)
return await self.project_repo.get_list(
year=year,
branch_id=branch_id,
offset=offset,
limit=limit,
with_count=with_count,
org_unit_ids=org_unit_ids,
)
async def get_list_with_reports(
self,
user: AppUser,
year: int | None = None,
branch_id: int | None = None,
offset: int | None = None,
limit: int | None = None,
with_count: bool = False,
) -> list[dict] | tuple[int, list[dict]]:
org_unit_ids = await self._allowed_org_unit_ids(user)
return await self.project_repo.get_with_reports(
year=year,
branch_id=branch_id,
offset=offset,
limit=limit,
with_count=with_count,
org_unit_ids=org_unit_ids,
)
async def get(self, project_id: int, user: AppUser) -> dict | None:
org_unit_ids = await self._allowed_org_unit_ids(user)
project = await self.project_repo.get(project_id=project_id, org_unit_ids=org_unit_ids)
if not project:
return None
project["reports"] = await self.project_repo.get_reports(project_id=project_id)
return project
async def get_instance(
self,
project_id: int,
user: AppUser | None = None,
org_unit_ids: list[int] | None = None,
) -> Project | None:
if org_unit_ids is None and user is not None:
org_unit_ids = await self._allowed_org_unit_ids(user)
return await self.project_repo.get_instance(project_id=project_id, org_unit_ids=org_unit_ids)
async def resolve_report_id(
self,
project_id: int,
year: int,
report_type: str,
user: AppUser,
) -> int | None:
normalized_type = report_type.upper()
if normalized_type not in ("LIMIT", "CURRENT_EXPENSES"):
raise ValidationException("report_type должен быть LIMIT или CURRENT_EXPENSES")
org_unit_ids = await self._allowed_org_unit_ids(user)
return await self.project_repo.resolve_report_id(
project_id=project_id,
year=year,
report_type=normalized_type,
org_unit_ids=org_unit_ids,
)
async def get_report_rows(
self,
project_id: int,
year: int,
report_type: str,
sections: list[str] | None,
user: AppUser,
) -> list[tuple]:
report_id = await self.resolve_report_id(project_id, year, report_type, user)
if not report_id:
raise ValidationException("Отчёт не найден")
return await self.project_repo.get_report_rows(report_id=report_id, sections=sections)
async def get_rf_rollup_rows(
self,
branch_id: int,
year: int,
sections: list[str] | None,
user: AppUser,
) -> list[tuple]:
org_unit_ids = await self._allowed_org_unit_ids(user)
if org_unit_ids is not None and branch_id not in org_unit_ids:
raise AccessDeniedException()
return await self.project_repo.get_rf_rollup_rows(
branch_id=branch_id,
year=year,
sections=sections,
)
async def get_project_summary_rows(
self,
project_id: int,
user: AppUser,
) -> list[tuple]:
project = await self.get_instance(project_id, user)
if not project:
raise ValidationException("Проект не найден")
return await self.project_repo.get_project_summary_rows(project_id=project_id)
async def upd_form3_cell(
self,
project_id: int,
year: int,
report_type: str,
line_id: int,
column: str,
value,
user: AppUser,
) -> list[tuple]:
report_id = await self.resolve_report_id(project_id, year, report_type, user)
if not report_id:
raise ValidationException("Отчёт не найден")
return await self.project_repo.upd_form3_cell(report_id, line_id, column, value)
async def upd_form3_cells(
self,
project_id: int,
year: int,
report_type: str,
changes: list[dict],
user: AppUser,
) -> list[tuple]:
report_id = await self.resolve_report_id(project_id, year, report_type, user)
if not report_id:
raise ValidationException("Отчёт не найден")
return await self.project_repo.upd_form3_cells(report_id, changes)
async def add_form3_line(
self,
project_id: int,
year: int,
report_type: str,
expense_item_id: int,
user: AppUser,
) -> list[tuple]:
report_id = await self.resolve_report_id(project_id, year, report_type, user)
if not report_id:
raise ValidationException("Отчёт не найден")
return await self.project_repo.add_form3_line(report_id, expense_item_id)
async def del_form3_line(
self,
project_id: int,
year: int,
report_type: str,
line_id: int,
user: AppUser,
) -> list[tuple]:
report_id = await self.resolve_report_id(project_id, year, report_type, user)
if not report_id:
raise ValidationException("Отчёт не найден")
return await self.project_repo.del_form3_line(line_id)
async def delete_project(self, project_id: int, user: AppUser):
project = await self.get(project_id, user)
if not project:
raise ValidationException("Проект не найден")
return await self.project_repo.del_project(project_id)
async def upd_project(
self,
project_id: int,
data: dict,
user: AppUser,
):
project = await self.get(project_id, user)
if not project:
raise ValidationException("Проект не найден")
if "placement_type" in data:
data["placement_type"] = placement_type_to_db(data["placement_type"])
await self.project_repo.upd_project(project_id, data)
return await self.get(project_id, user)
async def upd_smeta(
self,
project_id: int,
year: int,
data: dict,
user: AppUser,
):
org_unit_ids = await self._allowed_org_unit_ids(user)
rf_project_year_id = await self.project_repo.resolve_rf_project_year_id(
project_id=project_id,
year=year,
org_unit_ids=org_unit_ids,
)
if rf_project_year_id is None:
raise ValidationException("Смета не найдена")
await self.project_repo.upd_smeta(rf_project_year_id, data)
return await self.project_repo.get_smeta(rf_project_year_id)
async def add_project_year(
self,
project_id: int,
user: AppUser,
) -> dict:
org_unit_ids = await self._allowed_org_unit_ids(user)
project = await self.get_instance(
project_id=project_id,
org_unit_ids=org_unit_ids,
)
if not project:
raise ValidationException("Проект не найден")
last_year = await self.project_repo.get_max_year(
project_id=project_id,
org_unit_ids=org_unit_ids,
)
if not last_year:
raise ValidationException("У проекта нет года")
next_year = last_year + 1
return await self.project_repo.add_project_year(project_id=project_id, year=next_year)
async def add_project(
self,
name: str,
year: int,
org_unit_id: int,
level: str = "project",
parent_id: int | None = None,
project_type: str | None = None,
vsp_format: str | None = None,
placement_type: str | None = None,
object_address: str | None = None,
staff_count: int | None = None,
total_area: float | None = None,
) -> tuple[int, int, int]:
return await self.project_repo.add_project(
name=name,
year=year,
org_unit_id=org_unit_id,
level=level,
parent_id=parent_id,
project_type=project_type,
vsp_format=vsp_format,
placement_type=placement_type_to_db(placement_type),
object_address=object_address,
staff_count=staff_count,
total_area=total_area,
)
async def _allowed_org_unit_ids(self, user: AppUser) -> list[int] | None:
if user.role_id == UserRoleEnum.ADMIN:
return None
db_user = await self.user_repo.get(user_id=user.id, load_orgs=True)
if not db_user:
return []
return [ou.id for ou in db_user.org_units]