diff --git a/api/src/api/v1/vsp.py b/api/src/api/v1/vsp.py index 24652c0..b4947f4 100644 --- a/api/src/api/v1/vsp.py +++ b/api/src/api/v1/vsp.py @@ -59,12 +59,13 @@ async def get_vsp( @router.get("/dropdown", response_model=BaseListResponse[VSPInDB]) async def get_vsp_dropdown( ssp_id: int | None = None, + form_id: int | None = None, db: AsyncSession = Depends(get_db), current_user: AppUser = Depends(require_executor), ): """Получение записей для выпадающего списка INFO.""" service = VSPService(db) - result = await service.get_dropdown(user=current_user, ssp_id=ssp_id, with_count=True) + result = await service.get_dropdown(user=current_user, ssp_id=ssp_id, form_id=form_id, with_count=True) return BaseListResponse( success=True, message="Список INFO для выпадающего списка", diff --git a/api/src/services/vsp_service.py b/api/src/services/vsp_service.py index 60bac12..22f26d8 100644 --- a/api/src/services/vsp_service.py +++ b/api/src/services/vsp_service.py @@ -7,6 +7,7 @@ from openpyxl import Workbook from sqlalchemy.exc import IntegrityError from sqlalchemy.ext.asyncio import AsyncSession +from src.repository.budget_form_repository import BudgetFormRepository from src.core.errors import AccessDeniedException, ValidationException from src.db.models import AppUser, UserRoleEnum, Vsp from src.domain.schemas import VSPCreate, VSPUpdate @@ -29,6 +30,7 @@ class VSPService: def __init__(self, db: AsyncSession): self.db = db self.vsp_repo = VSPRepository(db) + self.form_repo = BudgetFormRepository(db) self.user_repo = UserRepository(db) async def get(self, vsp_id: int, user: AppUser, load_org_unit: bool = False) -> Optional[Vsp]: @@ -94,19 +96,27 @@ class VSPService: self, user: AppUser, ssp_id: int | None = None, + form_id: int | None = None, with_count: bool = False, ) -> list[Vsp]: ssp_ids = await self._get_scoped_ssp_ids(user=user) - + + checking_ssps = set() if ssp_id is not None: + checking_ssps.add(ssp_id) + if form_id is not None: + form = await self.form_repo.get(budget_form_id=form_id) + if form is not None: + checking_ssps.add(form.org_unit_id) + if checking_ssps: if ssp_ids is None: - ssp_ids = [ssp_id] - elif ssp_id not in set(ssp_ids): + ssp_ids = list(checking_ssps) + elif not checking_ssps & set(ssp_ids): if with_count: return 0, [] return [] else: - ssp_ids = [ssp_id] + ssp_ids = list(checking_ssps & set(ssp_ids)) return await self.vsp_repo.get_list( ssp_ids=ssp_ids, diff --git a/api/tests/integration/test_vsp.py b/api/tests/integration/test_vsp.py index 6889ce0..4bdfebf 100644 --- a/api/tests/integration/test_vsp.py +++ b/api/tests/integration/test_vsp.py @@ -37,14 +37,25 @@ def test_vsp_dropdown_smoke(client, admin_tokens, auth_headers): assert isinstance(payload["result"], list) -def test_vsp_dropdown_with_ssp_filter(client, admin_tokens, auth_headers): +@pytest.mark.parametrize( + "params, count", + [ + ([("ssp_id", 2)], 1), + ([("form_id", 1)], 0), + ([("form_id", 2)], 1), + ([("ssp_id", 2), ("form_id", 1)], 1), + ] +) +def test_vsp_dropdown_with_filter(client, admin_tokens, auth_headers, params, count): + filters = "&".join([f"{el[0]}={el[1]}" for el in params]) response = client.get( - "/api/v1/dict/info/dropdown?ssp_id=1", + f"/api/v1/dict/info/dropdown?{filters}", headers=auth_headers(admin_tokens), ) assert response.status_code == 200 payload = response.json() assert isinstance(payload["result"], list) + assert len(payload["result"]) == count def test_vsp_get_by_id(client, admin_tokens, auth_headers): diff --git a/api/tests/sqls/fixture.sql b/api/tests/sqls/fixture.sql index 6cb94e9..6aa3e65 100644 --- a/api/tests/sqls/fixture.sql +++ b/api/tests/sqls/fixture.sql @@ -15,8 +15,9 @@ INSERT INTO v3.user_org (id,user_id,org_unit_id) VALUES SELECT setval('v3.user_org_id_seq', 3); INSERT INTO v3.budget_form (id,form_type_code,"year",created_by,created_at,updated_by,updated_at,org_unit_id) VALUES - (1,'FORM_1',2027,NULL,'2026-05-06 16:57:38.066371',NULL,'2026-06-11 14:35:53.783017',1); -SELECT setval('v3.budget_form_id_seq', 1); + (1,'FORM_1',2027,NULL,'2026-05-06 16:57:38.066371',NULL,'2026-06-11 14:35:53.783017',1), + (4,'FORM_2',2026,NULL,'2026-05-08 09:08:12.230445',NULL,'2026-05-08 09:08:12.230445',2); +SELECT setval('v3.budget_form_id_seq', 4); INSERT INTO v3.budget_line (id,budget_form_id,expense_item_id,"name",internal_order,vsp_id,project_id,justification,created_by,created_at,updated_by,updated_at,direction) VALUES (1,1,88,'1234',NULL,NULL,NULL,NULL,NULL,'2026-05-06 16:58:05.793083',NULL,'2026-06-22 17:41:54.255313','Support'); @@ -26,5 +27,6 @@ INSERT INTO v3.form_phase (budget_form_id,sheet,phase_code,"role",column_keys,op (1,'AHR','test','DFIP','{{plan.q1}}','2026-05-05 03:00:00+03','2026-06-06 03:00:00+03'); INSERT INTO v3.vsp (id,branch_id,reg_number,address,format,opened_at,placement_type,staff_count,total_area,closed_at,is_active,updated_at,is_deleted,created_at,created_by,system_code,updated_by,vsp_type,notes,location_form,numbers,rent_contract_num,rent_end_date) VALUES - (1,2,'Тестовый всп 1','Тестовая 12','укукк','2026-05-07','ывс',2026,230,'2026-06-16',false,'2026-06-18 15:46:38.611903',false,'2026-06-04 14:36:59.737727',1,'1233',91,'','','встроенное помещение',NULL,'',NULL); -SELECT setval('v3.vsp_id_seq', 1); + (1,2,'Тестовый всп 1','Тестовая 12','укукк','2026-05-07','ывс',2026,230,'2026-06-16',false,'2026-06-18 15:46:38.611903',false,'2026-06-04 14:36:59.737727',1,'1233',91,'','','встроенное помещение',NULL,'',NULL), + (2,2,'Test12 -----','Тестовая 125','формат 15 ','2026-06-08',NULL,NULL,58,NULL,true,'2026-06-16 18:53:17.986651',false,'2026-06-09 09:04:33.29858',91,'123-1234',91,'субаренда','Работает ','аренда',155,'12-45','2026-10-02'); +SELECT setval('v3.vsp_id_seq', 2);