Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a079874
build(benefit): upgrade to python 3.12
voneiden Sep 22, 2025
2636a9a
refactor(benefit): apply pyupgrade
voneiden Sep 22, 2025
462ddde
deps(benefit): upgrade to Django 5.2
voneiden Sep 23, 2025
98333ea
fix: update SENTRY variable names
voneiden Oct 13, 2025
264f4b8
test(benefit): fix pytest_sessionfinish crash if test collection errors
voneiden Oct 13, 2025
b4f6f7d
fix: simplify GDPR API
voneiden Oct 13, 2025
f281600
test(benefit): update test compatibility with Django 5.2
voneiden Oct 13, 2025
b0ee522
test: generate uuid4 usernames in UserFactory
voneiden Oct 13, 2025
f608f5b
test(benefit): remove seeding and remove autouse db
voneiden Oct 14, 2025
a1a1a8e
test(benefit): flaky by freezing time
voneiden Oct 14, 2025
8fffa77
test(benefit): insufficiently mocked tests
voneiden Oct 14, 2025
607b96b
test(benefit): lazy use of autouse
voneiden Oct 14, 2025
50a4fde
test(benefit): flaky test due to random application language
voneiden Oct 14, 2025
4fa9045
test(benefit): flaky test by setting message_type
voneiden Oct 14, 2025
1c0926f
test(benefit): incorrect assert due to previous autouse
voneiden Oct 14, 2025
d5b2cbb
test(benefit): test dependency on company
voneiden Oct 14, 2025
5b0780d
test(benefit): unfreeze time
voneiden Oct 14, 2025
9067e09
test(benefit): remove milliseconds from test data
voneiden Oct 14, 2025
e6711ca
test: another isoformat fix
voneiden Oct 14, 2025
3090c7a
test(benefit): remove internal assumption about external time
voneiden Oct 14, 2025
5928eb3
test(benefit): freeze time in some tests
voneiden Oct 14, 2025
2a7ce00
test(benefit): adjust date_start in ApplicationFactory
voneiden Oct 14, 2025
fafda04
deps(benefit): migrate from pytest-freezegun to pytest-freezer
voneiden Oct 15, 2025
5cb9195
test(benefit): resolve post generation save deprecation warnings
voneiden Oct 15, 2025
806cf1e
fix(benefit): use timezone.now instead of datetime.now
voneiden Oct 15, 2025
7c66764
build: apply sonar suggestions on docker-entrypoint.sh
voneiden Oct 15, 2025
ebd745b
test(benefit): fix test flakyness related to EmployeeFactory
voneiden Oct 15, 2025
77e34d9
test(benefit): enable and update previously disabled test
voneiden Oct 15, 2025
7f954d1
test(benefit): use correct input data for testing record output
voneiden Oct 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/bf-py-coding-style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python ${{ inputs.python-version }}
- name: Setup Python 3.12
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
python-version: '3.12'
- name: Run pre-commit (benefit)
uses: pre-commit/action@v3.0.1
with:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/bf-pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:

services:
postgres:
image: postgres:13
image: postgres:17
ports:
- 5432:5432
options: >-
Expand All @@ -45,10 +45,10 @@ jobs:
sudo apt-get update
sudo apt-get install libpq-dev wkhtmltopdf gettext

- name: Setup Python 3.9
- name: Setup Python 3.12
uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: 3.12
cache: pip

- name: Cache pip packages
Expand Down
20 changes: 10 additions & 10 deletions backend/benefit/applications/api/v1/search_views.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import re
from datetime import datetime
from typing import Union

from dateutil.relativedelta import relativedelta
Expand All @@ -11,6 +10,7 @@
)
from django.db import models
from django.db.models import Q
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from fuzzywuzzy import fuzz
from rest_framework import filters as drf_filters
Expand Down Expand Up @@ -113,26 +113,26 @@ def _prepare_application_queryset(archived, subsidy_in_effect, years_since_decis
if subsidy_in_effect and subsidy_in_effect == SubsidyInEffect.NOW:
queryset = queryset.filter(
status=ApplicationStatus.ACCEPTED,
calculation__start_date__lte=datetime.now(),
calculation__end_date__gte=datetime.now(),
calculation__start_date__lte=timezone.now(),
calculation__end_date__gte=timezone.now(),
)
elif subsidy_in_effect and subsidy_in_effect.isnumeric():
queryset = queryset.filter(
status=ApplicationStatus.ACCEPTED,
calculation__end_date__gte=datetime.now().date()
calculation__end_date__gte=timezone.now().date()
- relativedelta(years=int(subsidy_in_effect)),
)
if years_since_decision:
queryset = queryset.filter(
Q(
status=ApplicationStatus.ACCEPTED,
batch__isnull=False,
batch__decision_date__gte=datetime.now()
batch__decision_date__gte=timezone.now()
- relativedelta(years=years_since_decision),
)
| Q(
status=ApplicationStatus.REJECTED,
handled_at__gte=datetime.now()
handled_at__gte=timezone.now()
- relativedelta(years=years_since_decision),
),
)
Expand All @@ -143,17 +143,17 @@ def _prepare_archival_application_queryset(subsidy_in_effect, years_since_decisi
queryset = ArchivalApplication.objects
if subsidy_in_effect and subsidy_in_effect == SubsidyInEffect.NOW:
return queryset.filter(
start_date__lte=datetime.now(),
end_date__gte=datetime.now(),
start_date__lte=timezone.now(),
end_date__gte=timezone.now(),
)
elif subsidy_in_effect:
return queryset.filter(
end_date__gte=datetime.now().date()
end_date__gte=timezone.now().date()
- relativedelta(years=int(subsidy_in_effect))
)
elif years_since_decision:
return queryset.filter(
end_date__gte=datetime.now().date()
end_date__gte=timezone.now().date()
- relativedelta(years=int(years_since_decision))
)
return queryset.all()
Expand Down
13 changes: 6 additions & 7 deletions backend/benefit/applications/benefit_aggregation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from dataclasses import dataclass, field
from decimal import Decimal
from itertools import chain
from typing import List, Optional, Union

from dateutil.relativedelta import relativedelta
from django.utils.text import format_lazy
Expand All @@ -16,11 +15,11 @@

@dataclass
class FormerBenefitInfo:
warnings: List[str] = field(default_factory=list)
months_used: Optional[Decimal] = (
None # None is used if employee info is not entered yet
)
months_remaining: Optional[Decimal] = None # None means that there is no limit
warnings: list[str] = field(default_factory=list)
months_used: None | (
Decimal
) = None # None is used if employee info is not entered yet
months_remaining: Decimal | None = None # None means that there is no limit


# apprenticeship is a special case
Expand Down Expand Up @@ -83,7 +82,7 @@ def get_former_benefit_info(

def _get_past_benefits(
application, company, social_security_number, end_date
) -> List[Union[PreviousBenefit, Application]]:
) -> list[PreviousBenefit | Application]:
"""
Return a list containing two types of objects:
* PreviousBenefits
Expand Down
15 changes: 7 additions & 8 deletions backend/benefit/applications/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import re
from datetime import date, timedelta
from typing import List

from dateutil.relativedelta import relativedelta
from django.conf import settings
Expand Down Expand Up @@ -189,8 +188,8 @@ def with_due_instalments(self, status: InstalmentStatus):

def get_by_statuses(
self,
application_statuses: List[ApplicationStatus],
ahjo_statuses: List[AhjoStatusEnum],
application_statuses: list[ApplicationStatus],
ahjo_statuses: list[AhjoStatusEnum],
has_no_case_id: bool,
retry_failed_older_than_hours: int = 0,
retry_status: AhjoStatusEnum = None,
Expand Down Expand Up @@ -264,8 +263,8 @@ def get_by_statuses(

def get_for_ahjo_decision(
self,
application_statuses: List[ApplicationStatus],
ahjo_statuses: List[AhjoStatusEnum],
application_statuses: list[ApplicationStatus],
ahjo_statuses: list[AhjoStatusEnum],
has_no_case_id: bool = False,
retry_failed_older_than_hours: int = 0,
retry_status: AhjoStatusEnum = None,
Expand Down Expand Up @@ -710,7 +709,7 @@ class DeMinimisAid(UUIDModel, TimeStampedModel):
)

def __str__(self):
return "{}: {} {}".format(self.pk, self.application.pk, self.granter)
return f"{self.pk}: {self.application.pk} {self.granter}"

class Meta:
db_table = "bf_applications_deminimisaid"
Expand Down Expand Up @@ -1135,7 +1134,7 @@ def birthday(self):
return social_security_number_birthdate(self.social_security_number)

def __str__(self):
return "{} {} ({})".format(self.first_name, self.last_name, self.email)
return f"{self.first_name} {self.last_name} ({self.email})"

class Meta:
db_table = "bf_applications_employee"
Expand Down Expand Up @@ -1195,7 +1194,7 @@ class Meta:
ordering = ["application__created_at", "attachment_type", "created_at"]

def __str__(self):
return "{} {}".format(self.attachment_type, self.attachment_file.name)
return f"{self.attachment_type} {self.attachment_file.name}"


class ReviewState(models.Model):
Expand Down
38 changes: 12 additions & 26 deletions backend/benefit/applications/tests/conftest.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import os
import random
import uuid
from datetime import date, datetime, timedelta
from datetime import date, timedelta

import factory
import pytest
from django.conf import settings
from django.db import connection
from django.utils import timezone

from applications.enums import (
Expand Down Expand Up @@ -66,14 +65,6 @@
from terms.tests.factories import TermsOfServiceApprovalFactory


@pytest.fixture(scope="session", autouse=True)
def django_db_setup(django_db_setup, django_db_blocker):
"""Test session DB setup."""
with django_db_blocker.unblock():
with connection.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;")


@pytest.fixture
def anonymous_application():
with factory.Faker.override_default_locale("fi_FI"):
Expand Down Expand Up @@ -330,11 +321,6 @@ def drafts_about_to_be_deleted(draft_notification_date, draft_applications):
yield draft_applications


@pytest.fixture(autouse=True)
def auto_accept_tos(autouse_django_db, accept_tos):
return accept_tos


@pytest.fixture()
def set_debug_to_true(settings):
settings.DEBUG = True
Expand Down Expand Up @@ -435,7 +421,7 @@ def ahjo_open_case_top_level_dict(decided_application):

return {
"Title": "a" * 512,
"Acquired": application.created_at.isoformat(),
"Acquired": application.created_at.isoformat("T", "seconds"),
"ClassificationCode": "02 05 01 00",
"ClassificationTitle": "Kunnan myöntämät avustukset",
"Language": language,
Expand Down Expand Up @@ -514,15 +500,15 @@ def _delete_attachments(application: Application):


def pytest_sessionfinish(session, exitstatus):
# Delete all files in the media folder
files_in_media = os.listdir(settings.MEDIA_ROOT)
number_of_files = len(files_in_media)
for file in files_in_media:
try:
try:
# Delete all files in the media folder
files_in_media = os.listdir(settings.MEDIA_ROOT)
number_of_files = len(files_in_media)
for file in files_in_media:
os.remove(os.path.join(settings.MEDIA_ROOT, file))
except OSError as e:
print(f"Error while deleting file in media folder: {e}") # noqa: T201
print(f"\nTests finished, deleted {number_of_files} files in the media folder") # noqa: T201
print(f"\nTests finished, deleted {number_of_files} files in the media folder") # noqa: T201
except OSError as e:
print(f"Error while deleting file in media folder: {e}") # noqa: T201


@pytest.fixture
Expand Down Expand Up @@ -897,7 +883,7 @@ def decision_details():
decision_maker_name="Test Test",
decision_maker_title="Test Title",
section_of_the_law="16 §",
decision_date=datetime.now(),
decision_date=timezone.now(),
)


Expand Down Expand Up @@ -1293,5 +1279,5 @@ def non_expired_token():
access_token="access_token",
refresh_token="refresh_token",
expires_in=30000,
created_at=datetime.now(timezone.utc),
created_at=timezone.now(),
)
8 changes: 6 additions & 2 deletions backend/benefit/applications/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ class ApplicationFactory(factory.django.DjangoModelFactory):
benefit_type = BenefitType.EMPLOYMENT_BENEFIT
start_date = factory.Faker(
"date_between_dates",
date_start=date(date.today().year, 1, 1),
# Start must not be more than 4 months old or validation errors might happen
date_start=date.today() - timedelta(days=90),
date_end=date.today() + timedelta(days=100),
)
end_date = factory.LazyAttribute(
Expand Down Expand Up @@ -160,6 +161,7 @@ def bases(self, created, extracted, **kwargs):

class Meta:
model = Application
skip_postgeneration_save = True


attachment_factory_string = "applications.tests.factories.AttachmentFactory"
Expand Down Expand Up @@ -229,6 +231,7 @@ def calculation(self, created, extracted, **kwargs):
self.calculation = Calculation.objects.create_for_application(self, **kwargs)
self.calculation.init_calculator()
self.calculation.calculate()
self.save()


class HandlingApplicationFactory(ReceivedApplicationFactory):
Expand Down Expand Up @@ -342,7 +345,7 @@ class EmployeeFactory(factory.django.DjangoModelFactory):
"random_element", elements=[v[0] for v in APPLICATION_LANGUAGE_CHOICES]
)
job_title = factory.Faker("job", locale="fi_FI")
monthly_pay = factory.Faker("random_int", max=5000)
monthly_pay = factory.Faker("random_int", min=1, max=5000)
vacation_money = factory.Faker("random_int", max=5000)
other_expenses = factory.Faker("random_int", max=5000)
working_hours = factory.Faker("random_int", min=18, max=40)
Expand Down Expand Up @@ -370,6 +373,7 @@ class BaseApplicationBatchFactory(factory.django.DjangoModelFactory):

class Meta:
model = ApplicationBatch
skip_postgeneration_save = True


class ApplicationBatchFactory(BaseApplicationBatchFactory):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def test_is_configured(ahjo_connector):
assert ahjo_connector.is_configured() is False


@pytest.mark.django_db
def test_get_new_token(ahjo_connector, ahjo_code, token_response):
# Test with valid auth code
with requests_mock.Mocker() as m:
Expand All @@ -94,6 +95,7 @@ def test_get_new_token(ahjo_connector, ahjo_code, token_response):
ahjo_connector.get_initial_token()


@pytest.mark.django_db
def test_refresh_token(ahjo_connector, ahjo_setting, token_response):
# Test with valid refresh token

Expand All @@ -115,6 +117,7 @@ def test_refresh_token(ahjo_connector, ahjo_setting, token_response):
ahjo_connector.refresh_token()


@pytest.mark.django_db
def test_refresh_expired_token(ahjo_connector, ahjo_setting, token_response):
# Test with valid refresh token
ahjo_setting.created_at = datetime.now(timezone.utc) - timedelta(hours=22)
Expand All @@ -129,6 +132,7 @@ def test_refresh_expired_token(ahjo_connector, ahjo_setting, token_response):
ahjo_connector.refresh_token()


@pytest.mark.django_db
def test_do_token_request(ahjo_connector: AhjoConnector, token_response):
# Test with successful request

Expand All @@ -149,6 +153,7 @@ def test_do_token_request(ahjo_connector: AhjoConnector, token_response):
ahjo_connector.do_token_request({})


@pytest.mark.django_db
def test_get_token_from_db(ahjo_connector: AhjoConnector, ahjo_setting):
token = ahjo_connector.get_token_from_db()
assert isinstance(token, AhjoToken)
Expand All @@ -172,6 +177,7 @@ def test_check_if_token_is_expired(expired_token, non_expired_token):
assert non_expired_token.has_expired() is False


@pytest.mark.django_db
def test_create_token(ahjo_connector: AhjoConnector, non_expired_token):
# Test with new token
token_to_create = AhjoToken(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def _prepare_calculation(application):
),
],
)
@pytest.mark.django_db
def test_decision_proposal_drafting(
application,
handler_api_client,
Expand Down
Loading
Loading