Skip to content
30 changes: 28 additions & 2 deletions src/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""

from contextlib import asynccontextmanager
from datetime import timedelta
from datetime import date, timedelta
import json
import logging
import os
Expand All @@ -29,14 +29,15 @@
import email_config
import response_schemas
import schemas
from util import check_permissions
from util import check_permissions, over_a_year

DEFAULT_TOKEN_EXPIRE_MINS = 30
ACCESS_TOKEN_EXPIRE_MINUTES = int(
os.environ.get("ACCESS_TOKEN_EXPIRE_MINUTES", DEFAULT_TOKEN_EXPIRE_MINS)
)
TEST_ENVIRONMENT = os.environ.get("TEST_ENVIRONMENT", "False") == "True"
DB_AUDIT_LOGS_ENABLED = os.environ.get("DB_AUDIT_LOGS_ENABLED", "False") == "True"
PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE = date(2025, 5, 31)
# ## INIT --------------------------------------------------

with open(
Expand Down Expand Up @@ -589,12 +590,24 @@ async def create_or_update_plano_entregas(

try:
if not db_plano_entregas: # create
if over_a_year(plano_entregas.data_inicio, plano_entregas.data_termino) == 1:
detail_msg = (
"Plano de entregas não pode abranger período maior que 1 ano"
)
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, detail=detail_msg)

novo_plano_entregas = await crud.create_plano_entregas(
db_session=db,
plano_entregas=novo_plano_entregas,
)
response.status_code = status.HTTP_201_CREATED
else: # update
if over_a_year(plano_entregas.data_inicio, plano_entregas.data_termino) == 1 and \
plano_entregas.data_inicio > PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE:
detail_msg = (
"Plano de entregas não pode abranger período maior que 1 ano"
)
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, detail=detail_msg)
novo_plano_entregas = await crud.update_plano_entregas(
db_session=db,
plano_entregas=novo_plano_entregas,
Expand Down Expand Up @@ -722,12 +735,25 @@ async def create_or_update_plano_trabalho(

try:
if not db_plano_trabalho: # create
if over_a_year(plano_trabalho.data_inicio, plano_trabalho.data_termino) == 1:
detail_msg = (
"Plano de trabalho não pode abranger período maior que 1 ano"
)
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, detail=detail_msg)

novo_plano_trabalho = await crud.create_plano_trabalho(
db_session=db,
plano_trabalho=novo_plano_trabalho,
)
response.status_code = status.HTTP_201_CREATED
else: # update
if over_a_year(plano_trabalho.data_inicio, plano_trabalho.data_termino) == 1 and \
plano_trabalho.data_inicio > PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE:
detail_msg = (
"Plano de trabalho não pode abranger período maior que 1 ano"
)
raise HTTPException(status.HTTP_422_UNPROCESSABLE_ENTITY, detail=detail_msg)

novo_plano_trabalho = await crud.update_plano_trabalho(
db_session=db,
plano_trabalho=novo_plano_trabalho,
Expand Down
14 changes: 0 additions & 14 deletions src/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
Participante,
Users,
)
from util import over_a_year

STR_FIELD_MAX_SIZE = 300
NON_NEGATIVE_INT4 = Annotated[NonNegativeInt, Field(le=(2**31) - 1)]
Expand Down Expand Up @@ -380,15 +379,6 @@ def validate_unidade(self):
)
return self

@model_validator(mode="after")
def year_interval(self) -> "PlanoTrabalhoSchema":
"""Garante que o plano não abrange um período maior que 1 ano."""
if over_a_year(self.data_inicio, self.data_termino) == 1:
raise ValueError(
"Plano de trabalho não pode abranger período maior que 1 ano"
)
return self

@model_validator(mode="after")
def must_be_sequential_dates(self) -> "PlanoTrabalhoSchema":
"Verifica se a data de início e a data de término estão na ordem esperada."
Expand Down Expand Up @@ -573,10 +563,6 @@ def validate_entregas_uniqueness(self) -> "PlanoEntregasSchema":
@model_validator(mode="after")
def validate_period(self) -> "PlanoEntregasSchema":
"""Valida o período do plano de entregas."""
if over_a_year(self.data_inicio, self.data_termino) == 1:
raise ValueError(
"Plano de entregas não pode abranger período maior que 1 ano"
)
if self.data_termino < self.data_inicio:
raise ValueError("data_termino deve ser maior ou igual que data_inicio.")
if self.data_avaliacao is not None and self.data_avaliacao < self.data_inicio:
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
MAX_BIGINT = (2**63) - 1

MIN_ALLOWED_PT_TCR_DATE = date(2023, 7, 31)

PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE = date(2025, 5, 31)

def get_bearer_token(username: str, password: str) -> str:
"""Login on api-pgd and returns token to next authenticated calls.
Expand Down
47 changes: 42 additions & 5 deletions tests/plano_entregas/date_validation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from util import over_a_year
from .core_test import BasePETest

from tests.conftest import PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE

# Datas básicas

Expand Down Expand Up @@ -51,14 +51,51 @@ def test_create_plano_entregas_date_interval_over_a_year(
detail_message = (
"Plano de entregas não pode abranger período maior que 1 ano"
)
assert any(
f"Value error, {detail_message}" in error["msg"]
for error in response.json().get("detail")
)
assert response.json().get("detail") == detail_message
else:
assert response.status_code == http_status.HTTP_201_CREATED
self.assert_equal_plano_entregas(response.json(), input_pe)

@pytest.mark.parametrize(
"data_inicio, data_termino",
[
("2024-01-01", "2025-01-02", ), # antes da data de corte (permitido)
("2025-06-01", "2026-06-02"), # após da data de corte (proibido)
],
)
def test_update_plano_entregas_date_interval_over_a_year(
self,
truncate_pe, # pylint: disable=unused-argument
data_inicio: str,
data_termino: str,
):
"""Plano de Entregas não pode ter vigência superior a um ano."""
self.put_plano_entregas(self.input_pe)
input_pe2 = deepcopy(self.input_pe)
input_pe2["data_inicio"] = data_inicio
input_pe2["data_termino"] = data_termino
# para evitar erro de data_avaliacao < data_inicio
input_pe2["data_avaliacao"] = data_inicio

response = self.put_plano_entregas(input_pe2)

if (
over_a_year(
date.fromisoformat(data_inicio), date.fromisoformat(data_termino)
)
== 1 and date.fromisoformat(data_inicio) > PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE
):
assert response.status_code == http_status.HTTP_422_UNPROCESSABLE_ENTITY
detail_message = (
"Plano de entregas não pode abranger período maior que 1 ano"
)
assert response.json().get("detail") == detail_message
else:
assert response.status_code == http_status.HTTP_200_OK
self.assert_equal_plano_entregas(response.json(), input_pe2)



@pytest.mark.parametrize(
"data_inicio, data_termino",
[
Expand Down
42 changes: 41 additions & 1 deletion tests/plano_trabalho/date_validation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from util import over_a_year, assert_error_message
from .core_test import BasePTTest
from tests.conftest import MIN_ALLOWED_PT_TCR_DATE
from tests.conftest import MIN_ALLOWED_PT_TCR_DATE, PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE
# Datas básicas


Expand Down Expand Up @@ -109,6 +109,46 @@ def test_create_plano_trabalho_date_interval_over_a_year(
assert response.status_code == status.HTTP_201_CREATED
self.assert_equal_plano_trabalho(response.json(), input_pt)

class TestUpdatePTDateIntervalOverAYear(BasePTTest):
"""Testes relacionados a atualizar um Plano de Trabalho com intervalo de
data superior a um ano."""

@pytest.mark.parametrize(
"data_inicio, data_termino",
[
("2024-01-01", "2025-05-31"), # mais que um ano antes da data de corte
("2025-06-01", "2026-06-02"), # mais que um ano após a data de corte
],
)
def test_update_plano_trabalho_date_interval_over_a_year(
self, data_inicio: str, data_termino: str
):
"""Plano de trabalho pode ser atualizado com vigência superior a um ano
desde que antes da data de corte."""
self.put_plano_trabalho(self.input_pt)
input_pt2 = deepcopy(self.input_pt)

input_pt2["data_inicio"] = data_inicio
input_pt2["data_termino"] = data_termino
input_pt2["avaliacoes_registros_execucao"] = []

response = self.put_plano_trabalho(input_pt2)

if (
over_a_year(
date.fromisoformat(data_inicio), date.fromisoformat(data_termino)
)
== 1 and date.fromisoformat(data_inicio) > PT_PE_UPDATE_YEAR_VALIDATION_CUTOFF_DATE
):
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
detail_message = (
"Plano de trabalho não pode abranger período maior que 1 ano"
)
assert_error_message(response, detail_message)
else:
assert response.status_code == status.HTTP_200_OK
self.assert_equal_plano_trabalho(response.json(), input_pt2)


class TestCreatePTOverlappingDateInterval(BasePTTest):
"""Testes relacionados a criar um Plano de Trabalho com sobreposição
Expand Down