diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000000..243fe0f804
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,31 @@
+# style(benefit): apply ruff format
+5b557933b1a275d60f9ad8a449a93fa7ca37e9fe
+# style(benefit): break long strings with black and reformat with ruff
+57d5aa102229bdefd4ca845f08afc40f5b57e1c6
+# style(benefit): reflow comments
+152aa1f10be35e93314edf2ed200f384d400e291
+# style(benefit): add noqa to all E501
+039f8f60d9e1ada9c0e6fd525ba33abde42565b7
+# style(benefit): add noqa to all T201
+1a9141dff51f0fd3e35a4477bfa3510b69672c31
+
+# style(kesaseteli): apply ruff format
+83fbeeccd762ad1db105d82f030617c70504e740
+# style(kesaseteli): split long strings with black
+87a9956457afce87acb910ff07cf6313efbd3735
+# style(kesaseteli): split long comments
+e8730817bd9aa5f97cbf7b2823f9563526520118
+# style(kesaseteli): apply docformatter
+d1710d68062def0a1c43be362d5948e7ea088249
+
+# style(shared): apply ruff format
+c850e2d19f40cabbe43f8cf331e7bf642e3099f6
+# style(shared): split long strings with black
+6f84683833b9fab8d4e586f88a15a40012aa7fee
+# style(shared): split long comments
+b16a7329fc75c71353e0cfa5701a39047bd85ddd
+# style(shared): apply docformatter
+931546951c1adb4c5d3a262c190bd332ae58604f
+
+# style(kesaseteli): apply order-by-type = false
+7255990d4800d34b53811bfddd840906aad1b385
diff --git a/.github/workflows/bf-py-coding-style.yml b/.github/workflows/bf-py-coding-style.yml
index 19aa555e7d..d00ef3b9c7 100644
--- a/.github/workflows/bf-py-coding-style.yml
+++ b/.github/workflows/bf-py-coding-style.yml
@@ -6,54 +6,29 @@ on:
pull_request:
paths:
- '.github/workflows/bf-py-coding-style.yml'
+ - 'backend/benefit/**'
+ - 'backend/shared/**'
workflow_dispatch:
env:
DEBUG: 1
jobs:
- py-coding-style:
- name: Python coding style
+ pre-commit:
+ name: Run pre-commit hooks
runs-on: ubuntu-latest
-
steps:
- - name: Check out repository
- uses: actions/checkout@v3
-
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
-
- - name: Cache pip packages
- uses: actions/cache@v3
- env:
- cache-name: cache-pip-modules
- with:
- path: ~/.pip-cache
- key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('**/requirements-dev.txt') }}
- restore-keys: |
- ${{ runner.os }}-build-${{ env.cache-name }}-
- ${{ runner.os }}-build-
- ${{ runner.os }}-
-
- - name: Install dependencies
- run: cd backend/benefit && pip install -r requirements.txt -r requirements-dev.txt
-
- - name: (BF) Formatting
- run: cd backend/benefit && black --check .
-
- - name: (BF) Linting
- run: cd backend/benefit && flake8
-
- - name: (BF) Import sorting
- run: cd backend/benefit && isort -c .
-
- - name: (Shared) Formatting
- run: cd backend/shared && black --check .
-
- - name: (Shared) Linting
- run: cd backend/shared && flake8
-
- - name: (Shared) Import sorting
- run: cd backend/shared && isort -c .
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup Python ${{ inputs.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ inputs.python-version }}
+ - name: Run pre-commit (benefit)
+ uses: pre-commit/action@v3.0.1
+ with:
+ extra_args: --files backend/benefit/**
+ - name: Run pre-commit (shared)
+ uses: pre-commit/action@v3.0.1
+ with:
+ extra_args: --files backend/shared/**
diff --git a/.github/workflows/ks-py-coding-style.yml b/.github/workflows/ks-py-coding-style.yml
index 53222533ab..464dbcb864 100644
--- a/.github/workflows/ks-py-coding-style.yml
+++ b/.github/workflows/ks-py-coding-style.yml
@@ -6,54 +6,29 @@ on:
pull_request:
paths:
- '.github/workflows/ks-py-coding-style.yml'
+ - 'backend/kesaseteli/**'
+ - 'backend/shared/**'
workflow_dispatch:
env:
DEBUG: 1
jobs:
- py-coding-style:
- name: Python coding style
+ pre-commit:
+ name: Run pre-commit hooks
runs-on: ubuntu-latest
-
steps:
- - name: Check out repository
- uses: actions/checkout@v3
-
- - name: Set up Python 3.9
- uses: actions/setup-python@v4
- with:
- python-version: '3.9'
-
- - name: Cache pip packages
- uses: actions/cache@v3
- env:
- cache-name: cache-pip-modules
- with:
- path: ~/.pip-cache
- key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/requirements.txt') }}-${{ hashFiles('**/requirements-dev.txt') }}
- restore-keys: |
- ${{ runner.os }}-build-${{ env.cache-name }}-
- ${{ runner.os }}-build-
- ${{ runner.os }}-
-
- - name: Install dependencies
- run: cd backend/kesaseteli && pip install -r requirements.txt -r requirements-dev.txt
-
- - name: (KS) Formatting
- run: cd backend/kesaseteli && black --check .
-
- - name: (KS) Linting
- run: cd backend/kesaseteli && flake8
-
- - name: (KS) Import sorting
- run: cd backend/kesaseteli && isort -c .
-
- - name: (Shared) Formatting
- run: cd backend/shared && black --check .
-
- - name: (Shared) Linting
- run: cd backend/shared && flake8
-
- - name: (Shared) Import sorting
- run: cd backend/shared && isort -c .
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup Python ${{ inputs.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ inputs.python-version }}
+ - name: Run pre-commit (kesaseteli)
+ uses: pre-commit/action@v3.0.1
+ with:
+ extra_args: --files backend/kesaseteli/**
+ - name: Run pre-commit (shared)
+ uses: pre-commit/action@v3.0.1
+ with:
+ extra_args: --files backend/shared/**
diff --git a/.husky/commit-msg b/.husky/commit-msg
deleted file mode 100755
index c160a77123..0000000000
--- a/.husky/commit-msg
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/usr/bin/env sh
-. "$(dirname -- "$0")/_/husky.sh"
-
-npx --no -- commitlint --edit ${1}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index ecf48e5d47..44df1fcb0e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,60 +1,35 @@
-fail_fast: true
-
+# Keep tool versions in sync with the versions in requirements-dev.txt
default_language_version:
- python: python3
-
-exclude: ^.*\b(migrations)\b.*$
-default_stages: [commit, manual]
-
+ python: python3
+default_install_hook_types: [pre-commit, commit-msg]
+default_stages: [pre-commit, manual]
repos:
- - repo: https://github.com/psf/black
- rev: 23.1.0
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v6.0.0
hooks:
- - id: black
- name: (BF) black
- files: ^backend/benefit
- - id: black
- name: (KS) black
- files: ^backend/kesaseteli
- - id: black
- name: (Shared) black
- files: ^backend/shared
- - repo: https://github.com/pycqa/isort
- rev: 5.12.0
+ - id: trailing-whitespace
+ - id: end-of-file-fixer
+ - id: check-yaml
+ - id: check-toml
+ - id: check-added-large-files
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.13.1
hooks:
- - id: isort
- name: (BF) isort
- args: [--settings-file, backend/benefit/setup.cfg]
- files: ^backend/benefit
- - id: isort
- name: (KS) isort
- args: [--settings-file, backend/kesaseteli/setup.cfg]
- files: ^backend/kesaseteli
- - id: isort
- name: (Shared) isort
- args: [--settings-file, backend/shared/setup.cfg]
- files: ^backend/shared
- - repo: https://github.com/pycqa/flake8
- rev: 6.0.0
+ # Run the linter.
+ - id: ruff-check
+ args: [ "--fix" ]
+ # Run the formatter.
+ - id: ruff-format
+ - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
+ rev: v9.22.0
hooks:
- - id: flake8
- name: (BF) flake8
- additional_dependencies: [flake8-isort, flake8-black]
- exclude: migrations|snapshots
- files: ^backend/benefit
- args: [--config, backend/benefit/setup.cfg]
- - id: flake8
- name: (KS) flake8
- additional_dependencies: [flake8-isort, flake8-black]
- exclude: migrations|snapshots
- files: ^backend/kesaseteli
- args: [--config, backend/kesaseteli/setup.cfg]
- - id: flake8
- name: (Shared) flake8
- additional_dependencies: [flake8-isort, flake8-black]
- exclude: migrations|snapshots
- files: ^backend/shared
- args: [--config, backend/shared/setup.cfg]
+ - id: commitlint
+ stages: [commit-msg, manual]
+ additional_dependencies: ["@commitlint/config-conventional"]
+ - repo: https://github.com/koalaman/shellcheck-precommit
+ rev: v0.10.0
+ hooks:
+ - id: shellcheck
- repo: local
hooks:
- id: lint-staged
@@ -63,11 +38,3 @@ repos:
language: system
types: [file]
require_serial: true
- - repo: local
- hooks:
- - id: commit-msg
- name: Validate commit message (conventional commits)
- entry: "./.husky/commit-msg"
- language: system
- stages:
- - commit-msg
diff --git a/README.md b/README.md
index 8ee255e444..39ff2b286b 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ This monorepo contains code for three different employment services:
* Handler
* **TET Job Search** - retired and can be found in [here](https://github.com/City-of-Helsinki/yjdh/tree/ab8b87d5466badb37dccb968830ddbb2a51ec170)
- * Backend
+ * Backend
* Youth
* Admin
@@ -59,7 +59,7 @@ More information in [Confluence](https://helsinkisolutionoffice.atlassian.net/wi
3. Make additional changes & commit, e.g. `git commit -m "feat: new feature frontend"`
4. Open a pull request, for example with title `HL-123: New feature`
5. After PR checks are passed and PR is approved, merge with squash merge (set commit message to e.g. `feat: new feature`) or rebase and merge
-6. Release Please opens release PR with a title similar to this: `chore(main): release benefit-backend 1.1.1`
+6. Release Please opens release PR with a title similar to this: `chore(main): release benefit-backend 1.1.1`
7. Merge release pull request to `main`. This creates a versioned release tag (e.g. `benefit-backend: v1.1.1`) that triggers staging and production deploy (Deploys still must be approved from Azure DevOps).
## Setting up git hooks
@@ -141,12 +141,24 @@ YJDH-Benefit provides two services for applying and for handling the application
1. If github action deploy fail with error like this in your pull-request:
```text
- Error: rendered manifests contain a resource that already exists.
- Unable to continue with install: Service "yjdh-135-send-localization-param-to-suomifi-yjdh-ks-service"
- in namespace "yjdh-yjdh-135-send-localization-param-to-suomifi-227" exists and cannot be
- imported into the current release: invalid ownership metadata; annotation validation error:
- key "meta.helm.sh/release-name" must equal "yjdh-135-send-localization-par-review-yjdh-ks-bknd":
+ Error: rendered manifests contain a resource that already exists.
+ Unable to continue with install: Service "yjdh-135-send-localization-param-to-suomifi-yjdh-ks-service"
+ in namespace "yjdh-yjdh-135-send-localization-param-to-suomifi-227" exists and cannot be
+ imported into the current release: invalid ownership metadata; annotation validation error:
+ key "meta.helm.sh/release-name" must equal "yjdh-135-send-localization-par-review-yjdh-ks-bknd":
current value is "yjdh-135-send-localization-par-review-yjdh-ks-empl"
```
The reason for this is that your pr's branch name is too long. You have to rename it and create a new pr. See instructions at [StackOverflow](https://stackoverflow.com/questions/30590083/how-do-i-rename-both-a-git-local-and-remote-branch-name).
+
+
+### Git blame ignore refs
+
+Project includes a `.git-blame-ignore-revs` file for ignoring certain commits from `git blame`.
+This can be useful for ignoring e.g. formatting commits, so that it is more clear from `git blame`
+where the actual code change came from. Configure your git to use it for this project with the
+following command:
+
+```shell
+git config blame.ignoreRevsFile .git-blame-ignore-revs
+```
diff --git a/backend/benefit/README.md b/backend/benefit/README.md
index d24105c927..f14811fc44 100644
--- a/backend/benefit/README.md
+++ b/backend/benefit/README.md
@@ -189,17 +189,18 @@ Currently configured jobs (registered in the `applications/jobs`-directory):
## Code format
-This project uses
-[`black`](https://github.com/psf/black),
-[`flake8`](https://gitlab.com/pycqa/flake8) and
-[`isort`](https://github.com/PyCQA/isort)
-for code formatting and quality checking. Project follows the basic
-black config, without any modifications.
+This project uses [](https://docs.astral.sh/ruff/) for code formatting and quality checking.
+
+Basic `ruff` commands:
-Basic `black` commands:
+* lint: `ruff check`
+* apply safe lint fixes: `ruff check --fix`
+* check formatting: `ruff format --check`
+* format: `ruff format`
-- To let `black` do its magic: `black .`
-- To see which files `black` would change: `black --check .`
+[`pre-commit`](https://pre-commit.com/) can be used to install and
+run all the formatting tools as git hooks automatically before a
+commit.
## Storages
diff --git a/backend/benefit/applications/api/v1/ahjo_decision_views.py b/backend/benefit/applications/api/v1/ahjo_decision_views.py
index bd278e1eab..ba2baf7548 100644
--- a/backend/benefit/applications/api/v1/ahjo_decision_views.py
+++ b/backend/benefit/applications/api/v1/ahjo_decision_views.py
@@ -1,7 +1,7 @@
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _
from drf_spectacular.types import OpenApiTypes
-from drf_spectacular.utils import extend_schema, OpenApiParameter
+from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
@@ -31,7 +31,7 @@ class DecisionProposalTemplateSectionList(APIView):
"""
View to list the decision proposal templates with placeholders replaced by actual application data.
* Only handlers are able to access this view.
- """
+ """ # noqa: E501
permission_classes = [BFIsHandler]
@@ -45,7 +45,7 @@ class DecisionProposalTemplateSectionList(APIView):
location=OpenApiParameter.PATH,
),
],
- description=("API for querying decision proposal templates"),
+ description="API for querying decision proposal templates",
request=DecisionProposalTemplateSectionSerializer,
)
def get(self, request, format=None) -> Response:
@@ -102,7 +102,8 @@ def get(self, request, format=None) -> Response:
),
],
description=(
- "API for listing and creating decision texts. Only handlers are able to access this view."
+ "API for listing and creating decision texts. Only handlers are able to access"
+ " this view."
),
request=DecisionTextSerializer,
)
@@ -180,8 +181,11 @@ def patch(self, request):
decision_part = data.get("decision_text")
justification_part = data.get("justification_text")
ahjo_text = AhjoDecisionText.objects.filter(application=application)
- decision_text = f'{_("Päätös")}
{decision_part}\
-{_("Päätöksen perustelut")}
{justification_part}'
+ decision_text = (
+ "{_("Päätös")}
{decision_part}{_("Päätöksen perustelut")}
{justification_part}' # noqa: E501
+ )
available_decision_makers = AhjoSetting.objects.get(
name="ahjo_decision_maker"
diff --git a/backend/benefit/applications/api/v1/ahjo_integration_views.py b/backend/benefit/applications/api/v1/ahjo_integration_views.py
index 4a3ebc76b2..1b5f3146ca 100644
--- a/backend/benefit/applications/api/v1/ahjo_integration_views.py
+++ b/backend/benefit/applications/api/v1/ahjo_integration_views.py
@@ -6,7 +6,7 @@
from django.http import FileResponse
from django.shortcuts import get_object_or_404
from drf_spectacular.types import OpenApiTypes
-from drf_spectacular.utils import extend_schema, OpenApiParameter
+from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework import status
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
@@ -18,13 +18,15 @@
AhjoDecisionCallbackSerializer,
)
from applications.enums import (
+ DEFAULT_AHJO_CALLBACK_ERROR_MESSAGE,
AhjoCallBackStatus,
AhjoDecisionUpdateType,
AhjoRequestType,
- AhjoStatus as AhjoStatusEnum,
ApplicationBatchStatus,
ApplicationStatus,
- DEFAULT_AHJO_CALLBACK_ERROR_MESSAGE,
+)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
)
from applications.models import AhjoStatus, Application, ApplicationBatch, Attachment
from applications.services.ahjo.exceptions import AhjoCallbackError
@@ -48,7 +50,9 @@ class AhjoApplicationView(APIView):
location=OpenApiParameter.PATH,
)
],
- description="Sends a delete / cancel case request to Ahjo for given application.",
+ description=(
+ "Sends a delete / cancel case request to Ahjo for given application."
+ ),
)
def delete(self, request, *args, **kwargs):
application_id = self.kwargs["uuid"]
@@ -61,7 +65,10 @@ def delete(self, request, *args, **kwargs):
):
return Response(
{
- "message": "Cannot delete because a decision proposal has been sent to Ahjo"
+ "message": (
+ "Cannot delete because a decision proposal has been sent to"
+ " Ahjo"
+ )
},
status=status.HTTP_400_BAD_REQUEST,
)
@@ -103,8 +110,10 @@ def get(self, request, *args, **kwargs):
"", # Optional user backend
Operation.READ,
attachment,
- additional_information=f"attachment {attachment.attachment_file} \
-of type {attachment.attachment_type} was sent to AHJO!",
+ additional_information=(
+ f"attachment {attachment.attachment_file} of type"
+ f" {attachment.attachment_type} was sent to AHJO!"
+ ),
)
attachment.downloaded_by_ahjo = datetime.now(timezone.utc)
attachment.save()
@@ -115,9 +124,9 @@ def _prepare_file_response(attachment: Attachment) -> FileResponse:
file_handle = attachment.attachment_file.open()
response = FileResponse(file_handle, content_type=attachment.content_type)
response["Content-Length"] = attachment.attachment_file.size
- response[
- "Content-Disposition"
- ] = f"attachment; filename={attachment.attachment_file.name}"
+ response["Content-Disposition"] = (
+ f"attachment; filename={attachment.attachment_file.name}"
+ )
return response
@@ -186,9 +195,11 @@ def cb_info_message(
request_type: AhjoRequestType,
) -> str:
"""Return a string with information about the received callback."""
- return f"Application {application.application_number}: \
- received a callback for request_type {request_type} \
- with request id: {callback_data['requestId']}, full callback data: {callback_data}"
+ return (
+ f"Application {application.application_number}: received a callback"
+ f" for request_type {request_type} with request id:"
+ f" {callback_data['requestId']}, full callback data: {callback_data}"
+ )
@transaction.atomic
def handle_success_callback(
@@ -289,7 +300,7 @@ def _handle_open_case_success(self, application: Application, callback_data: dic
"""Update the application with the case id (diaarinumero) and case guid from the Ahjo callback data.
If the application has attachments with a matching hash value, save the version series id for each attachment.
Create a new single-application ApplicationBatch for the application and set the batch_id for the application.
- """
+ """ # noqa: E501
if callback_data["caseGuid"]:
application.ahjo_case_guid = callback_data["caseGuid"]
if callback_data["caseId"]:
@@ -337,10 +348,12 @@ def _save_version_series_id(
attachment.save()
def handle_decision_proposal_success(self, application: Application):
- # do anything that needs to be done when Ahjo has received a decision proposal request
+ # do anything that needs to be done when Ahjo has received a decision proposal
+ # request
if not application.batch:
raise AhjoCallbackError(
- f"Application {application.id} has no batch when Ahjo has received a decision proposal request"
+ f"Application {application.id} has no batch when Ahjo has received a"
+ " decision proposal request"
)
batch = application.batch
batch.status = ApplicationBatchStatus.AWAITING_AHJO_DECISION
@@ -353,14 +366,16 @@ def _log_failure_details(
request_type: AhjoRequestType,
):
LOGGER.error(
- f"Received unsuccessful callback for {request_type} for application {application.id} \
- with request_id {callback_data['requestId']}, callback data: {callback_data}"
+ f"Received unsuccessful callback for {request_type} for application"
+ f" {application.id} with request_id"
+ f" {callback_data['requestId']}, callback data: {callback_data}"
)
for cb_record in callback_data.get("records", []):
if cb_record.get("status") == AhjoCallBackStatus.FAILURE:
LOGGER.error(
- f"Ahjo reports failure with record, hash value {cb_record['hashValue']} \
- and fileURI {cb_record['fileURI']}"
+ "Ahjo reports failure with record, hash value"
+ f" {cb_record['hashValue']} and fileURI"
+ f" {cb_record['fileURI']}"
)
@@ -401,8 +416,11 @@ def post(self, request, *args, **kwargs):
"",
Operation.UPDATE,
application,
- additional_information=f"Decision proposal callback of type: {update_type} was received \
- from Ahjo for application {application.application_number}",
+ additional_information=(
+ f"Decision proposal callback of type: {update_type} was"
+ " received from Ahjo for application"
+ f" {application.application_number}"
+ ),
)
except Application.DoesNotExist:
# Ahjo needs a 200 OK response even if an application is not found
diff --git a/backend/benefit/applications/api/v1/application_batch_views.py b/backend/benefit/applications/api/v1/application_batch_views.py
index ba7633a36e..9ffd914235 100755
--- a/backend/benefit/applications/api/v1/application_batch_views.py
+++ b/backend/benefit/applications/api/v1/application_batch_views.py
@@ -12,7 +12,8 @@
from django_filters import rest_framework as filters
from django_filters.widgets import CSVWidget
from drf_spectacular.utils import extend_schema
-from rest_framework import filters as drf_filters, status
+from rest_framework import filters as drf_filters
+from rest_framework import status
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
@@ -47,8 +48,10 @@ class ApplicationBatchFilter(filters.FilterSet):
widget=CSVWidget,
choices=ApplicationBatchStatus.choices,
help_text=(
- "Filter by application batch status. Multiple statuses may be specified as"
- " a comma-separated list, such as 'status=draft,decided'",
+ (
+ "Filter by application batch status. Multiple statuses may be specified"
+ " as a comma-separated list, such as 'status=draft,decided'"
+ ),
),
)
@@ -227,7 +230,9 @@ def talpa_export_batch(self, request, *args, **kwargs) -> HttpResponse:
Operation.READ,
a,
ip_address=ip_address,
- additional_information="application csv data was downloaded by TALPA robot",
+ additional_information=(
+ "application csv data was downloaded by TALPA robot"
+ ),
)
return response
@@ -238,7 +243,7 @@ def assign_applications(self, request):
"""
Assign one or more applications to a batch. If there's no batch for given app status,
create one as a draft and assign all applications to it.
- """
+ """ # noqa: E501
app_status = request.data["status"]
app_ids = request.data["application_ids"]
@@ -251,7 +256,7 @@ def create_application_batch_by_ids(app_status, apps):
if (
app_status not in [ApplicationStatus.ACCEPTED, ApplicationStatus.REJECTED]
- or type(app_ids) != list
+ or type(app_ids) is not list
):
return Response(
{"detail": "Status or application id is not valid"},
@@ -286,7 +291,10 @@ def create_application_batch_by_ids(app_status, apps):
else:
return Response(
{
- "detail": "Unable to create a new batch or merge application to existing one."
+ "detail": (
+ "Unable to create a new batch or merge application to existing"
+ " one."
+ )
},
status=status.HTTP_400_BAD_REQUEST,
)
@@ -326,7 +334,7 @@ def deassign_applications(self, request, pk=None):
def status(self, request, pk=None):
"""
Assign a new status for batch: as pending for Ahjo proposal or switch back to draft
- """
+ """ # noqa: E501
new_status = request.data["status"]
if _unallowed_status_change(new_status):
diff --git a/backend/benefit/applications/api/v1/application_views.py b/backend/benefit/applications/api/v1/application_views.py
index 84ebf39cf8..d9703bfa8f 100755
--- a/backend/benefit/applications/api/v1/application_views.py
+++ b/backend/benefit/applications/api/v1/application_views.py
@@ -1,7 +1,7 @@
import logging
import re
from datetime import date, timedelta
-from decimal import Decimal, ROUND_DOWN
+from decimal import ROUND_DOWN, Decimal
from typing import List
from dateutil.relativedelta import relativedelta
@@ -15,11 +15,13 @@
from django.utils import timezone
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
-from django_filters import DateFromToRangeFilter, rest_framework as filters
+from django_filters import DateFromToRangeFilter
+from django_filters import rest_framework as filters
from django_filters.widgets import CSVWidget
from drf_spectacular.types import OpenApiTypes
-from drf_spectacular.utils import extend_schema, OpenApiParameter
-from rest_framework import filters as drf_filters, status
+from drf_spectacular.utils import OpenApiParameter, extend_schema
+from rest_framework import filters as drf_filters
+from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
from rest_framework.parsers import MultiPartParser
@@ -90,8 +92,10 @@ class BaseApplicationFilter(filters.FilterSet):
widget=CSVWidget,
choices=ApplicationStatus.choices,
help_text=(
- "Filter by application status. Multiple statuses may be specified as a"
- " comma-separated list, such as 'status=draft,received'",
+ (
+ "Filter by application status. Multiple statuses may be specified as a"
+ " comma-separated list, such as 'status=draft,received'"
+ ),
),
)
archived_for_applicant = filters.BooleanFilter(
@@ -148,7 +152,8 @@ class Meta:
class HandlerApplicationFilter(BaseApplicationFilter):
- # the date when application was last set to either REJECTED, ACCEPTED or CANCELLED status
+ # the date when application was last set to either REJECTED, ACCEPTED or CANCELLED
+ # status
handled_at = DateFromToRangeFilter(method="filter_handled_at")
def filter_handled_at(self, queryset, name, value):
@@ -193,8 +198,10 @@ class Meta:
widget=CSVWidget,
choices=ApplicationAlterationState.choices,
help_text=(
- "Filter by alteration state. Multiple states may be specified as a"
- " comma-separated list, such as 'state=handled,cancelled'",
+ (
+ "Filter by alteration state. Multiple states may be specified as a"
+ " comma-separated list, such as 'state=handled,cancelled'"
+ ),
),
)
@@ -251,13 +258,14 @@ def simplified_application_list(self, request):
"""
Convenience action for the frontends that by default excludes the fields that are not normally
needed in application listing pages.
- """
+ """ # noqa: E501
context = self.get_serializer_context()
qs = self._get_simplified_queryset(request, context)
serializer = self.serializer_class(qs, many=True, context=context)
data = serializer.data
- # Sorting by encrypted fields has to be done after the data has been retrieved and decrypted
+ # Sorting by encrypted fields has to be done after the data has been retrieved
+ # and decrypted
if request.query_params.get("order_by") in ["employee_name"]:
data = sorted(
data,
@@ -340,7 +348,8 @@ def _get_simplified_queryset(self, request, context) -> QuerySet:
if should_filter_archived:
qs = qs.filter(archived=should_filter_archived)
else:
- # Applications with second instalment are considered archived but should be included in main views
+ # Applications with second instalment are considered archived but should
+ # be included in main views
qs = qs.filter(
Q(archived=should_filter_archived)
| Q(pk__in=self._get_application_pks_with_instalments())
@@ -428,7 +437,7 @@ def get_application_template(self, request, pk=None):
del v["id"]
else:
de_minimis_aid_set = []
- """
+ """ # noqa: E501
de_minimis_aid_set = []
return Response(
{
@@ -501,7 +510,8 @@ def update(self, request, *args, **kwargs):
)
# If the alteration has been handled, the only allowed edit is to cancel it.
- # If the alteration has been cancelled, it cannot be modified in any way anymore.
+ # If the alteration has been cancelled, it cannot be modified in any way
+ # anymore.
if current_state == ApplicationAlterationState.CANCELLED or (
current_state == ApplicationAlterationState.HANDLED and forbidden_if_handled
):
@@ -532,7 +542,8 @@ def update_with_csv(self, request):
alteration.recovery_start_date = request.data.get("recovery_start_date")
alteration.save()
- # CsvService requires a queryset, so we need to create a queryset with the alteration
+ # CsvService requires a queryset, so we need to create a queryset with the
+ # alteration
queryset = ApplicationAlteration.objects.filter(
id__in=[alteration.id],
)
@@ -549,7 +560,8 @@ def update_with_csv(self, request):
)
except ObjectDoesNotExist:
raise ImproperlyConfigured(
- "application_alteration_fields fields not found in the ahjo_settings table"
+ "application_alteration_fields fields not found in the ahjo_settings"
+ " table"
)
def _alterations_csv_response(
@@ -558,7 +570,7 @@ def _alterations_csv_response(
config: AlterationCsvConfigurableFields,
user: User,
) -> StreamingHttpResponse:
- """Generate a response with a CSV file containing application alteration data."""
+ """Generate a response with a CSV file containing application alteration data.""" # noqa: E501
csv_service = ApplicationAlterationCsvService(queryset, config, user)
response = HttpResponse(
@@ -590,7 +602,8 @@ class ApplicantApplicationViewSet(BaseApplicationViewSet):
filterset_class = ApplicantApplicationFilter
def _annotate_unread_messages_count(self, qs):
- # since there other annotations added elsewhere, use subquery to avoid wrong results.
+ # since there other annotations added elsewhere, use subquery to avoid wrong
+ # results.
# also, using a subquery is more performant
return qs.annotate(
unread_messages_count=SubqueryCount(
@@ -747,14 +760,15 @@ def _annotate_unread_messages_count(self, qs):
def get_queryset(self):
# The default ordering in the handling views:
- # * In the "received" table, ordering should be by the send time, most recent first
+ # * In the "received" table, ordering should be by the send time, most recent
+ # first
# * In the "handling" table, ordering should be by the calculation modification
# time, most recent first
# * In the archive page, ordering should be by handled_at, most recent first.
# All these goals are achieved by ordering by first handled_at, then
# calculation.modified_at.
- # * in the "received" and "handling" table, no application has handled_at set yet,
- # so applications will compare as equals
+ # * in the "received" and "handling" table, no application has handled_at set
+ # yet, so applications will compare as equals
# * For received applications, the send time is the same as calculation
# modification time
return self._annotate_unread_messages_count(
@@ -898,8 +912,8 @@ def require_additional_information(self, request, pk) -> HttpResponse:
if to_status == ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED:
# Create an automatic message for the applicant
- # self.instance.additional_information_requested_at is not updated at this point as
- # it's a queryset annotation, so need to refresh
+ # self.instance.additional_information_requested_at is not updated at
+ # this point as it's a queryset annotation, so need to refresh
application.additional_information_requested_at = (
Application.objects.get(
pk=application.pk
@@ -933,14 +947,15 @@ def _create_application_batch(self, status) -> QuerySet[Application]:
"""
Create a new application batch out of the existing applications in the given status
that are not yet assigned to a batch.
- """
+ """ # noqa: E501
queryset = self.get_queryset().filter(status=status, batch__isnull=True)
status_map = {
ApplicationStatus.ACCEPTED: ApplicationBatchStatus.DECIDED_ACCEPTED,
ApplicationStatus.REJECTED: ApplicationBatchStatus.DECIDED_REJECTED,
}
if status not in status_map:
- assert False, "Internal error, should not happen"
+ raise AssertionError("Internal error, should not happen")
+
application_ids = [application.pk for application in queryset]
if queryset:
batch = ApplicationBatch.objects.create(
diff --git a/backend/benefit/applications/api/v1/power_bi_integration_views.py b/backend/benefit/applications/api/v1/power_bi_integration_views.py
index d29f97ee68..83622f8d7a 100644
--- a/backend/benefit/applications/api/v1/power_bi_integration_views.py
+++ b/backend/benefit/applications/api/v1/power_bi_integration_views.py
@@ -3,7 +3,8 @@
from django.db.models import QuerySet
from django.http import StreamingHttpResponse
from django.utils import timezone
-from django_filters import DateFromToRangeFilter, rest_framework as filters
+from django_filters import DateFromToRangeFilter
+from django_filters import rest_framework as filters
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
@@ -60,7 +61,8 @@ def get(self, request, *args, **kwargs) -> StreamingHttpResponse:
)
return response
else:
- # Handle invalid filters (e.g., return a default queryset or handle the error)
+ # Handle invalid filters (e.g., return a default queryset or handle the
+ # error)
return StreamingHttpResponse("Invalid filters", status=400)
def _csv_response(
diff --git a/backend/benefit/applications/api/v1/search_views.py b/backend/benefit/applications/api/v1/search_views.py
index fd41646c0d..6b97c26614 100755
--- a/backend/benefit/applications/api/v1/search_views.py
+++ b/backend/benefit/applications/api/v1/search_views.py
@@ -13,7 +13,8 @@
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from fuzzywuzzy import fuzz
-from rest_framework import filters as drf_filters, status
+from rest_framework import filters as drf_filters
+from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
@@ -328,7 +329,7 @@ def _query_by_application_number(
Q(year_of_birth=f"{year_prefix}{year_suffix}")
| Q(
year_of_birth="1900"
- ) # A few ArchivalApplication do not have birth year and is marked as 1900
+ ) # A few ArchivalApplication do not have birth year and is marked as 1900 # noqa: E501
),
),
}
@@ -400,7 +401,7 @@ def _query_and_respond_to_numbers(
):
"""
Perform simple LIKE query for application number, AHJO case ID and company business ID
- """
+ """ # noqa: E501
applications = application_queryset.filter(
Q(company__business_id__icontains=search_query_str)
| Q(ahjo_case_id__icontains=search_query_str)
@@ -464,7 +465,8 @@ def _perform_in_memory_search(
else:
detected_pattern = f"{SearchPattern.COMPANY} {SearchPattern.IN_MEMORY}"
- # Try fuzzy matching with high threshold. If zero matches, try lower score and finally try substring matching
+ # Try fuzzy matching with high threshold. If zero matches, try lower score and
+ # finally try substring matching
in_memory_results = _fuzzy_matching(data, in_memory_filter_str, 80)
if not in_memory_results["data"]:
in_memory_results = _fuzzy_matching(data, in_memory_filter_str, 70)
@@ -475,7 +477,7 @@ def _perform_in_memory_search(
)
detected_pattern += "-fallback"
- return {**in_memory_results, **{"detected_pattern": detected_pattern}}
+ return {**in_memory_results, "detected_pattern": detected_pattern}
def _query_for_company_name(
diff --git a/backend/benefit/applications/api/v1/serializers/ahjo_callback.py b/backend/benefit/applications/api/v1/serializers/ahjo_callback.py
index 7cbe40cf88..d218f6e38b 100644
--- a/backend/benefit/applications/api/v1/serializers/ahjo_callback.py
+++ b/backend/benefit/applications/api/v1/serializers/ahjo_callback.py
@@ -3,11 +3,11 @@
class AhjoCallbackSerializer(serializers.Serializer):
message = serializers.CharField(required=False)
- requestId = serializers.UUIDField(format="hex_verbose", required=False)
- caseId = serializers.CharField(required=False)
- caseGuid = serializers.UUIDField(format="hex_verbose", required=False)
+ requestId = serializers.UUIDField(format="hex_verbose", required=False) # noqa: N815
+ caseId = serializers.CharField(required=False) # noqa: N815
+ caseGuid = serializers.UUIDField(format="hex_verbose", required=False) # noqa: N815
records = serializers.ListField(required=False)
- failureDetails = serializers.ListField(required=False)
+ failureDetails = serializers.ListField(required=False) # noqa: N815
# You can add additional validation here if needed
def validate_message(self, message):
@@ -20,5 +20,5 @@ def validate_message(self, message):
class AhjoDecisionCallbackSerializer(serializers.Serializer):
updatetype = serializers.CharField(required=False)
id = serializers.CharField(required=False)
- caseId = serializers.CharField(required=False)
- caseGuid = serializers.UUIDField(format="hex_verbose", required=False)
+ caseId = serializers.CharField(required=False) # noqa: N815
+ caseGuid = serializers.UUIDField(format="hex_verbose", required=False) # noqa: N815
diff --git a/backend/benefit/applications/api/v1/serializers/application.py b/backend/benefit/applications/api/v1/serializers/application.py
index 6e032fe8d5..9652086253 100755
--- a/backend/benefit/applications/api/v1/serializers/application.py
+++ b/backend/benefit/applications/api/v1/serializers/application.py
@@ -37,6 +37,8 @@
from applications.benefit_aggregation import get_former_benefit_info
from applications.enums import (
AhjoStatus as AhjoStatusEnum,
+)
+from applications.enums import (
ApplicationActions,
ApplicationBatchStatus,
ApplicationOrigin,
@@ -70,8 +72,8 @@
from common.delay_call import call_now_or_later, do_delayed_calls_at_end
from common.exceptions import BenefitAPIException
from common.utils import (
- get_date_range_end_with_days360,
PhoneNumberField,
+ get_date_range_end_with_days360,
to_decimal,
update_object,
)
@@ -111,7 +113,7 @@ class BaseApplicationSerializer(DynamicFieldsModelSerializer):
Fields in the Company model come from YTJ/other source and are not editable by user, and are listed
in read_only_fields. If sent in the request, these fields are ignored.
- """
+ """ # noqa: E501
status = serializers.ChoiceField(
choices=ApplicationStatus.choices,
@@ -548,7 +550,7 @@ def get_warnings(self, obj) -> Dict[str, List[str]]:
"warning string",
],
}
- """
+ """ # noqa: E501
warnings = {}
if all(
[
@@ -749,7 +751,7 @@ def _validate_de_minimis_aid_set(
* de_minimis_aid: boolean yes/no/null value
* de_minimis_aid_set: the DeMinimisAid objects represented as list of dicts
(at this point, the individual dicts have been already valided by DeMinimisAidSerializer
- """
+ """ # noqa: E501
if (
OrganizationType.resolve_organization_type(company.company_form_code)
== OrganizationType.ASSOCIATION
@@ -895,13 +897,14 @@ def _validate_non_draft_required_fields(self, data):
) == OrganizationType.ASSOCIATION:
required_fields.append("association_has_business_activities")
- # For associations, validate() already limits the association_immediate_manager_check value to [None, True]
+ # For associations, validate() already limits the
+ # association_immediate_manager_check value to [None, True]
# at submit time, only True is allowed.
required_fields.append("association_immediate_manager_check")
elif organization_type == OrganizationType.COMPANY:
required_fields.append("de_minimis_aid")
else:
- assert False, "unreachable"
+ raise AssertionError("unreachable")
# if pay_subsidy_granted is selected, then the applicant needs to also select if
# it's an apprenticeship_program or not
@@ -985,7 +988,8 @@ def _validate_apprenticeship_program(
raise serializers.ValidationError(
{
"apprenticeship_program": _(
- "Apprenticeship program can not be selected if there is no granted pay subsidy"
+ "Apprenticeship program can not be selected if there is no"
+ " granted pay subsidy"
)
}
)
@@ -998,7 +1002,8 @@ def _validate_apprenticeship_program(
raise serializers.ValidationError(
{
"apprenticeship_program": _(
- "Apprenticeship program has to be yes or no if there is a granted pay subsidy"
+ "Apprenticeship program has to be yes or no if there is a"
+ " granted pay subsidy"
)
}
)
@@ -1021,7 +1026,7 @@ def _get_available_benefit_types(
"""
Make the logic of determining available benefit types available both for generating the list of
benefit types and validating the incoming data
- """
+ """ # noqa: E501
if (
OrganizationType.resolve_organization_type(company.company_form_code)
== OrganizationType.ASSOCIATION
@@ -1048,10 +1053,11 @@ def _handle_breaking_changes(self, company, data):
"""
Handle cases where applicant is updating an application, moves back to a previous page
and changes a field value in an incompatible way.
- """
+ """ # noqa: E501
if not self.instance:
# only handle the changes when doing updates.
- # incompatible data that is sent when creating an application results in a validation error.
+ # incompatible data that is sent when creating an application results in a
+ # validation error.
return
if OrganizationType.resolve_organization_type(
@@ -1083,7 +1089,8 @@ def _reset_de_minimis_aid(self, data):
data["de_minimis_aid_set"] = []
def _reset_benefit_type(self, data):
- # reset the benefit type and the fields in the employee that are tied to the benefit type
+ # reset the benefit type and the fields in the employee that are tied to the
+ # benefit type
data["benefit_type"] = ""
data["employee"]["job_title"] = ""
data["employee"]["commission_description"] = ""
@@ -1160,25 +1167,23 @@ def handle_status_transition(
self, instance, previous_status, approve_terms, log_entry_comment
):
if (
- (
- previous_status,
- instance.status,
- )
- in ApplicantApplicationStatusValidator.SUBMIT_APPLICATION_STATE_TRANSITIONS
- ):
+ previous_status,
+ instance.status,
+ ) in ApplicantApplicationStatusValidator.SUBMIT_APPLICATION_STATE_TRANSITIONS:
# moving out of DRAFT or ADDITIONAL_INFORMATION_NEEDED, so the applicant
# may have modified the application
self._validate_attachments(instance)
self._validate_employee_consent(instance)
self._update_applicant_terms_approval(instance, approve_terms)
if not hasattr(instance, "calculation"):
- # if the previous status was ADDITIONAL_INFORMATION_NEEDED, then calculation already
- # exists
+ # if the previous status was ADDITIONAL_INFORMATION_NEEDED, then
+ # calculation already exists
Calculation.objects.create_for_application(instance)
if previous_status == ApplicationStatus.DRAFT:
- # Do not validate if previous_status is ADDITIONAL_INFORMATION_NEEDED, as the validation
- # rule only applies to the first application submission.
+ # Do not validate if previous_status is ADDITIONAL_INFORMATION_NEEDED,
+ # as the validation rule only applies to the first application
+ # submission.
user = self.get_logged_in_user()
self._validate_date_range_on_submit(
instance.start_date, instance.end_date, user.is_staff
@@ -1262,7 +1267,7 @@ def _validate_attachments(self, instance):
* If wrong types of attachments have been uploaded, they are purged from the system. This might happen
if the applicant first uploads attachments, but then goes back to previous steps and changes certain
application fields before submitting the application
- """
+ """ # noqa: E501
attachment_requirements = self.get_attachment_requirements(instance)
required_attachment_types = [
@@ -1290,7 +1295,8 @@ def _validate_attachments(self, instance):
required_attachment_types.remove(attachment.attachment_type)
if required_attachment_types:
- # if anything still remains in the list, it means some attachment(s) were missing
+ # if anything still remains in the list, it means some attachment(s) were
+ # missing
raise serializers.ValidationError(
_("Application does not have required attachments")
)
@@ -1397,7 +1403,8 @@ def _update_de_minimis_aid(self, application, de_minimis_data):
)
)
# Clear the previous DeMinimisAid objects from the database.
- # The request must always contain all the DeMinimisAid objects for this application.
+ # The request must always contain all the DeMinimisAid objects for this
+ # application.
current_de_minimis_aid_set = application.de_minimis_aid_set.all()
for de_minimis in current_de_minimis_aid_set:
audit_logging.log(
@@ -1410,9 +1417,9 @@ def _update_de_minimis_aid(self, application, de_minimis_data):
for idx, aid_item in enumerate(serializer.validated_data):
aid_item["application_id"] = application.pk
- aid_item[
- "ordering"
- ] = idx # use the ordering defined in the JSON sent by the client
+ aid_item["ordering"] = (
+ idx # use the ordering defined in the JSON sent by the client
+ )
de_minimis_list = serializer.save()
for de_minimis in de_minimis_list:
@@ -1523,7 +1530,7 @@ def get_batch_status(self, obj):
return getattr(obj.batch, "status", False) if obj.batch else False
changes = serializers.SerializerMethodField(
- help_text=("Possible changes made by handler to the application."),
+ help_text="Possible changes made by handler to the application.",
)
def get_changes(self, obj):
@@ -1730,9 +1737,10 @@ def update(self, instance, validated_data):
_("Application can not be changed in this status")
)
calculation_data = validated_data.pop("calculation", None)
- # FIX for HL-639 where application submitted manually by handler is missing pay subsidies in the DB
- # because in the JSON payload pay_subsidies is an empty list and thus not None
- # here we check that this is the final submit request from the handler and if so, we set pay_subsidies to None
+ # FIX for HL-639 where application submitted manually by handler is missing pay
+ # subsidies in the DB because in the JSON payload pay_subsidies is an empty list
+ # and thus not None here we check that this is the final submit request from the
+ # handler and if so, we set pay_subsidies to None
if (
instance.application_origin == ApplicationOrigin.HANDLER
and validated_data["status"] == ApplicationStatus.RECEIVED
@@ -1785,9 +1793,9 @@ def _update_calculation(self, application, calculation_data, previous_status):
ApplicationStatus.is_handler_editable_status(previous_status)
and application.status == ApplicationStatus.ACCEPTED
):
- # When application is accepted, only certain fields that don't change the calculation
- # result can be modified, otherwise the handled would be accepting a benefit amount that they've not
- # seen.
+ # When application is accepted, only certain fields that don't change
+ # the calculation result can be modified, otherwise the handled would be
+ # accepting a benefit amount that they've not seen.
update_object(
application.calculation,
calculation_data,
@@ -1831,9 +1839,9 @@ def _common_ordered_nested_update(self, application, serializer):
)
for idx, nested_object in enumerate(serializer.validated_data):
nested_object["application_id"] = application.pk
- nested_object[
- "ordering"
- ] = idx # use the ordering defined in the JSON sent by the client
+ nested_object["ordering"] = (
+ idx # use the ordering defined in the JSON sent by the client
+ )
serializer.save()
if hasattr(application, "calculation"):
call_now_or_later(
@@ -1854,7 +1862,8 @@ def handle_status_transition(
self._assign_handler_if_needed(instance)
if not instance.handled_by_ahjo_automation and instance.ahjo_case_id is None:
- # If the application has been handled by the Ahjo automation, we don't want to
+ # If the application has been handled by the Ahjo automation, we don't want
+ # to
# remove the batch, as it's needed for the Ahjo automation
self._remove_batch_if_needed(instance)
@@ -1873,7 +1882,8 @@ def _cancel_application(self, instance):
def _assign_handler_if_needed(self, instance):
# Assign current user to the application.calculation.handler
- # NOTE: This handler might be overridden if there is a handler pk included in the request post data
+ # NOTE: This handler might be overridden if there is a handler pk included in
+ # the request post data
handler = get_request_user_from_context(self)
if settings.NEXT_PUBLIC_MOCK_FLAG and isinstance(handler, AnonymousUser):
handler = get_user_model().objects.all().order_by("username").first()
@@ -2091,7 +2101,8 @@ class Meta:
handled_at = serializers.SerializerMethodField(
"get_handled_at",
help_text=(
- "Archival applications do not have a handled_at timestamp, use start_date instead"
+ "Archival applications do not have a handled_at timestamp, use start_date"
+ " instead"
),
)
company = CompanySerializer(read_only=True)
@@ -2099,12 +2110,13 @@ class Meta:
employee = serializers.SerializerMethodField(
"get_employee",
help_text=(
- "Wrap employee data in a dictionary to match the structure of the normal applications"
+ "Wrap employee data in a dictionary to match the structure of the normal"
+ " applications"
),
)
calculation = serializers.SerializerMethodField(
"get_calculation",
- help_text=("Start and end date"),
+ help_text="Start and end date",
)
def get_handled_at(self, obj):
diff --git a/backend/benefit/applications/api/v1/serializers/application_alteration.py b/backend/benefit/applications/api/v1/serializers/application_alteration.py
index f08b1ed637..9e0f43861d 100644
--- a/backend/benefit/applications/api/v1/serializers/application_alteration.py
+++ b/backend/benefit/applications/api/v1/serializers/application_alteration.py
@@ -1,5 +1,5 @@
from datetime import date
-from decimal import Decimal, ROUND_DOWN
+from decimal import ROUND_DOWN, Decimal
from django.conf import settings
from django.core.exceptions import ValidationError
@@ -93,12 +93,15 @@ class Meta:
)
cancelled_by = UserSerializer(
read_only=True,
- help_text="The handler responsible for the cancellation of this alteration, if any",
+ help_text=(
+ "The handler responsible for the cancellation of this alteration, if any"
+ ),
)
def validate_recovery_amount(self, value):
if value is not None:
- # Round down the recovery_amount to the nearest integer while keeping it as Decimal
+ # Round down the recovery_amount to the nearest integer while keeping it as
+ # Decimal
return value.quantize(Decimal("1"), rounding=ROUND_DOWN)
return value
@@ -146,7 +149,8 @@ def _validate_conditional_required_fields(self, is_suspended, data):
ValidationError(
format_lazy(
_(
- "{field} must be filled if using an e-invoice address"
+ "{field} must be filled if using an e-invoice"
+ " address"
),
field=field_label,
)
@@ -163,7 +167,8 @@ def _validate_date_range_within_application_date_range(
errors.append(
ValidationError(
_(
- "The change to employment cannot start before the start date of the benefit period"
+ "The change to employment cannot start before the start date of"
+ " the benefit period"
)
)
)
@@ -171,7 +176,8 @@ def _validate_date_range_within_application_date_range(
errors.append(
ValidationError(
_(
- "The change to employment cannot start after the end date of the benefit period"
+ "The change to employment cannot start after the end date of"
+ " the benefit period"
)
)
)
@@ -180,7 +186,8 @@ def _validate_date_range_within_application_date_range(
errors.append(
ValidationError(
_(
- "The end date of the change period cannot be after the end date of the benefit period"
+ "The end date of the change period cannot be after the end"
+ " date of the benefit period"
)
)
)
@@ -188,7 +195,8 @@ def _validate_date_range_within_application_date_range(
errors.append(
ValidationError(
_(
- "The end date of the change period cannot be before the start date of the same period"
+ "The end date of the change period cannot be before the"
+ " start date of the same period"
)
)
)
@@ -217,7 +225,8 @@ def _validate_date_range_overlaps(self, self_id, application, start_date, end_da
errors.append(
ValidationError(
_(
- "Another change to employment has already been reported for the same period"
+ "Another change to employment has already been reported for the"
+ " same period"
)
)
)
diff --git a/backend/benefit/applications/api/v1/serializers/attachment.py b/backend/benefit/applications/api/v1/serializers/attachment.py
index b866ca8c9d..0d56b3ade9 100644
--- a/backend/benefit/applications/api/v1/serializers/attachment.py
+++ b/backend/benefit/applications/api/v1/serializers/attachment.py
@@ -2,7 +2,8 @@
import filetype
from django.conf import settings
-from django.forms import ImageField, ValidationError as DjangoFormsValidationError
+from django.forms import ImageField
+from django.forms import ValidationError as DjangoFormsValidationError
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
@@ -12,10 +13,10 @@
from applications.enums import ApplicationStatus
from applications.models import Attachment
from applications.services.clamav import (
- clamav_client,
ClamAvServiceUnavailableException,
- FileInfectedException,
- FileScanException,
+ FileInfectedError,
+ FileScanError,
+ clamav_client,
)
from helsinkibenefit.settings import MAX_UPLOAD_SIZE
from users.utils import get_request_user_from_context
@@ -106,7 +107,8 @@ def validate(self, data):
if not self._is_valid_pdf(data["attachment_file"]):
raise serializers.ValidationError(_("Not a valid pdf file"))
elif not self._is_valid_image(data["attachment_file"]):
- # only pdf and image files are listed in ATTACHMENT_CONTENT_TYPE_CHOICES, so if we get here,
+ # only pdf and image files are listed in ATTACHMENT_CONTENT_TYPE_CHOICES, so
+ # if we get here,
# the content type is an image file
raise serializers.ValidationError(_("Not a valid image file"))
return data
@@ -132,15 +134,15 @@ def _is_valid_pdf(self, uploaded_file):
def _scan_with_clamav(self, file):
try:
clamav_client.scan(file.name, file.file)
- except FileScanException as fse:
+ except FileScanError as fse:
log.error(f"File '{fse.file_name}' scanning failed")
raise ClamAvServiceUnavailableException()
- except FileInfectedException as fie:
+ except FileInfectedError as fie:
log.error(f"File '{fie.file_name}' infected, viruses: {fie.viruses}")
translation_text = _("File is infected with")
raise serializers.ValidationError(
{
- "non_field_errors": f'{translation_text} {", ".join(fie.viruses)}',
+ "non_field_errors": f"{translation_text} {', '.join(fie.viruses)}",
"key": "malware",
},
)
diff --git a/backend/benefit/applications/api/v1/serializers/batch.py b/backend/benefit/applications/api/v1/serializers/batch.py
index 711abd7502..3d70a0815f 100755
--- a/backend/benefit/applications/api/v1/serializers/batch.py
+++ b/backend/benefit/applications/api/v1/serializers/batch.py
@@ -155,7 +155,7 @@ def to_representation(self, instance):
class BatchCompanySerializer(ReadOnlySerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- setattr(self.Meta, "read_only_fields", [*self.fields])
+ self.Meta.read_only_fields = [*self.fields]
class Meta:
model = Company
@@ -168,7 +168,7 @@ class Meta:
class BatchEmployeeSerializer(ReadOnlySerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- setattr(self.Meta, "read_only_fields", [*self.fields])
+ self.Meta.read_only_fields = [*self.fields]
class Meta:
model = Employee
diff --git a/backend/benefit/applications/api/v1/serializers/de_minimis.py b/backend/benefit/applications/api/v1/serializers/de_minimis.py
index 4f154562d9..13f8a30802 100755
--- a/backend/benefit/applications/api/v1/serializers/de_minimis.py
+++ b/backend/benefit/applications/api/v1/serializers/de_minimis.py
@@ -12,7 +12,7 @@ class DeMinimisAidSerializer(serializers.ModelSerializer):
The "ordering" field is not editable and is ignored if present in POST/PUT data.
The ordering of the DeMinimisAid objects is determined by their order in the "de_minimis_aid_set" list
in the Application.
- """
+ """ # noqa: E501
MAX_AID_AMOUNT = 300000
amount = serializers.DecimalField(
diff --git a/backend/benefit/applications/api/v1/serializers/utils.py b/backend/benefit/applications/api/v1/serializers/utils.py
index 42c6981855..fda76ee847 100755
--- a/backend/benefit/applications/api/v1/serializers/utils.py
+++ b/backend/benefit/applications/api/v1/serializers/utils.py
@@ -6,7 +6,7 @@ class DynamicFieldsModelSerializer(serializers.ModelSerializer):
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed and exclude_fields parameter argument that controls
which fields should not be displayed.
- """
+ """ # noqa: E501
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -23,4 +23,4 @@ def __init__(self, *args, **kwargs):
class ReadOnlySerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- setattr(self.Meta, "read_only_fields", [*self.fields])
+ self.Meta.read_only_fields = [*self.fields]
diff --git a/backend/benefit/applications/api/v1/status_transition_validator.py b/backend/benefit/applications/api/v1/status_transition_validator.py
index 426a637204..95d088250e 100644
--- a/backend/benefit/applications/api/v1/status_transition_validator.py
+++ b/backend/benefit/applications/api/v1/status_transition_validator.py
@@ -17,7 +17,8 @@ def get_current_status(self, serializer_field):
def __call__(self, value, serializer_field):
if status := self.get_current_status(serializer_field):
- # In case it's an update operation, validate with the current status in database
+ # In case it's an update operation, validate with the current status in
+ # database
if value != status and value not in self.STATUS_TRANSITIONS[status]:
raise serializers.ValidationError(
format_lazy(
diff --git a/backend/benefit/applications/api/v1/talpa_integration_views.py b/backend/benefit/applications/api/v1/talpa_integration_views.py
index 3a5071f7be..feee3bd4f2 100644
--- a/backend/benefit/applications/api/v1/talpa_integration_views.py
+++ b/backend/benefit/applications/api/v1/talpa_integration_views.py
@@ -62,7 +62,8 @@ def _get_applications(self, application_numbers) -> Union[List[Application], Non
)
if not applications.exists() and application_numbers:
LOGGER.error(
- f"No applications found with numbers: {application_numbers} for update after TALPA download"
+ f"No applications found with numbers: {application_numbers} for update"
+ " after TALPA download"
)
return None
return applications
@@ -76,7 +77,8 @@ def _get_applications_and_instalments(
if not applications.exists() and application_numbers:
LOGGER.error(
- f"No applications found with numbers: {application_numbers} for update after TALPA download"
+ f"No applications found with numbers: {application_numbers} for update"
+ " after TALPA download"
)
return []
return applications
@@ -109,7 +111,7 @@ def _handle_successful_applications(
@transaction.atomic
def _handle_failed_applications(self, application_numbers: list, ip_address: str):
- """Update applications and related batch which could not be processed with status REJECTED_BY_TALPA"""
+ """Update applications and related batch which could not be processed with status REJECTED_BY_TALPA""" # noqa: E501
if settings.PAYMENT_INSTALMENTS_ENABLED:
applications = self._get_applications_and_instalments(application_numbers)
@@ -118,7 +120,9 @@ def _handle_failed_applications(self, application_numbers: list, ip_address: str
applications=applications,
instalment_status=InstalmentStatus.ERROR_IN_TALPA,
ip_address=ip_address,
- log_message="there was an error and the instalment was not read by TALPA",
+ log_message=(
+ "there was an error and the instalment was not read by TALPA"
+ ),
is_success=False,
)
else:
@@ -143,7 +147,7 @@ def update_application_and_related_batch(
):
"""Update applications and related batch with given statuses and log the event.
This will be deprecated after the instalments feature is enabled for all applications.
- """
+ """ # noqa: E501
for application in applications:
application.talpa_status = application_talpa_status
application.archived = is_archived
@@ -169,7 +173,7 @@ def do_status_updates_based_on_instalments(
If the instalments 1/1 or 2/2, e.g the final instalment,
update the application status, batch status to SENT_TO_TALPA.
Always set the application as archived after the first instalment is succesfully sent to talpa.
- """
+ """ # noqa: E501
for application in applications:
try:
instalment = application.calculation.instalments.get(
@@ -182,12 +186,13 @@ def do_status_updates_based_on_instalments(
instalment.save()
except ObjectDoesNotExist:
LOGGER.error(
- f"Valid payable Instalment not found for application {application.application_number}"
+ "Valid payable Instalment not found for application"
+ f" {application.application_number}"
)
except MultipleObjectsReturned:
LOGGER.error(
- f"Multiple payable Instalments found for application \
-{application.application_number}, there should be only one"
+ "Multiple payable Instalments found for application"
+ f" {application.application_number}, there should be only one"
)
if is_success:
@@ -199,8 +204,11 @@ def do_status_updates_based_on_instalments(
ip_address=ip_address,
application_talpa_status=ApplicationTalpaStatus.PARTIALLY_SENT_TO_TALPA,
batch_status=ApplicationBatchStatus.PARTIALLY_SENT_TO_TALPA,
- log_message=f"instalment {instalment.instalment_number}/{application.number_of_instalments} \
-was read by TALPA and marked as paid",
+ log_message=(
+ "instalment"
+ f" {instalment.instalment_number}/{application.number_of_instalments}" # noqa: E501
+ " was read by TALPA and marked as paid"
+ ),
is_archived=True,
)
diff --git a/backend/benefit/applications/benefit_aggregation.py b/backend/benefit/applications/benefit_aggregation.py
index 3a429689f0..a52341566a 100644
--- a/backend/benefit/applications/benefit_aggregation.py
+++ b/backend/benefit/applications/benefit_aggregation.py
@@ -17,9 +17,9 @@
@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_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
@@ -36,10 +36,10 @@ def get_former_benefit_info(
apprenticeship_program,
):
# the application field values are separate parameters, because validation is done
- # before assigning values, and if a new Application is being created, an Application doesn't yet exist when
- # the rest framework does the validation.
- # The Application parameter is only used to ensure that the application being validated isn't validated
- # against itself.
+ # before assigning values, and if a new Application is being created, an Application
+ # doesn't yet exist when the rest framework does the validation.
+ # The Application parameter is only used to ensure that the application being
+ # validated isn't validated against itself.
former_benefit_info = FormerBenefitInfo()
@@ -60,7 +60,8 @@ def get_former_benefit_info(
benefit.duration_in_months for benefit in recent_benefits
)
if apprenticeship_program:
- # Kanslia Helsinki-lisä Teams discussion 2021-12-09: there's no upper limit defined for
+ # Kanslia Helsinki-lisä Teams discussion 2021-12-09: there's no upper limit
+ # defined for
# sequentially granted apprenticeship benefits
former_benefit_info.months_remaining = None
else:
@@ -129,7 +130,7 @@ def _get_benefits_relevant_for_validation(past_benefits, start_date):
:return: A new list, containing only those entries that are relevant for validating a new application
starting on start_date.
- """
+ """ # noqa: E501
if not past_benefits:
return []
most_recent_benefit = past_benefits[0]
@@ -137,15 +138,15 @@ def _get_benefits_relevant_for_validation(past_benefits, start_date):
most_recent_benefit.end_date
< start_date - relativedelta(months=BENEFIT_WAITING_PERIOD_MONTHS)
):
- # at least BENEFIT_WAITING_PERIOD_MONTHS elapsed since a Helsinki benefit was granted
- # for this employee last time.
+ # at least BENEFIT_WAITING_PERIOD_MONTHS elapsed since a Helsinki benefit was
+ # granted for this employee last time.
return []
# scroll back previous benefits until we find a gap of BENEFIT_WAITING_PERIOD_MONTHS
applicable_benefits = [most_recent_benefit]
for old_benefit, older_benefit in pairwise(past_benefits):
- # on the first round of loop, old_benefit == most_recent_benefit, which already is in
- # applicable_benefits
+ # on the first round of loop, old_benefit == most_recent_benefit, which already
+ # is in applicable_benefits
if (
older_benefit.end_date + relativedelta(months=BENEFIT_WAITING_PERIOD_MONTHS)
< old_benefit.start_date
@@ -164,7 +165,8 @@ def _get_benefit_overlap_warnings(past_benefits, start_date, end_date):
warnings.append(
format_lazy(
_(
- "There's already an accepted application with overlapping date range"
+ "There's already an accepted application with overlapping date"
+ " range"
),
start_date=benefit.start_date,
end_date=benefit.end_date,
diff --git a/backend/benefit/applications/enums.py b/backend/benefit/applications/enums.py
index fd30d5d34e..29acceb2b8 100644
--- a/backend/benefit/applications/enums.py
+++ b/backend/benefit/applications/enums.py
@@ -10,8 +10,9 @@ class ApplicationStatus(models.TextChoices):
DRAFT = "draft", _("Draft")
RECEIVED = "received", _("Received")
HANDLING = "handling", _("Handling")
- ADDITIONAL_INFORMATION_NEEDED = "additional_information_needed", _(
- "Additional information requested"
+ ADDITIONAL_INFORMATION_NEEDED = (
+ "additional_information_needed",
+ _("Additional information requested"),
)
CANCELLED = "cancelled", _("Cancelled")
ACCEPTED = "accepted", _("Accepted")
@@ -38,15 +39,17 @@ def is_handler_editable_status(cls, status, new_status=None):
if new_status is not None and new_status not in cls.values:
raise ValueError(_("Invalid application status change"))
- # Application can be transitioned back from these non-editable statuses, so make an exception
- # to make the application editable if status transition is done at the same time
+ # Application can be transitioned back from these non-editable statuses, so make
+ # an exception to make the application editable if status transition is done at
+ # the same time
if (status, new_status) in [
(ApplicationStatus.ACCEPTED, ApplicationStatus.HANDLING),
(ApplicationStatus.REJECTED, ApplicationStatus.HANDLING),
]:
return True
- # drafts may be edited by the handler when entering data from a paper application
+ # drafts may be edited by the handler when entering data from a paper
+ # application
return status in (
cls.DRAFT,
cls.RECEIVED,
@@ -97,8 +100,9 @@ class AttachmentType(models.TextChoices):
EMPLOYMENT_CONTRACT = "employment_contract", _("employment contract")
PAY_SUBSIDY_DECISION = "pay_subsidy_decision", _("pay subsidy decision")
COMMISSION_CONTRACT = "commission_contract", _("commission contract")
- EDUCATION_CONTRACT = "education_contract", _(
- "education contract of the apprenticeship office"
+ EDUCATION_CONTRACT = (
+ "education_contract",
+ _("education contract of the apprenticeship office"),
)
HELSINKI_BENEFIT_VOUCHER = "helsinki_benefit_voucher", _("helsinki benefit voucher")
EMPLOYEE_CONSENT = "employee_consent", _("employee consent")
@@ -106,8 +110,9 @@ class AttachmentType(models.TextChoices):
OTHER_ATTACHMENT = "other_attachment", _("other attachment")
PDF_SUMMARY = "pdf_summary", _("pdf summary")
DECISION_TEXT_XML = "decision_text_xml", _("public decision text xml attachment")
- DECISION_TEXT_SECRET_XML = "decision_text_secret_xml", _(
- "non-public decision text xml attachment"
+ DECISION_TEXT_SECRET_XML = (
+ "decision_text_secret_xml",
+ _("non-public decision text xml attachment"),
)
@@ -118,20 +123,24 @@ class AttachmentRequirement(models.TextChoices):
class ApplicationBatchStatus(models.TextChoices):
DRAFT = "draft", _("Draft")
- AHJO_REPORT_CREATED = "exported_ahjo_report", _(
- "Ahjo report created, not yet sent to AHJO"
+ AHJO_REPORT_CREATED = (
+ "exported_ahjo_report",
+ _("Ahjo report created, not yet sent to AHJO"),
)
- AWAITING_AHJO_DECISION = "awaiting_ahjo_decision", _(
- "Sent to Ahjo, decision pending"
+ AWAITING_AHJO_DECISION = (
+ "awaiting_ahjo_decision",
+ _("Sent to Ahjo, decision pending"),
)
DECIDED_ACCEPTED = "accepted", _("Accepted in Ahjo")
DECIDED_REJECTED = "rejected", _("Rejected in Ahjo")
- RETURNED = "returned", _(
- "Returned from Ahjo without decision"
+ RETURNED = (
+ "returned",
+ _("Returned from Ahjo without decision"),
) # Theoretically possible: means that a decision was not made
SENT_TO_TALPA = "sent_to_talpa", _("Sent to Talpa")
- PARTIALLY_SENT_TO_TALPA = "partially_sent_to_talpa", _(
- "One of two instalments sent to Talpa"
+ PARTIALLY_SENT_TO_TALPA = (
+ "partially_sent_to_talpa",
+ _("One of two instalments sent to Talpa"),
)
COMPLETED = "completed", _("Processing is completed")
REJECTED_BY_TALPA = "rejected_by_talpa", _("Rejected by Talpa")
@@ -141,11 +150,13 @@ class ApplicationBatchStatus(models.TextChoices):
class ApplicationTalpaStatus(models.TextChoices):
NOT_PROCESSED_BY_TALPA = "not_sent_to_talpa", _("Not sent to Talpa")
REJECTED_BY_TALPA = "rejected_by_talpa", _("Rejected by Talpa")
- PARTIALLY_SENT_TO_TALPA = "partially_sent_to_talpa", _(
- "One of two instalments sent to Talpa"
+ PARTIALLY_SENT_TO_TALPA = (
+ "partially_sent_to_talpa",
+ _("One of two instalments sent to Talpa"),
)
- SUCCESSFULLY_SENT_TO_TALPA = "successfully_sent_to_talpa", _(
- "Successfully sent to Talpa"
+ SUCCESSFULLY_SENT_TO_TALPA = (
+ "successfully_sent_to_talpa",
+ _("Successfully sent to Talpa"),
)
@@ -168,21 +179,25 @@ class PaySubsidyGranted(models.TextChoices):
class AhjoStatus(models.TextChoices):
# The possible statuses for Ahjo processing
- SUBMITTED_BUT_NOT_SENT_TO_AHJO = "submitted_but_not_sent_to_ahjo", _(
- "Submitted but not sent to AHJO"
+ SUBMITTED_BUT_NOT_SENT_TO_AHJO = (
+ "submitted_but_not_sent_to_ahjo",
+ _("Submitted but not sent to AHJO"),
)
- REQUEST_TO_OPEN_CASE_SENT = "request_to_open_case_sent", _(
- "Request to open the case sent to AHJO"
+ REQUEST_TO_OPEN_CASE_SENT = (
+ "request_to_open_case_sent",
+ _("Request to open the case sent to AHJO"),
)
CASE_OPENED = "case_opened", _("Case opened in AHJO")
UPDATE_REQUEST_SENT = "update_request_sent", _("Update request sent")
UPDATE_REQUEST_RECEIVED = "update_request_received", _("Update request received")
DECISION_PROPOSAL_SENT = "decision_proposal_sent", _("Decision proposal sent")
- DECISION_PROPOSAL_ACCEPTED = "decision_proposal_accepted", _(
- "Decision proposal accepted"
+ DECISION_PROPOSAL_ACCEPTED = (
+ "decision_proposal_accepted",
+ _("Decision proposal accepted"),
)
- DECISION_PROPOSAL_REJECTED = "decision_proposal_rejected", _(
- "Decision proposal rejected"
+ DECISION_PROPOSAL_REJECTED = (
+ "decision_proposal_rejected",
+ _("Decision proposal rejected"),
)
SCHEDULED_FOR_DELETION = "scheduled_for_deletion", _("Scheduled for deletion")
DELETE_REQUEST_SENT = "delete_request_sent", _("Delete request sent")
@@ -192,17 +207,20 @@ class AhjoStatus(models.TextChoices):
REMOVED_IN_AHJO = "removed", _("Decision cancelled in Ahjo")
SIGNED_IN_AHJO = "signed", _("Decision signed and completed in Ahjo")
UPDATED_IN_AHJO = "updated", _("Decision updated in Ahjo")
- DECISION_DETAILS_REQUEST_SENT = "decision_details_request_sent", _(
- "Decision details request sent"
+ DECISION_DETAILS_REQUEST_SENT = (
+ "decision_details_request_sent",
+ _("Decision details request sent"),
)
- DETAILS_RECEIVED_FROM_AHJO = "details_received", _(
- "Decision details received from Ahjo"
+ DETAILS_RECEIVED_FROM_AHJO = (
+ "details_received",
+ _("Decision details received from Ahjo"),
)
class ApplicationActions(models.TextChoices):
- HANDLER_ALLOW_APPLICATION_EDIT = "HANDLER_ALLOW_APPLICATION_EDIT", _(
- "Allow/disallow applicant's modifications to the application"
+ HANDLER_ALLOW_APPLICATION_EDIT = (
+ "HANDLER_ALLOW_APPLICATION_EDIT",
+ _("Allow/disallow applicant's modifications to the application"),
)
@@ -219,8 +237,9 @@ class AhjoRequestType(models.TextChoices):
SEND_DECISION_PROPOSAL = "send_decision", _("Send decision to Ahjo")
GET_DECISION_DETAILS = "get_decision_details", _("Get decision details from Ahjo")
SUBSCRIBE_TO_DECISIONS = "subscribe_to_decisions", _("Subscribe to decisions API")
- GET_DECISION_MAKER = "get_decision_maker", _(
- "Get decision maker name from Ahjo API"
+ GET_DECISION_MAKER = (
+ "get_decision_maker",
+ _("Get decision maker name from Ahjo API"),
)
GET_SIGNER = "get_signer", _("Get signer name a and AD id from Ahjo API")
@@ -298,11 +317,15 @@ def __post_init__(self):
{
"id": "NO_ID",
"context": "Received an error but no failure details in the callback.",
- "message": "Ahjo-pyynnössä tapahtui virhe, mutta Ahjo ei palauttanut tarkempia tietoja.",
+ "message": (
+ "Ahjo-pyynnössä tapahtui virhe, mutta Ahjo ei palauttanut tarkempia"
+ " tietoja."
+ ),
}
]
-# Call gettext on some of the enums so that "makemessages" command can find them when used dynamically in templates
+# Call gettext on some of the enums so that "makemessages" command can find them when
+# used dynamically in templates
_("granted")
_("granted_aged")
_("not_granted")
diff --git a/backend/benefit/applications/exceptions.py b/backend/benefit/applications/exceptions.py
index 16a9b902db..0b87c76702 100644
--- a/backend/benefit/applications/exceptions.py
+++ b/backend/benefit/applications/exceptions.py
@@ -3,8 +3,6 @@ class BatchCompletionDecisionDateError(Exception):
Used when decision date is not in validation's range
"""
- pass
-
class BatchCompletionRequiredFieldsError(Exception):
"""
@@ -12,13 +10,9 @@ class BatchCompletionRequiredFieldsError(Exception):
when trying to complete a batch
"""
- pass
-
class BatchTooManyDraftsError(Exception):
"""
Raised when there is too many drafts with the same value
of proposal_for_decision
"""
-
- pass
diff --git a/backend/benefit/applications/jobs/hourly/hourly_ahjo_job.py b/backend/benefit/applications/jobs/hourly/hourly_ahjo_job.py
index 474f783fcd..2c60f4bb1e 100644
--- a/backend/benefit/applications/jobs/hourly/hourly_ahjo_job.py
+++ b/backend/benefit/applications/jobs/hourly/hourly_ahjo_job.py
@@ -7,7 +7,7 @@
"""
A hourly job to refresh the Ahjo access token via the refresh token saved in the Django database.
If the Ahjo automation is enabled, the job will also send requests to Ahjo to get decision details.
-"""
+""" # noqa: E501
class Job(HourlyJob):
diff --git a/backend/benefit/applications/management/commands/ahjo_base_command.py b/backend/benefit/applications/management/commands/ahjo_base_command.py
index b07d8763c8..eaa4effa91 100644
--- a/backend/benefit/applications/management/commands/ahjo_base_command.py
+++ b/backend/benefit/applications/management/commands/ahjo_base_command.py
@@ -5,7 +5,7 @@
from django.utils import timezone
from applications.services.ahjo.request_handler import AhjoRequestHandler
-from applications.services.ahjo_authentication import AhjoTokenExpiredException
+from applications.services.ahjo_authentication import AhjoTokenExpiredError
from applications.services.ahjo_integration import get_token
LOGGER = logging.getLogger(__name__)
@@ -21,7 +21,7 @@ def get_token(self):
except ImproperlyConfigured as e:
LOGGER.error(f"Failed to get auth token for Ahjo: {e}")
return None
- except AhjoTokenExpiredException as e:
+ except AhjoTokenExpiredError as e:
LOGGER.error(f"Ahjo Token expired: {e}")
return None
@@ -43,7 +43,8 @@ def handle(self, *args, **options):
except ValueError as e:
self.style.ERROR(
self.stdout.write(
- f"{timezone.now()}: Failed to make request {self.request_type.value} to Ahjo: {e}"
+ f"{timezone.now()}: Failed to make request"
+ f" {self.request_type.value} to Ahjo: {e}"
)
)
return
diff --git a/backend/benefit/applications/management/commands/check_and_notify_ending_benefits.py b/backend/benefit/applications/management/commands/check_and_notify_ending_benefits.py
index 4a9552eda5..6cc1130a8e 100644
--- a/backend/benefit/applications/management/commands/check_and_notify_ending_benefits.py
+++ b/backend/benefit/applications/management/commands/check_and_notify_ending_benefits.py
@@ -13,32 +13,40 @@
)
BENEFIT_PERIOD_IS_ABOUT_TO_END_MESSAGE = _(
- "Your application's {application_number} benefit period will end soon, at {benefit_end_date}."
+ "Your application's {application_number} benefit period will end soon, at"
+ " {benefit_end_date}."
)
class Command(BaseCommand):
- help = "Query applications that are close to the end of the benefit period and send a notification to the applicant"
+ help = (
+ "Query applications that are close to the end of the benefit period and send a"
+ " notification to the applicant"
+ )
def add_arguments(self, parser):
parser.add_argument(
"--notify",
type=int,
default=30,
- help="The number of days before benefit end date and when to notify the applicant",
+ help=(
+ "The number of days before benefit end date and when to notify the"
+ " applicant"
+ ),
)
def handle(self, *args, **options):
number_of_notified_applications = notify_applications(options["notify"])
self.stdout.write(
- f"Notified users of {number_of_notified_applications} applications about ending benefit period"
+ f"Notified users of {number_of_notified_applications} applications about"
+ " ending benefit period"
)
def notify_applications(days_to_period_end: int) -> int:
"""Query applications that are close to the benefit end date and not have any alterations.
Send a notification to the applicant.
- Returns the number of notified applications."""
+ Returns the number of notified applications.""" # noqa: E501
target_date = timezone.now() + timedelta(days=days_to_period_end)
applications_to_notify = Application.objects.filter(
@@ -59,7 +67,7 @@ def get_benefit_notice_email_notification_subject():
def _send_notification_mail(application: Application, target_date: date) -> int:
- """Send a notification mail to the applicant about the upcoming end of the benefit period"""
+ """Send a notification mail to the applicant about the upcoming end of the benefit period""" # noqa: E501
context = get_email_template_context(application)
context["upcoming_benefit_end_date"] = target_date.strftime("%d.%m.%Y")
diff --git a/backend/benefit/applications/management/commands/check_drafts_to_delete.py b/backend/benefit/applications/management/commands/check_drafts_to_delete.py
index 4564e8f1ac..ed9c64bf7f 100644
--- a/backend/benefit/applications/management/commands/check_drafts_to_delete.py
+++ b/backend/benefit/applications/management/commands/check_drafts_to_delete.py
@@ -13,20 +13,27 @@
)
APPLICATION_ABOUT_TO_BE_DELETED_MESSAGE = _(
- "Your application {id} will be deleted soon. If you want to continue the application process, please do so by "
- "{application_deletion_date}, otherwise the application will deleted permanently."
+ "Your application {id} will be deleted soon. If you want to continue the"
+ " application process, please do so by {application_deletion_date}, otherwise the"
+ " application will deleted permanently."
)
class Command(BaseCommand):
- help = "Query draft applications that are close to the deletion date and send a notification to the applicant"
+ help = (
+ "Query draft applications that are close to the deletion date and send a"
+ " notification to the applicant"
+ )
def add_arguments(self, parser):
parser.add_argument(
"--notify",
type=int,
default=14,
- help="The number of days before the deletion date and when to notify the applicant",
+ help=(
+ "The number of days before the deletion date and when to notify the"
+ " applicant"
+ ),
)
parser.add_argument(
@@ -41,13 +48,14 @@ def handle(self, *args, **options):
options["notify"], options["keep"]
)
self.stdout.write(
- f"Notified users of {number_of_notified_applications} applications about upcoming application deletion"
+ f"Notified users of {number_of_notified_applications} applications about"
+ " upcoming application deletion"
)
def notify_applications(days_to_deletion: int, days_to_keep: int) -> int:
"""Query applications that are close to the deletion date and send a notification to the applicant.
- Returns the number of notified applications."""
+ Returns the number of notified applications.""" # noqa: E501
draft_scope_in_days = days_to_keep - days_to_deletion
applications_to_notify = Application.objects.filter(
@@ -68,7 +76,7 @@ def get_draft_notice_email_notification_subject():
def _send_notification_mail(application: Application, days_to_keep: int) -> int:
- """Send a notification mail to the applicant about the upcoming application deletion"""
+ """Send a notification mail to the applicant about the upcoming application deletion""" # noqa: E501
application_deletion_date = (
application.modified_at + timedelta(days=(days_to_keep))
).strftime("%d.%m.%Y")
diff --git a/backend/benefit/applications/management/commands/create-proposal-drafts.py b/backend/benefit/applications/management/commands/create_proposal_drafts.py
similarity index 91%
rename from backend/benefit/applications/management/commands/create-proposal-drafts.py
rename to backend/benefit/applications/management/commands/create_proposal_drafts.py
index 06bee9202f..e1e67f0846 100755
--- a/backend/benefit/applications/management/commands/create-proposal-drafts.py
+++ b/backend/benefit/applications/management/commands/create_proposal_drafts.py
@@ -11,7 +11,7 @@ def handle(self, *args, **options):
total_created = 0
for application in applications:
try:
- application.decision_proposal_draft
+ application.decision_proposal_draft # noqa
except: # noqa
AhjoDecisionProposalDraft.objects.create(
application=application,
diff --git a/backend/benefit/applications/management/commands/delete_applications.py b/backend/benefit/applications/management/commands/delete_applications.py
index cae53804d2..f61b70ff2e 100644
--- a/backend/benefit/applications/management/commands/delete_applications.py
+++ b/backend/benefit/applications/management/commands/delete_applications.py
@@ -9,7 +9,10 @@
class Command(BaseCommand):
- help = "Delete applications with the given status (draft or cancelled) and older than the given number of days"
+ help = (
+ "Delete applications with the given status (draft or cancelled) and older than"
+ " the given number of days"
+ )
allowed_statuses = [
ApplicationStatus.DRAFT,
ApplicationStatus.CANCELLED,
@@ -30,8 +33,10 @@ def add_arguments(self, parser) -> None:
"--status",
type=str,
nargs="+", # Allow multiple statuses
- help="The statuses of the applications to delete. \
-pass multiple statuses separated by spaces.",
+ help=(
+ "The statuses of the applications to delete. pass multiple statuses"
+ " separated by spaces."
+ ),
)
def handle(self, *args, **options) -> None:
@@ -43,20 +48,21 @@ def handle(self, *args, **options) -> None:
]
if invalid_statuses:
self.stderr.write(
- f"Invalid statuses provided: {', '.join(invalid_statuses)}. \
-Allowed statuses are: {', '.join(self.allowed_statuses)}."
+ f"Invalid statuses provided: {', '.join(invalid_statuses)}. Allowed"
+ f" statuses are: {', '.join(self.allowed_statuses)}."
)
return
number_of_deleted_applications = _delete_applications(keep_days, statuses)
self.stdout.write(
- f"Deleted {number_of_deleted_applications} applications with status {options['status']}"
+ f"Deleted {number_of_deleted_applications} applications with status"
+ f" {options['status']}"
)
def _delete_applications(days_to_keep: int, statuses: List[str]) -> int:
"""Delete applications with the given status and older than the given number of days.
- Also delete their attachment files."""
+ Also delete their attachment files.""" # noqa: E501
applications_to_delete = Application.objects.filter(
status__in=statuses,
diff --git a/backend/benefit/applications/management/commands/import_archival_applications.py b/backend/benefit/applications/management/commands/import_archival_applications.py
index 5e46ad6bc3..ade6a81cfb 100644
--- a/backend/benefit/applications/management/commands/import_archival_applications.py
+++ b/backend/benefit/applications/management/commands/import_archival_applications.py
@@ -61,8 +61,10 @@ def add_arguments(self, parser):
"--filename",
type=str,
default="test.xlsx",
- help="Filename for Excel spreadsheet to import,"
- "store spreadsheet under backend/benefit/applications/resources",
+ help=(
+ "Filename for Excel spreadsheet to import,"
+ "store spreadsheet under backend/benefit/applications/resources"
+ ),
)
parser.add_argument(
@@ -76,7 +78,10 @@ def add_arguments(self, parser):
"--production",
type=bool,
default=None,
- help="Set to True to actually import the data, otherwise will only do a dry run",
+ help=(
+ "Set to True to actually import the data, otherwise will only do a"
+ " dry run"
+ ),
)
def handle(self, filename, production, sheet_name, *args, **options): # noqa
@@ -90,7 +95,7 @@ def isna(value):
else:
from pandas import isna, read_excel
- EXPECTED_SPREADSHEET_COLUMNS = {
+ expected_spreadsheet_columns = {
"company_name": "hakija",
"application_number": "Hakemusnro",
"business_id": "y-tunnus",
@@ -102,7 +107,7 @@ def isna(value):
"year_of_birth": "synt. vuosi",
}
- OPTIONAL_SPREADSHEET_COLUMNS = {"handled_at": "Päätöspäivä"}
+ optional_spreadsheet_columns = {"handled_at": "Päätöspäivä"}
# mock data if it's a pytest run
if is_pytest:
@@ -120,27 +125,27 @@ def isna(value):
columns = [x.strip(" ") for x in columns]
if not production:
- print(
+ print( # noqa: T201
"\n ###################\n",
"##### DRY RUN #####\n",
"###################\n",
)
else:
- print(
+ print( # noqa: T201
"\n ######################\n",
"##### PRODUCTION #####\n",
"######################\n",
)
- print(f"Verifying data from {filename}")
- print(
+ print(f"Verifying data from {filename}") # noqa: T201
+ print( # noqa: T201
f"• Found {len(spreadsheet_data)} rows of data with {len(columns)} columns"
)
column_index = []
- for technical_key, spreadsheet_key in EXPECTED_SPREADSHEET_COLUMNS.items():
+ for technical_key, spreadsheet_key in expected_spreadsheet_columns.items():
if spreadsheet_key not in columns:
- print(f'! Column "{spreadsheet_key}" not found in spreadsheet keys')
+ print(f'! Column "{spreadsheet_key}" not found in spreadsheet keys') # noqa: T201
raise CommandError("Excel is not in expected format")
column_index.append(
{
@@ -149,9 +154,9 @@ def isna(value):
"key": technical_key,
}
)
- print("• Spreadsheet's column headers are as expected")
+ print("• Spreadsheet's column headers are as expected") # noqa: T201
- for technical_key, spreadsheet_key in OPTIONAL_SPREADSHEET_COLUMNS.items():
+ for technical_key, spreadsheet_key in optional_spreadsheet_columns.items():
if spreadsheet_key in columns:
column_index.append(
{
@@ -174,15 +179,15 @@ def isna(value):
mapped_rows.append(mapped_row)
- print(f"• Collected {len(mapped_rows)} rows to import")
+ print(f"• Collected {len(mapped_rows)} rows to import") # noqa: T201
- print("\nNow importing rows ...")
+ print("\nNow importing rows ...") # noqa: T201
rows_imported = 0
rows_skipped = 0
for row in mapped_rows:
application_number = row.get("application_number")
- print(
+ print( # noqa: T201
f"\n{application_number}",
)
@@ -192,7 +197,7 @@ def isna(value):
if not is_pytest and not all(validate_data(row)):
rows_skipped += 1
- print(
+ print( # noqa: T201
f"! Skipping: invalid data for {application_number} / {company_str}"
)
continue
@@ -207,35 +212,37 @@ def isna(value):
company = get_or_create_organisation_with_business_id(
row["business_id"]
)
- print(f"• Found: company {company_str}")
+ print(f"• Found: company {company_str}") # noqa: T201
else:
- print(f"+ Created: company {company_str}")
+ print(f"+ Created: company {company_str}") # noqa: T201
except Exception:
company_found = False
- print(f"! Skipping: {company_str} not found")
+ print(f"! Skipping: {company_str} not found") # noqa: T201
continue
if company_found:
- # Remove all conflicting archival applications with the same application number
+ # Remove all conflicting archival applications with the same application
+ # number
existing_apps = ArchivalApplication.objects.filter(
application_number=application_number
)
if existing_apps and production:
for app in existing_apps:
- print("- Removing: imported previously")
+ print("- Removing: imported previously") # noqa: T201
app.delete()
row.pop("company_name")
row.pop("business_id")
app = ArchivalApplication(**row, company=company)
if production:
- print("+ Created: application imported!")
+ print("+ Created: application imported!") # noqa: T201
app.save()
rows_imported += 1
else:
- print(f"• Skipping: {app.application_number}")
+ print(f"• Skipping: {app.application_number}") # noqa: T201
- print(
- f"\nDone! Imported {rows_imported} rows as ArchivalApplication.\nSkipped {rows_skipped} rows.\n"
+ print( # noqa: T201
+ f"\nDone! Imported {rows_imported} rows as ArchivalApplication.\nSkipped"
+ f" {rows_skipped} rows.\n"
)
diff --git a/backend/benefit/applications/management/commands/refresh_ahjo_token.py b/backend/benefit/applications/management/commands/refresh_ahjo_token.py
index 4fe824011b..981b60d620 100644
--- a/backend/benefit/applications/management/commands/refresh_ahjo_token.py
+++ b/backend/benefit/applications/management/commands/refresh_ahjo_token.py
@@ -3,7 +3,7 @@
from applications.services.ahjo_authentication import (
AhjoConnector,
- AhjoTokenRetrievalException,
+ AhjoTokenRetrievalError,
)
@@ -20,4 +20,4 @@ def handle(self, *args, **options):
token = ahjo_connector.refresh_token()
self.stdout.write(f"Ahjo token refreshed, new access token: {token}")
except Exception as e:
- raise AhjoTokenRetrievalException(f"Failed to refresh Ahjo token: {e}")
+ raise AhjoTokenRetrievalError(f"Failed to refresh Ahjo token: {e}")
diff --git a/backend/benefit/applications/management/commands/seed.py b/backend/benefit/applications/management/commands/seed.py
index c46dc8c162..ceaf3ac8f5 100755
--- a/backend/benefit/applications/management/commands/seed.py
+++ b/backend/benefit/applications/management/commands/seed.py
@@ -9,6 +9,8 @@
from applications.enums import (
AhjoStatus as AhjoStatusEnum,
+)
+from applications.enums import (
ApplicationAlterationType,
ApplicationBatchStatus,
ApplicationOrigin,
@@ -93,7 +95,7 @@ def clear_applications():
def run_seed(number):
"""Delete all existing applications and create applications for all statuses,
with cancelled applications being modified 30 days ago and drafts being modified 180 and 166 days ago
- """
+ """ # noqa: E501
def _create_batch(
status: ApplicationBatchStatus, proposal_for_decision: ApplicationStatus
@@ -102,7 +104,8 @@ def _create_batch(
status=status, proposal_for_decision=proposal_for_decision
)
- # Need to delete a few applications that are made for the batch for testing purposes
+ # Need to delete a few applications that are made for the batch for testing
+ # purposes
Application.objects.filter(batch=batch).delete()
apps = []
@@ -220,8 +223,8 @@ def _past_datetime(days: int) -> datetime:
def _create_templates():
- AcceptedDecisionProposalFactory(),
- DeniedDecisionProposalFactory(),
+ (AcceptedDecisionProposalFactory(),)
+ (DeniedDecisionProposalFactory(),)
def _create_dummy_ahjo_user_and_token():
diff --git a/backend/benefit/applications/management/commands/send_ahjo_requests.py b/backend/benefit/applications/management/commands/send_ahjo_requests.py
index c677118a8d..ab17e69802 100644
--- a/backend/benefit/applications/management/commands/send_ahjo_requests.py
+++ b/backend/benefit/applications/management/commands/send_ahjo_requests.py
@@ -16,7 +16,7 @@
from applications.services.ahjo_application_service import AhjoApplicationsService
from applications.services.ahjo_authentication import (
AhjoToken,
- AhjoTokenExpiredException,
+ AhjoTokenExpiredError,
)
from applications.services.ahjo_error_writer import AhjoErrorWriter, AhjoFormattedError
from applications.services.ahjo_integration import (
@@ -33,10 +33,12 @@
class Command(BaseCommand):
- help = f"Send the specified requests to Ahjo Rest API. Possible request types are: \
-{AhjoRequestType.OPEN_CASE}, {AhjoRequestType.SEND_DECISION_PROPOSAL}, \
-{AhjoRequestType.ADD_RECORDS}, {AhjoRequestType.UPDATE_APPLICATION}, \
-{AhjoRequestType.GET_DECISION_DETAILS}, {AhjoRequestType.DELETE_APPLICATION}"
+ help = (
+ "Send the specified requests to Ahjo Rest API. Possible request types are:"
+ f" {AhjoRequestType.OPEN_CASE}, {AhjoRequestType.SEND_DECISION_PROPOSAL},"
+ f" {AhjoRequestType.ADD_RECORDS}, {AhjoRequestType.UPDATE_APPLICATION},"
+ f" {AhjoRequestType.GET_DECISION_DETAILS}, {AhjoRequestType.DELETE_APPLICATION}"
+ )
is_retry = False
def add_arguments(self, parser):
@@ -63,8 +65,10 @@ def add_arguments(self, parser):
"--retry-failed-older-than",
type=int,
default=0,
- help="Retry sending requests for applications that have \
-not moved to the next status in the last x hours",
+ help=(
+ "Retry sending requests for applications that have not moved to the"
+ " next status in the last x hours"
+ ),
)
def get_application_numbers(self, applications: QuerySet[Application]) -> str:
@@ -73,7 +77,7 @@ def get_application_numbers(self, applications: QuerySet[Application]) -> str:
def handle(self, *args, **options):
try:
ahjo_auth_token = get_token()
- except AhjoTokenExpiredException as e:
+ except AhjoTokenExpiredError as e:
LOGGER.error(f"Failed to get auth token from Ahjo: {e}")
return
except ImproperlyConfigured as e:
@@ -102,8 +106,8 @@ def handle(self, *args, **options):
message_start = "retry" if self.is_retry else "send"
self.stdout.write(
- f"Would {message_start} sending {request_type} \
-requests for {len(applications)} applications to Ahjo"
+ f"Would {message_start} sending {request_type} requests for"
+ f" {len(applications)} applications to Ahjo"
)
for application in applications:
@@ -130,8 +134,10 @@ def run_requests(
message_start = "Retrying" if self.is_retry else "Sending"
- message = f"{message_start} {ahjo_request_type} request to Ahjo \
-for {len(applications)} applications: {application_numbers}"
+ message = (
+ f"{message_start} {ahjo_request_type} request to Ahjo for"
+ f" {len(applications)} applications: {application_numbers}"
+ )
self.stdout.write(self._print_with_timestamp(message))
@@ -142,7 +148,9 @@ def run_requests(
ValueError: "Value error for application",
ObjectDoesNotExist: "Object not found error for application",
ImproperlyConfigured: "Improperly configured error for application",
- DecisionProposalAlreadyAcceptedError: "Decision proposal error for application",
+ DecisionProposalAlreadyAcceptedError: (
+ "Decision proposal error for application"
+ ),
}
for application in applications:
@@ -153,7 +161,10 @@ def run_requests(
application, ahjo_auth_token
)
except tuple(exception_messages.keys()) as e:
- error_text = f"{exception_messages[type(e)]} {application.application_number}: {e}"
+ error_text = (
+ f"{exception_messages[type(e)]}"
+ f" {application.application_number}: {e}"
+ )
LOGGER.error(error_text)
AhjoErrorWriter.write_to_validation_error(
AhjoFormattedError(
@@ -199,14 +210,15 @@ def _print_results(
self.stdout.write(
self.style.SUCCESS(
self._print_with_timestamp(
- f"Sent {ahjo_request_type} requests for {len(successful_applications)} \
-application(s): {successful_application_numbers} to Ahjo"
+ f"Sent {ahjo_request_type} requests for"
+ f" {len(successful_applications)} application(s):"
+ f" {successful_application_numbers} to Ahjo"
)
)
)
self.stdout.write(
- f"Submitting {len(successful_applications)} {ahjo_request_type} \
-requests took {elapsed_time} seconds to run."
+ f"Submitting {len(successful_applications)} {ahjo_request_type}"
+ f" requests took {elapsed_time} seconds to run."
)
if failed_applications:
failed_application_numbers = self.get_application_numbers(
@@ -216,8 +228,9 @@ def _print_results(
self.stdout.write(
self.style.ERROR(
self._print_with_timestamp(
- f"Failed to submit {ahjo_request_type} {len(failed_applications)} \
-application(s): {failed_application_numbers} to Ahjo"
+ f"Failed to submit {ahjo_request_type}"
+ f" {len(failed_applications)} application(s):"
+ f" {failed_application_numbers} to Ahjo"
)
)
)
@@ -229,15 +242,18 @@ def _handle_application_request_success(
response_text: str,
request_type: AhjoRequestType,
) -> str:
- # The request id is returned in the response text in text format {request_id}, so remove brackets here
+ # The request id is returned in the response text in text format {request_id},
+ # so remove brackets here
response_text = response_text.replace("{", "").replace("}", "")
ahjo_status = application.ahjo_status.latest()
ahjo_status.ahjo_request_id = response_text
ahjo_status.save()
- return f"{counter}. Successfully submitted {request_type} request for application {application.id}, \
- number: {application.application_number}, to Ahjo, \
- received Ahjo requestId: {response_text}"
+ return (
+ f"{counter}. Successfully submitted {request_type} request for application"
+ f" {application.id}, number: {application.application_number},"
+ f" to Ahjo, received Ahjo requestId: {response_text}"
+ )
def _handle_successful_request(
self,
@@ -276,8 +292,10 @@ def _handle_failed_request(
self.stdout.write(
self.style.ERROR(
self._print_with_timestamp(
- f"{counter}. Failed to submit {request_type} for application {application.id} \
- number: {application.application_number}, to Ahjo. {additional_error_text}"
+ f"{counter}. Failed to submit {request_type} for application"
+ f" {application.id} number:"
+ f" {application.application_number}, to Ahjo."
+ f" {additional_error_text}"
)
)
)
@@ -287,7 +305,9 @@ def _get_request_handler(self, request_type: AhjoRequestType):
AhjoRequestType.OPEN_CASE: send_open_case_request_to_ahjo,
AhjoRequestType.SEND_DECISION_PROPOSAL: send_decision_proposal_to_ahjo,
AhjoRequestType.ADD_RECORDS: send_new_attachment_records_to_ahjo,
- AhjoRequestType.UPDATE_APPLICATION: update_application_summary_record_in_ahjo,
+ AhjoRequestType.UPDATE_APPLICATION: (
+ update_application_summary_record_in_ahjo
+ ),
AhjoRequestType.GET_DECISION_DETAILS: get_decision_details_from_ahjo,
AhjoRequestType.DELETE_APPLICATION: delete_application_in_ahjo,
}
diff --git a/backend/benefit/applications/migrations/0001_initial.py b/backend/benefit/applications/migrations/0001_initial.py
index 87ca3d011d..7075f9859d 100644
--- a/backend/benefit/applications/migrations/0001_initial.py
+++ b/backend/benefit/applications/migrations/0001_initial.py
@@ -1,15 +1,15 @@
# Generated by Django 3.2 on 2021-06-14 06:22
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import localflavor.generic.models
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
-
initial = True
dependencies = [
@@ -134,7 +134,10 @@ class Migration(migrations.Migration):
"co_operation_negotiations_description",
models.CharField(
max_length=256,
- verbose_name="additional information about the ongoing co-operation negotiations",
+ verbose_name=(
+ "additional information about the ongoing co-operation"
+ " negotiations"
+ ),
),
),
("apprenticeship_program", models.BooleanField(null=True)),
@@ -534,7 +537,10 @@ class Migration(migrations.Migration):
"co_operation_negotiations_description",
models.CharField(
max_length=256,
- verbose_name="additional information about the ongoing co-operation negotiations",
+ verbose_name=(
+ "additional information about the ongoing co-operation"
+ " negotiations"
+ ),
),
),
("apprenticeship_program", models.BooleanField(null=True)),
diff --git a/backend/benefit/applications/migrations/0002_field_changes_for_application_api.py b/backend/benefit/applications/migrations/0002_field_changes_for_application_api.py
index 38f5f804dd..3ea3155e4f 100644
--- a/backend/benefit/applications/migrations/0002_field_changes_for_application_api.py
+++ b/backend/benefit/applications/migrations/0002_field_changes_for_application_api.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.4 on 2021-06-16 12:01
-from django.db import migrations, models
import localflavor.generic.models
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0001_initial"),
]
@@ -79,7 +78,9 @@ class Migration(migrations.Migration):
field=models.CharField(
blank=True,
max_length=256,
- verbose_name="additional information about the ongoing co-operation negotiations",
+ verbose_name=(
+ "additional information about the ongoing co-operation negotiations"
+ ),
),
),
migrations.AlterField(
@@ -142,7 +143,9 @@ class Migration(migrations.Migration):
field=models.CharField(
blank=True,
max_length=256,
- verbose_name="additional information about the ongoing co-operation negotiations",
+ verbose_name=(
+ "additional information about the ongoing co-operation negotiations"
+ ),
),
),
migrations.AlterField(
diff --git a/backend/benefit/applications/migrations/0003_employee.py b/backend/benefit/applications/migrations/0003_employee.py
index 4ae30102a3..9941a2f8db 100644
--- a/backend/benefit/applications/migrations/0003_employee.py
+++ b/backend/benefit/applications/migrations/0003_employee.py
@@ -8,7 +8,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0002_field_changes_for_application_api"),
]
diff --git a/backend/benefit/applications/migrations/0004_validation_fixes.py b/backend/benefit/applications/migrations/0004_validation_fixes.py
index 84a1c574f9..10d151ff89 100644
--- a/backend/benefit/applications/migrations/0004_validation_fixes.py
+++ b/backend/benefit/applications/migrations/0004_validation_fixes.py
@@ -1,12 +1,12 @@
# Generated by Django 3.2.4 on 2021-06-22 04:35
import datetime
-from django.db import migrations, models
+
import phonenumber_field.modelfields
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0003_employee"),
]
diff --git a/backend/benefit/applications/migrations/0005_employee_is_living_in_helsinki.py b/backend/benefit/applications/migrations/0005_employee_is_living_in_helsinki.py
index a5cd84522b..31f71b3d61 100644
--- a/backend/benefit/applications/migrations/0005_employee_is_living_in_helsinki.py
+++ b/backend/benefit/applications/migrations/0005_employee_is_living_in_helsinki.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0004_validation_fixes"),
]
diff --git a/backend/benefit/applications/migrations/0006_field_changes_for_employee_api.py b/backend/benefit/applications/migrations/0006_field_changes_for_employee_api.py
index 1bfad1a35e..7fcc87c398 100644
--- a/backend/benefit/applications/migrations/0006_field_changes_for_employee_api.py
+++ b/backend/benefit/applications/migrations/0006_field_changes_for_employee_api.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2021-07-01 06:49
-from django.db import migrations, models
import encrypted_fields.fields
import phonenumber_field.modelfields
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0005_employee_is_living_in_helsinki"),
]
diff --git a/backend/benefit/applications/migrations/0007_application_page2_new_fields.py b/backend/benefit/applications/migrations/0007_application_page2_new_fields.py
index 8d7ed9bf0e..34428d4e97 100644
--- a/backend/benefit/applications/migrations/0007_application_page2_new_fields.py
+++ b/backend/benefit/applications/migrations/0007_application_page2_new_fields.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0006_field_changes_for_employee_api"),
]
diff --git a/backend/benefit/applications/migrations/0008_attachment.py b/backend/benefit/applications/migrations/0008_attachment.py
index a764f43d82..3aedbbd142 100644
--- a/backend/benefit/applications/migrations/0008_attachment.py
+++ b/backend/benefit/applications/migrations/0008_attachment.py
@@ -1,12 +1,12 @@
# Generated by Django 3.2.4 on 2021-07-02 10:36
-from django.db import migrations, models
-import django.db.models.deletion
import uuid
+import django.db.models.deletion
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0007_application_page2_new_fields"),
]
diff --git a/backend/benefit/applications/migrations/0009_attachments_api.py b/backend/benefit/applications/migrations/0009_attachments_api.py
index 4d6d4d9e34..29d9036839 100644
--- a/backend/benefit/applications/migrations/0009_attachments_api.py
+++ b/backend/benefit/applications/migrations/0009_attachments_api.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0008_attachment"),
]
diff --git a/backend/benefit/applications/migrations/0010_application_missing_applicant_fields.py b/backend/benefit/applications/migrations/0010_application_missing_applicant_fields.py
index 5de227c0d4..82ab61bacb 100644
--- a/backend/benefit/applications/migrations/0010_application_missing_applicant_fields.py
+++ b/backend/benefit/applications/migrations/0010_application_missing_applicant_fields.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0009_attachments_api"),
]
diff --git a/backend/benefit/applications/migrations/0011_application_step.py b/backend/benefit/applications/migrations/0011_application_step.py
index 7da6d9cef9..300b8fac01 100644
--- a/backend/benefit/applications/migrations/0011_application_step.py
+++ b/backend/benefit/applications/migrations/0011_application_step.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0010_application_missing_applicant_fields"),
]
diff --git a/backend/benefit/applications/migrations/0012_create_application_number_seq.py b/backend/benefit/applications/migrations/0012_create_application_number_seq.py
index f4a73a13c7..cfb1d34739 100644
--- a/backend/benefit/applications/migrations/0012_create_application_number_seq.py
+++ b/backend/benefit/applications/migrations/0012_create_application_number_seq.py
@@ -4,15 +4,14 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0011_application_step"),
]
operations = [
migrations.RunSQL(
- "CREATE SEQUENCE seq_application_number INCREMENT BY 1 START WITH 125000 OWNED "
- "BY bf_applications_application.application_number",
+ "CREATE SEQUENCE seq_application_number INCREMENT BY 1 START WITH 125000"
+ " OWNED BY bf_applications_application.application_number",
"DROP SEQUENCE seq_application_number",
)
]
diff --git a/backend/benefit/applications/migrations/0013_application_number_auto_field.py b/backend/benefit/applications/migrations/0013_application_number_auto_field.py
index 3373d939bb..f202244150 100644
--- a/backend/benefit/applications/migrations/0013_application_number_auto_field.py
+++ b/backend/benefit/applications/migrations/0013_application_number_auto_field.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2.4 on 2021-08-11 16:21
-import applications.models
from django.db import migrations, models
+import applications.models
+
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0012_create_application_number_seq"),
]
diff --git a/backend/benefit/applications/migrations/0014_application_batch.py b/backend/benefit/applications/migrations/0014_application_batch.py
index 35c9c51ed3..8b6d8656e2 100644
--- a/backend/benefit/applications/migrations/0014_application_batch.py
+++ b/backend/benefit/applications/migrations/0014_application_batch.py
@@ -1,12 +1,12 @@
# Generated by Django 3.2.4 on 2021-08-20 06:41
-from django.db import migrations, models
-import django.db.models.deletion
import uuid
+import django.db.models.deletion
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0001_initial"),
("applications", "0013_application_number_auto_field"),
diff --git a/backend/benefit/applications/migrations/0015_application_batch_api.py b/backend/benefit/applications/migrations/0015_application_batch_api.py
index 074382c3d3..e345633ea6 100644
--- a/backend/benefit/applications/migrations/0015_application_batch_api.py
+++ b/backend/benefit/applications/migrations/0015_application_batch_api.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0014_application_batch"),
]
diff --git a/backend/benefit/applications/migrations/0016_benefit_amount.py b/backend/benefit/applications/migrations/0016_benefit_amount.py
index 281123b336..5a5cb15de0 100644
--- a/backend/benefit/applications/migrations/0016_benefit_amount.py
+++ b/backend/benefit/applications/migrations/0016_benefit_amount.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0015_application_batch_api"),
]
@@ -29,7 +28,9 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=8,
null=True,
- verbose_name="amount of the benefit manually entered by the application handler",
+ verbose_name=(
+ "amount of the benefit manually entered by the application handler"
+ ),
),
),
migrations.AddField(
@@ -51,7 +52,9 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=8,
null=True,
- verbose_name="amount of the benefit manually entered by the application handler",
+ verbose_name=(
+ "amount of the benefit manually entered by the application handler"
+ ),
),
),
]
diff --git a/backend/benefit/applications/migrations/0017_add_company_department.py b/backend/benefit/applications/migrations/0017_add_company_department.py
index d67ccc1c25..f788405ffe 100644
--- a/backend/benefit/applications/migrations/0017_add_company_department.py
+++ b/backend/benefit/applications/migrations/0017_add_company_department.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0016_benefit_amount"),
]
diff --git a/backend/benefit/applications/migrations/0018_remove_unsearchable_social_security_number.py b/backend/benefit/applications/migrations/0018_remove_unsearchable_social_security_number.py
index d6e05b2b07..704dbeb174 100644
--- a/backend/benefit/applications/migrations/0018_remove_unsearchable_social_security_number.py
+++ b/backend/benefit/applications/migrations/0018_remove_unsearchable_social_security_number.py
@@ -1,12 +1,9 @@
# Generated by Django 3.2.4 on 2021-09-07 11:30
from django.db import migrations
-from django.conf import settings
-import encrypted_fields.fields
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0017_add_company_department"),
]
diff --git a/backend/benefit/applications/migrations/0019_searchable_social_security_number.py b/backend/benefit/applications/migrations/0019_searchable_social_security_number.py
index 0d037a28a6..356bce0045 100644
--- a/backend/benefit/applications/migrations/0019_searchable_social_security_number.py
+++ b/backend/benefit/applications/migrations/0019_searchable_social_security_number.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2021-09-07 11:30
-from django.db import migrations
-from django.conf import settings
import encrypted_fields.fields
+from django.conf import settings
+from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0018_remove_unsearchable_social_security_number"),
]
diff --git a/backend/benefit/applications/migrations/0020_employee_consent_attachment_type.py b/backend/benefit/applications/migrations/0020_employee_consent_attachment_type.py
index 7fc7680c7f..4776d43d35 100644
--- a/backend/benefit/applications/migrations/0020_employee_consent_attachment_type.py
+++ b/backend/benefit/applications/migrations/0020_employee_consent_attachment_type.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0019_searchable_social_security_number"),
]
diff --git a/backend/benefit/applications/migrations/0021_allow_blank_batch.py b/backend/benefit/applications/migrations/0021_allow_blank_batch.py
index 01def4c6e2..77c0793116 100644
--- a/backend/benefit/applications/migrations/0021_allow_blank_batch.py
+++ b/backend/benefit/applications/migrations/0021_allow_blank_batch.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.4 on 2021-09-25 10:59
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0020_employee_consent_attachment_type"),
]
diff --git a/backend/benefit/applications/migrations/0022_add_association_immediate_manager_check.py b/backend/benefit/applications/migrations/0022_add_association_immediate_manager_check.py
index 026cb00902..cada43e437 100644
--- a/backend/benefit/applications/migrations/0022_add_association_immediate_manager_check.py
+++ b/backend/benefit/applications/migrations/0022_add_association_immediate_manager_check.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0021_allow_blank_batch"),
]
diff --git a/backend/benefit/applications/migrations/0023_move_benefit_amount_to_calculation.py b/backend/benefit/applications/migrations/0023_move_benefit_amount_to_calculation.py
index 7185bcd794..cce7bae2e3 100644
--- a/backend/benefit/applications/migrations/0023_move_benefit_amount_to_calculation.py
+++ b/backend/benefit/applications/migrations/0023_move_benefit_amount_to_calculation.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0022_add_association_immediate_manager_check"),
]
diff --git a/backend/benefit/applications/migrations/0024_phone_number_length_validation.py b/backend/benefit/applications/migrations/0024_phone_number_length_validation.py
index 47eb036856..3e6570c1fb 100644
--- a/backend/benefit/applications/migrations/0024_phone_number_length_validation.py
+++ b/backend/benefit/applications/migrations/0024_phone_number_length_validation.py
@@ -6,7 +6,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0023_move_benefit_amount_to_calculation"),
]
diff --git a/backend/benefit/applications/migrations/0025_new_application_status.py b/backend/benefit/applications/migrations/0025_new_application_status.py
index 18675a06ae..28027e52ec 100644
--- a/backend/benefit/applications/migrations/0025_new_application_status.py
+++ b/backend/benefit/applications/migrations/0025_new_application_status.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0024_phone_number_length_validation"),
]
diff --git a/backend/benefit/applications/migrations/0026_alter_applicationbatch_status.py b/backend/benefit/applications/migrations/0026_alter_applicationbatch_status.py
index a73e2ee2e6..c8c5ba71fb 100644
--- a/backend/benefit/applications/migrations/0026_alter_applicationbatch_status.py
+++ b/backend/benefit/applications/migrations/0026_alter_applicationbatch_status.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0025_new_application_status"),
]
diff --git a/backend/benefit/applications/migrations/0027_applicationlogentry_ordering.py b/backend/benefit/applications/migrations/0027_applicationlogentry_ordering.py
index ca21b645d3..5495768bcc 100644
--- a/backend/benefit/applications/migrations/0027_applicationlogentry_ordering.py
+++ b/backend/benefit/applications/migrations/0027_applicationlogentry_ordering.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0026_alter_applicationbatch_status"),
]
diff --git a/backend/benefit/applications/migrations/0028_company_form_code.py b/backend/benefit/applications/migrations/0028_company_form_code.py
index d64226276b..117b9d8858 100644
--- a/backend/benefit/applications/migrations/0028_company_form_code.py
+++ b/backend/benefit/applications/migrations/0028_company_form_code.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0027_applicationlogentry_ordering"),
]
diff --git a/backend/benefit/applications/migrations/0028_localized_iban_field.py b/backend/benefit/applications/migrations/0028_localized_iban_field.py
index 7ef3dbf31a..8f0cf1d93a 100644
--- a/backend/benefit/applications/migrations/0028_localized_iban_field.py
+++ b/backend/benefit/applications/migrations/0028_localized_iban_field.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2.4 on 2022-03-21 07:45
-import common.localized_iban_field
from django.db import migrations
+import common.localized_iban_field
+
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0028_company_form_code"),
]
diff --git a/backend/benefit/applications/migrations/0030_encrypt_employee_first_name_and_last_name.py b/backend/benefit/applications/migrations/0030_encrypt_employee_first_name_and_last_name.py
index 8df9219339..4415ef93e2 100644
--- a/backend/benefit/applications/migrations/0030_encrypt_employee_first_name_and_last_name.py
+++ b/backend/benefit/applications/migrations/0030_encrypt_employee_first_name_and_last_name.py
@@ -1,8 +1,8 @@
# Generated by Django 3.2.18 on 2023-03-29 09:41
-from django.db import migrations
-from django.conf import settings
import encrypted_fields.fields
+from django.conf import settings
+from django.db import migrations
class Migration(migrations.Migration):
diff --git a/backend/benefit/applications/migrations/0031_application_batches_expert_inspector_title.py b/backend/benefit/applications/migrations/0031_application_batches_expert_inspector_title.py
index e84a83ed4c..f8e3d92c26 100644
--- a/backend/benefit/applications/migrations/0031_application_batches_expert_inspector_title.py
+++ b/backend/benefit/applications/migrations/0031_application_batches_expert_inspector_title.py
@@ -1,15 +1,17 @@
from django.db import migrations, models
-class Migration(migrations.Migration):
- dependencies = [
- ("applications", "0030_encrypt_employee_first_name_and_last_name")
- ]
+class Migration(migrations.Migration):
+ dependencies = [("applications", "0030_encrypt_employee_first_name_and_last_name")]
operations = [
- migrations.AddField("ApplicationBatch", "expert_inspector_title", models.CharField(
- blank=True,
- max_length=64,
- verbose_name="Expert inspector's title",
- )),
+ migrations.AddField(
+ "ApplicationBatch",
+ "expert_inspector_title",
+ models.CharField(
+ blank=True,
+ max_length=64,
+ verbose_name="Expert inspector's title",
+ ),
+ ),
]
diff --git a/backend/benefit/applications/migrations/0032_auto_20230526_1010.py b/backend/benefit/applications/migrations/0032_auto_20230526_1010.py
index 1e843226c8..01375bdf73 100755
--- a/backend/benefit/applications/migrations/0032_auto_20230526_1010.py
+++ b/backend/benefit/applications/migrations/0032_auto_20230526_1010.py
@@ -1,27 +1,36 @@
# Generated by Django 3.2.18 on 2023-05-26 07:10
-import applications.models
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
+import applications.models
-class Migration(migrations.Migration):
+class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0031_application_batches_expert_inspector_title'),
+ ("applications", "0031_application_batches_expert_inspector_title"),
]
operations = [
migrations.AddField(
- model_name='applicationbatch',
- name='handler',
- field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
+ model_name="applicationbatch",
+ name="handler",
+ field=models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='decision_date',
- field=models.DateField(blank=True, null=True, validators=[applications.models.validate_decision_date], verbose_name='date of the decision in Ahjo'),
+ model_name="applicationbatch",
+ name="decision_date",
+ field=models.DateField(
+ blank=True,
+ null=True,
+ validators=[applications.models.validate_decision_date],
+ verbose_name="date of the decision in Ahjo",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0033_add_origin_and_attachment_types.py b/backend/benefit/applications/migrations/0033_add_origin_and_attachment_types.py
index 9f2eb141c9..216ba7a00f 100644
--- a/backend/benefit/applications/migrations/0033_add_origin_and_attachment_types.py
+++ b/backend/benefit/applications/migrations/0033_add_origin_and_attachment_types.py
@@ -1,36 +1,66 @@
# Generated by Django 3.2.18 on 2023-06-15 09:52
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0032_auto_20230526_1010'),
+ ("applications", "0032_auto_20230526_1010"),
]
operations = [
migrations.AddField(
- model_name='application',
- name='application_origin',
- field=models.CharField(choices=[('handler', 'Handler'), ('applicant', 'Applicant')], default='applicant', max_length=64, verbose_name='application origin'),
+ model_name="application",
+ name="application_origin",
+ field=models.CharField(
+ choices=[("handler", "Handler"), ("applicant", "Applicant")],
+ default="applicant",
+ max_length=64,
+ verbose_name="application origin",
+ ),
),
migrations.AddField(
- model_name='historicalapplication',
- name='application_origin',
- field=models.CharField(choices=[('handler', 'Handler'), ('applicant', 'Applicant')], default='applicant', max_length=64, verbose_name='application origin'),
+ model_name="historicalapplication",
+ name="application_origin",
+ field=models.CharField(
+ choices=[("handler", "Handler"), ("applicant", "Applicant")],
+ default="applicant",
+ max_length=64,
+ verbose_name="application origin",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='handler',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
+ model_name="applicationbatch",
+ name="handler",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ ),
),
migrations.AlterField(
- model_name='attachment',
- name='attachment_type',
- field=models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment')], max_length=64, verbose_name='attachment type in business rules'),
+ model_name="attachment",
+ name="attachment_type",
+ field=models.CharField(
+ choices=[
+ ("employment_contract", "employment contract"),
+ ("pay_subsidy_decision", "pay subsidy decision"),
+ ("commission_contract", "commission contract"),
+ (
+ "education_contract",
+ "education contract of the apprenticeship office",
+ ),
+ ("helsinki_benefit_voucher", "helsinki benefit voucher"),
+ ("employee_consent", "employee consent"),
+ ("full_application", "full application"),
+ ("other_attachment", "other attachment"),
+ ],
+ max_length=64,
+ verbose_name="attachment type in business rules",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0034_batch_talpa_inspectors.py b/backend/benefit/applications/migrations/0034_batch_talpa_inspectors.py
index 8d081b6ac2..0cad96a162 100644
--- a/backend/benefit/applications/migrations/0034_batch_talpa_inspectors.py
+++ b/backend/benefit/applications/migrations/0034_batch_talpa_inspectors.py
@@ -2,7 +2,6 @@
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
diff --git a/backend/benefit/applications/migrations/0035_alter_applicationbatch_handler.py b/backend/benefit/applications/migrations/0035_alter_applicationbatch_handler.py
index cb708c7ea7..fd5787187a 100644
--- a/backend/benefit/applications/migrations/0035_alter_applicationbatch_handler.py
+++ b/backend/benefit/applications/migrations/0035_alter_applicationbatch_handler.py
@@ -1,8 +1,8 @@
# Generated by Django 3.2.18 on 2023-06-15 11:47
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
diff --git a/backend/benefit/applications/migrations/0037_reviewstate.py b/backend/benefit/applications/migrations/0037_reviewstate.py
index fa9b8e46d1..3a99e67d87 100644
--- a/backend/benefit/applications/migrations/0037_reviewstate.py
+++ b/backend/benefit/applications/migrations/0037_reviewstate.py
@@ -1,28 +1,58 @@
# Generated by Django 3.2.18 on 2023-07-19 20:52
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0036_alter_employee_working_hours'),
+ ("applications", "0036_alter_employee_working_hours"),
]
operations = [
migrations.CreateModel(
- name='ReviewState',
+ name="ReviewState",
fields=[
- ('application', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='applications.application', verbose_name='application')),
- ('company', models.BooleanField(default=False, verbose_name='company')),
- ('company_contact_person', models.BooleanField(default=False, verbose_name='company contact person')),
- ('de_minimis_aids', models.BooleanField(default=False, verbose_name='de minimis aids')),
- ('co_operation_negotiations', models.BooleanField(default=False, verbose_name='co-operation negotiations')),
- ('employee', models.BooleanField(default=False, verbose_name='employee')),
- ('pay_subsidy', models.BooleanField(default=False, verbose_name='pay subsidy')),
- ('benefit', models.BooleanField(default=False, verbose_name='benefit')),
- ('employment', models.BooleanField(default=False, verbose_name='employment')),
+ (
+ "application",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.CASCADE,
+ primary_key=True,
+ serialize=False,
+ to="applications.application",
+ verbose_name="application",
+ ),
+ ),
+ ("company", models.BooleanField(default=False, verbose_name="company")),
+ (
+ "company_contact_person",
+ models.BooleanField(
+ default=False, verbose_name="company contact person"
+ ),
+ ),
+ (
+ "de_minimis_aids",
+ models.BooleanField(default=False, verbose_name="de minimis aids"),
+ ),
+ (
+ "co_operation_negotiations",
+ models.BooleanField(
+ default=False, verbose_name="co-operation negotiations"
+ ),
+ ),
+ (
+ "employee",
+ models.BooleanField(default=False, verbose_name="employee"),
+ ),
+ (
+ "pay_subsidy",
+ models.BooleanField(default=False, verbose_name="pay subsidy"),
+ ),
+ ("benefit", models.BooleanField(default=False, verbose_name="benefit")),
+ (
+ "employment",
+ models.BooleanField(default=False, verbose_name="employment"),
+ ),
],
),
]
diff --git a/backend/benefit/applications/migrations/0038_reviewstate_approval.py b/backend/benefit/applications/migrations/0038_reviewstate_approval.py
index 75181c6d73..e6caa0d987 100644
--- a/backend/benefit/applications/migrations/0038_reviewstate_approval.py
+++ b/backend/benefit/applications/migrations/0038_reviewstate_approval.py
@@ -4,15 +4,14 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0037_reviewstate'),
+ ("applications", "0037_reviewstate"),
]
operations = [
migrations.AddField(
- model_name='reviewstate',
- name='approval',
- field=models.BooleanField(default=False, verbose_name='approval'),
+ model_name="reviewstate",
+ name="approval",
+ field=models.BooleanField(default=False, verbose_name="approval"),
),
]
diff --git a/backend/benefit/applications/migrations/0039_alter_paysubsidy_percentages.py b/backend/benefit/applications/migrations/0039_alter_paysubsidy_percentages.py
index 9339abf11f..ae4d1d9c70 100644
--- a/backend/benefit/applications/migrations/0039_alter_paysubsidy_percentages.py
+++ b/backend/benefit/applications/migrations/0039_alter_paysubsidy_percentages.py
@@ -4,30 +4,49 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0038_reviewstate_approval'),
+ ("applications", "0038_reviewstate_approval"),
]
operations = [
migrations.AlterField(
- model_name='application',
- name='additional_pay_subsidy_percent',
- field=models.IntegerField(blank=True, choices=[(50, '50%'), (70, '70%'), (100, '100%')], null=True, verbose_name='Pay subsidy percent for second pay subsidy grant'),
+ model_name="application",
+ name="additional_pay_subsidy_percent",
+ field=models.IntegerField(
+ blank=True,
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ null=True,
+ verbose_name="Pay subsidy percent for second pay subsidy grant",
+ ),
),
migrations.AlterField(
- model_name='application',
- name='pay_subsidy_percent',
- field=models.IntegerField(blank=True, choices=[(50, '50%'), (70, '70%'), (100, '100%')], null=True, verbose_name='Pay subsidy percent'),
+ model_name="application",
+ name="pay_subsidy_percent",
+ field=models.IntegerField(
+ blank=True,
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ null=True,
+ verbose_name="Pay subsidy percent",
+ ),
),
migrations.AlterField(
- model_name='historicalapplication',
- name='additional_pay_subsidy_percent',
- field=models.IntegerField(blank=True, choices=[(50, '50%'), (70, '70%'), (100, '100%')], null=True, verbose_name='Pay subsidy percent for second pay subsidy grant'),
+ model_name="historicalapplication",
+ name="additional_pay_subsidy_percent",
+ field=models.IntegerField(
+ blank=True,
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ null=True,
+ verbose_name="Pay subsidy percent for second pay subsidy grant",
+ ),
),
migrations.AlterField(
- model_name='historicalapplication',
- name='pay_subsidy_percent',
- field=models.IntegerField(blank=True, choices=[(50, '50%'), (70, '70%'), (100, '100%')], null=True, verbose_name='Pay subsidy percent'),
+ model_name="historicalapplication",
+ name="pay_subsidy_percent",
+ field=models.IntegerField(
+ blank=True,
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ null=True,
+ verbose_name="Pay subsidy percent",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0040_pay_subsidy_types.py b/backend/benefit/applications/migrations/0040_pay_subsidy_types.py
index 568da432ee..648b359e91 100644
--- a/backend/benefit/applications/migrations/0040_pay_subsidy_types.py
+++ b/backend/benefit/applications/migrations/0040_pay_subsidy_types.py
@@ -1,6 +1,7 @@
# Generated by Django 3.2.18 on 2023-09-21 10:39
from django.db import migrations, models
+
from applications.enums import PaySubsidyGranted
diff --git a/backend/benefit/applications/migrations/0041_add_paper_application_date.py b/backend/benefit/applications/migrations/0041_add_paper_application_date.py
index 3bce0b52f0..3f37b09f15 100644
--- a/backend/benefit/applications/migrations/0041_add_paper_application_date.py
+++ b/backend/benefit/applications/migrations/0041_add_paper_application_date.py
@@ -4,20 +4,23 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0040_pay_subsidy_types'),
+ ("applications", "0040_pay_subsidy_types"),
]
operations = [
migrations.AddField(
- model_name='application',
- name='paper_application_date',
- field=models.DateField(blank=True, null=True, verbose_name='paper application date'),
+ model_name="application",
+ name="paper_application_date",
+ field=models.DateField(
+ blank=True, null=True, verbose_name="paper application date"
+ ),
),
migrations.AddField(
- model_name='historicalapplication',
- name='paper_application_date',
- field=models.DateField(blank=True, null=True, verbose_name='paper application date'),
+ model_name="historicalapplication",
+ name="paper_application_date",
+ field=models.DateField(
+ blank=True, null=True, verbose_name="paper application date"
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0042_reviewstate_paper.py b/backend/benefit/applications/migrations/0042_reviewstate_paper.py
index 303ad41de0..50cb20ddbd 100644
--- a/backend/benefit/applications/migrations/0042_reviewstate_paper.py
+++ b/backend/benefit/applications/migrations/0042_reviewstate_paper.py
@@ -4,15 +4,14 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0041_add_paper_application_date'),
+ ("applications", "0041_add_paper_application_date"),
]
operations = [
migrations.AddField(
- model_name='reviewstate',
- name='paper',
- field=models.BooleanField(default=False, verbose_name='paper'),
+ model_name="reviewstate",
+ name="paper",
+ field=models.BooleanField(default=False, verbose_name="paper"),
),
]
diff --git a/backend/benefit/applications/migrations/0043_ahjosetting.py b/backend/benefit/applications/migrations/0043_ahjosetting.py
index c63024a541..d4a6ab8e6a 100644
--- a/backend/benefit/applications/migrations/0043_ahjosetting.py
+++ b/backend/benefit/applications/migrations/0043_ahjosetting.py
@@ -4,23 +4,38 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0042_reviewstate_paper'),
+ ("applications", "0042_reviewstate_paper"),
]
operations = [
migrations.CreateModel(
- name='AhjoSetting',
+ name="AhjoSetting",
fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('name', models.CharField(max_length=255, unique=True)),
- ('data', models.JSONField()),
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ ("name", models.CharField(max_length=255, unique=True)),
+ ("data", models.JSONField()),
],
options={
- 'abstract': False,
+ "abstract": False,
},
),
]
diff --git a/backend/benefit/applications/migrations/0044_ahjostatus.py b/backend/benefit/applications/migrations/0044_ahjostatus.py
index 04e68a30cc..98622f0042 100644
--- a/backend/benefit/applications/migrations/0044_ahjostatus.py
+++ b/backend/benefit/applications/migrations/0044_ahjostatus.py
@@ -1,31 +1,86 @@
# Generated by Django 3.2.18 on 2023-10-26 11:01
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0043_ahjosetting'),
+ ("applications", "0043_ahjosetting"),
]
operations = [
migrations.CreateModel(
- name='AhjoStatus',
+ name="AhjoStatus",
fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('status', models.CharField(choices=[('submitted_but_not_sent_to_ahjo', 'Submitted but not sent to AHJO'), ('request_to_open_case_sent', 'Request to open the case sent to AHJO'), ('diary_number_received', 'Diary number received'), ('case_opened', 'Case opened in AHJO'), ('update_request_sent', 'Update request sent'), ('update_request_received', 'Update request received'), ('decision_proposal_sent', 'Decision proposal sent'), ('decision_proposal_accepted', 'Decision proposal accepted'), ('decision_proposal_rejected', 'Decision proposal rejected'), ('delete_request_sent', 'Delete request sent'), ('delete_request_received', 'Delete request received')], default='submitted_but_not_sent_to_ahjo', max_length=64, verbose_name='status')),
- ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ahjo_status', to='applications.application', verbose_name='application')),
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ (
+ "status",
+ models.CharField(
+ choices=[
+ (
+ "submitted_but_not_sent_to_ahjo",
+ "Submitted but not sent to AHJO",
+ ),
+ (
+ "request_to_open_case_sent",
+ "Request to open the case sent to AHJO",
+ ),
+ ("diary_number_received", "Diary number received"),
+ ("case_opened", "Case opened in AHJO"),
+ ("update_request_sent", "Update request sent"),
+ ("update_request_received", "Update request received"),
+ ("decision_proposal_sent", "Decision proposal sent"),
+ (
+ "decision_proposal_accepted",
+ "Decision proposal accepted",
+ ),
+ (
+ "decision_proposal_rejected",
+ "Decision proposal rejected",
+ ),
+ ("delete_request_sent", "Delete request sent"),
+ ("delete_request_received", "Delete request received"),
+ ],
+ default="submitted_but_not_sent_to_ahjo",
+ max_length=64,
+ verbose_name="status",
+ ),
+ ),
+ (
+ "application",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="ahjo_status",
+ to="applications.application",
+ verbose_name="application",
+ ),
+ ),
],
options={
- 'verbose_name': 'ahjo status',
- 'verbose_name_plural': 'ahjo statuses',
- 'db_table': 'bf_applications_ahjo_status',
- 'ordering': ['application__created_at', 'created_at'],
- 'get_latest_by': 'created_at',
+ "verbose_name": "ahjo status",
+ "verbose_name_plural": "ahjo statuses",
+ "db_table": "bf_applications_ahjo_status",
+ "ordering": ["application__created_at", "created_at"],
+ "get_latest_by": "created_at",
},
),
]
diff --git a/backend/benefit/applications/migrations/0046_add_ahjo_ids_to_application.py b/backend/benefit/applications/migrations/0046_add_ahjo_ids_to_application.py
index 26886a4d3e..629f13b67d 100644
--- a/backend/benefit/applications/migrations/0046_add_ahjo_ids_to_application.py
+++ b/backend/benefit/applications/migrations/0046_add_ahjo_ids_to_application.py
@@ -4,30 +4,29 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0045_alter_ahjostatus_status'),
+ ("applications", "0045_alter_ahjostatus_status"),
]
operations = [
migrations.AddField(
- model_name='application',
- name='ahjo_case_guid',
+ model_name="application",
+ name="ahjo_case_guid",
field=models.UUIDField(blank=True, null=True),
),
migrations.AddField(
- model_name='application',
- name='ahjo_case_id',
+ model_name="application",
+ name="ahjo_case_id",
field=models.CharField(blank=True, max_length=64, null=True),
),
migrations.AddField(
- model_name='historicalapplication',
- name='ahjo_case_guid',
+ model_name="historicalapplication",
+ name="ahjo_case_guid",
field=models.UUIDField(blank=True, null=True),
),
migrations.AddField(
- model_name='historicalapplication',
- name='ahjo_case_id',
+ model_name="historicalapplication",
+ name="ahjo_case_id",
field=models.CharField(blank=True, max_length=64, null=True),
),
]
diff --git a/backend/benefit/applications/migrations/0047_remove_phone_number_restriction.py b/backend/benefit/applications/migrations/0047_remove_phone_number_restriction.py
index cda4bd0c90..a183dfd695 100644
--- a/backend/benefit/applications/migrations/0047_remove_phone_number_restriction.py
+++ b/backend/benefit/applications/migrations/0047_remove_phone_number_restriction.py
@@ -1,29 +1,40 @@
# Generated by Django 3.2.23 on 2023-12-20 14:27
-from django.db import migrations
import phonenumber_field.modelfields
+from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0046_add_ahjo_ids_to_application'),
+ ("applications", "0046_add_ahjo_ids_to_application"),
]
operations = [
migrations.AlterField(
- model_name='application',
- name='company_contact_person_phone_number',
- field=phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None, verbose_name="company contact person's phone number"),
+ model_name="application",
+ name="company_contact_person_phone_number",
+ field=phonenumber_field.modelfields.PhoneNumberField(
+ blank=True,
+ max_length=128,
+ region=None,
+ verbose_name="company contact person's phone number",
+ ),
),
migrations.AlterField(
- model_name='employee',
- name='phone_number',
- field=phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None, verbose_name='phone number'),
+ model_name="employee",
+ name="phone_number",
+ field=phonenumber_field.modelfields.PhoneNumberField(
+ blank=True, max_length=128, region=None, verbose_name="phone number"
+ ),
),
migrations.AlterField(
- model_name='historicalapplication',
- name='company_contact_person_phone_number',
- field=phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None, verbose_name="company contact person's phone number"),
+ model_name="historicalapplication",
+ name="company_contact_person_phone_number",
+ field=phonenumber_field.modelfields.PhoneNumberField(
+ blank=True,
+ max_length=128,
+ region=None,
+ verbose_name="company contact person's phone number",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py b/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py
index 49d8130c25..fe4ae22bc5 100644
--- a/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py
+++ b/backend/benefit/applications/migrations/0048_alter_attachment_attachment_type.py
@@ -4,15 +4,31 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0047_remove_phone_number_restriction'),
+ ("applications", "0047_remove_phone_number_restriction"),
]
operations = [
migrations.AlterField(
- model_name='attachment',
- name='attachment_type',
- field=models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment'), ('pdf_summary', 'pdf summary')], max_length=64, verbose_name='attachment type in business rules'),
+ model_name="attachment",
+ name="attachment_type",
+ field=models.CharField(
+ choices=[
+ ("employment_contract", "employment contract"),
+ ("pay_subsidy_decision", "pay subsidy decision"),
+ ("commission_contract", "commission contract"),
+ (
+ "education_contract",
+ "education contract of the apprenticeship office",
+ ),
+ ("helsinki_benefit_voucher", "helsinki benefit voucher"),
+ ("employee_consent", "employee consent"),
+ ("full_application", "full application"),
+ ("other_attachment", "other attachment"),
+ ("pdf_summary", "pdf summary"),
+ ],
+ max_length=64,
+ verbose_name="attachment type in business rules",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0049_historicalemployee.py b/backend/benefit/applications/migrations/0049_historicalemployee.py
index f9beabf1e5..06bb5e006d 100644
--- a/backend/benefit/applications/migrations/0049_historicalemployee.py
+++ b/backend/benefit/applications/migrations/0049_historicalemployee.py
@@ -1,59 +1,230 @@
# Generated by Django 3.2.23 on 2024-01-10 13:46
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import encrypted_fields.fields
import phonenumber_field.modelfields
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0048_alter_attachment_attachment_type'),
+ ("applications", "0048_alter_attachment_attachment_type"),
]
operations = [
migrations.CreateModel(
- name='HistoricalEmployee',
+ name="HistoricalEmployee",
fields=[
- ('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='time created')),
- ('modified_at', models.DateTimeField(blank=True, editable=False, verbose_name='time modified')),
- ('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)),
- ('encrypted_first_name', encrypted_fields.fields.EncryptedCharField(blank=True, max_length=128, verbose_name='first name')),
- ('encrypted_last_name', encrypted_fields.fields.EncryptedCharField(blank=True, max_length=128, verbose_name='last name')),
- ('first_name', encrypted_fields.fields.SearchField(blank=True, db_index=True, encrypted_field_name='encrypted_first_name', hash_key='02c5b8605cd4f9c188eee422209069b7bd3a607f0ae0a166eab0da223d1b6735', max_length=66, null=True)),
- ('last_name', encrypted_fields.fields.SearchField(blank=True, db_index=True, encrypted_field_name='encrypted_last_name', hash_key='af1b5a67d11197865a731c26bf9659716b9ded71c2802b4363856fe613b6b527', max_length=66, null=True)),
- ('encrypted_social_security_number', encrypted_fields.fields.EncryptedCharField(blank=True, max_length=11, verbose_name='social security number')),
- ('social_security_number', encrypted_fields.fields.SearchField(blank=True, db_index=True, encrypted_field_name='encrypted_social_security_number', hash_key='ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669', max_length=66, null=True)),
- ('phone_number', phonenumber_field.modelfields.PhoneNumberField(blank=True, max_length=128, region=None, verbose_name='phone number')),
- ('email', models.EmailField(blank=True, max_length=254, verbose_name='email')),
- ('employee_language', models.CharField(blank=True, choices=[('fi', 'suomi'), ('sv', 'svenska'), ('en', 'english')], default='fi', max_length=2)),
- ('job_title', models.CharField(blank=True, max_length=128, verbose_name='job title')),
- ('monthly_pay', models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True, verbose_name='monthly pay')),
- ('vacation_money', models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True, verbose_name='vacation money')),
- ('other_expenses', models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True, verbose_name='other expenses')),
- ('working_hours', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True, verbose_name='working hour')),
- ('collective_bargaining_agreement', models.CharField(blank=True, max_length=64, verbose_name='collective bargaining agreement')),
- ('is_living_in_helsinki', models.BooleanField(default=False, verbose_name='is living in helsinki')),
- ('commission_amount', models.DecimalField(blank=True, decimal_places=2, max_digits=7, null=True, verbose_name='amount of the commission (eur)')),
- ('commission_description', models.CharField(blank=True, max_length=256, verbose_name='Description of the commission')),
- ('history_id', models.AutoField(primary_key=True, serialize=False)),
- ('history_date', models.DateTimeField(db_index=True)),
- ('history_change_reason', models.CharField(max_length=100, null=True)),
- ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
- ('application', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='applications.application', verbose_name='application')),
- ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
+ (
+ "created_at",
+ models.DateTimeField(
+ blank=True, editable=False, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(
+ blank=True, editable=False, verbose_name="time modified"
+ ),
+ ),
+ (
+ "id",
+ models.UUIDField(db_index=True, default=uuid.uuid4, editable=False),
+ ),
+ (
+ "encrypted_first_name",
+ encrypted_fields.fields.EncryptedCharField(
+ blank=True, max_length=128, verbose_name="first name"
+ ),
+ ),
+ (
+ "encrypted_last_name",
+ encrypted_fields.fields.EncryptedCharField(
+ blank=True, max_length=128, verbose_name="last name"
+ ),
+ ),
+ (
+ "first_name",
+ encrypted_fields.fields.SearchField(
+ blank=True,
+ db_index=True,
+ encrypted_field_name="encrypted_first_name",
+ hash_key="02c5b8605cd4f9c188eee422209069b7bd3a607f0ae0a166eab0da223d1b6735",
+ max_length=66,
+ null=True,
+ ),
+ ),
+ (
+ "last_name",
+ encrypted_fields.fields.SearchField(
+ blank=True,
+ db_index=True,
+ encrypted_field_name="encrypted_last_name",
+ hash_key="af1b5a67d11197865a731c26bf9659716b9ded71c2802b4363856fe613b6b527",
+ max_length=66,
+ null=True,
+ ),
+ ),
+ (
+ "encrypted_social_security_number",
+ encrypted_fields.fields.EncryptedCharField(
+ blank=True, max_length=11, verbose_name="social security number"
+ ),
+ ),
+ (
+ "social_security_number",
+ encrypted_fields.fields.SearchField(
+ blank=True,
+ db_index=True,
+ encrypted_field_name="encrypted_social_security_number",
+ hash_key="ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669",
+ max_length=66,
+ null=True,
+ ),
+ ),
+ (
+ "phone_number",
+ phonenumber_field.modelfields.PhoneNumberField(
+ blank=True,
+ max_length=128,
+ region=None,
+ verbose_name="phone number",
+ ),
+ ),
+ (
+ "email",
+ models.EmailField(blank=True, max_length=254, verbose_name="email"),
+ ),
+ (
+ "employee_language",
+ models.CharField(
+ blank=True,
+ choices=[("fi", "suomi"), ("sv", "svenska"), ("en", "english")],
+ default="fi",
+ max_length=2,
+ ),
+ ),
+ (
+ "job_title",
+ models.CharField(
+ blank=True, max_length=128, verbose_name="job title"
+ ),
+ ),
+ (
+ "monthly_pay",
+ models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=7,
+ null=True,
+ verbose_name="monthly pay",
+ ),
+ ),
+ (
+ "vacation_money",
+ models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=7,
+ null=True,
+ verbose_name="vacation money",
+ ),
+ ),
+ (
+ "other_expenses",
+ models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=7,
+ null=True,
+ verbose_name="other expenses",
+ ),
+ ),
+ (
+ "working_hours",
+ models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=5,
+ null=True,
+ verbose_name="working hour",
+ ),
+ ),
+ (
+ "collective_bargaining_agreement",
+ models.CharField(
+ blank=True,
+ max_length=64,
+ verbose_name="collective bargaining agreement",
+ ),
+ ),
+ (
+ "is_living_in_helsinki",
+ models.BooleanField(
+ default=False, verbose_name="is living in helsinki"
+ ),
+ ),
+ (
+ "commission_amount",
+ models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=7,
+ null=True,
+ verbose_name="amount of the commission (eur)",
+ ),
+ ),
+ (
+ "commission_description",
+ models.CharField(
+ blank=True,
+ max_length=256,
+ verbose_name="Description of the commission",
+ ),
+ ),
+ ("history_id", models.AutoField(primary_key=True, serialize=False)),
+ ("history_date", models.DateTimeField(db_index=True)),
+ ("history_change_reason", models.CharField(max_length=100, null=True)),
+ (
+ "history_type",
+ models.CharField(
+ choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
+ max_length=1,
+ ),
+ ),
+ (
+ "application",
+ models.ForeignKey(
+ blank=True,
+ db_constraint=False,
+ null=True,
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ related_name="+",
+ to="applications.application",
+ verbose_name="application",
+ ),
+ ),
+ (
+ "history_user",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
],
options={
- 'verbose_name': 'historical employee',
- 'verbose_name_plural': 'historical employees',
- 'db_table': 'bf_applications_employee_history',
- 'ordering': ('-history_date', '-history_id'),
- 'get_latest_by': ('history_date', 'history_id'),
+ "verbose_name": "historical employee",
+ "verbose_name_plural": "historical employees",
+ "db_table": "bf_applications_employee_history",
+ "ordering": ("-history_date", "-history_id"),
+ "get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
diff --git a/backend/benefit/applications/migrations/0050_add_rejected_by_talpa_status.py b/backend/benefit/applications/migrations/0050_add_rejected_by_talpa_status.py
index 1761c396f2..f670beb0fa 100644
--- a/backend/benefit/applications/migrations/0050_add_rejected_by_talpa_status.py
+++ b/backend/benefit/applications/migrations/0050_add_rejected_by_talpa_status.py
@@ -4,40 +4,133 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0049_historicalemployee'),
+ ("applications", "0049_historicalemployee"),
]
operations = [
migrations.AlterField(
- model_name='application',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('rejected_by_talpa', 'Rejected by Talpa')], default='draft', max_length=64, verbose_name='status'),
+ model_name="application",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status",
+ ),
),
migrations.AlterField(
- model_name='applicationlogentry',
- name='from_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('rejected_by_talpa', 'Rejected by Talpa')], max_length=64),
+ model_name="applicationlogentry",
+ name="from_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='applicationlogentry',
- name='to_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('rejected_by_talpa', 'Rejected by Talpa')], max_length=64),
+ model_name="applicationlogentry",
+ name="to_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='historicalapplication',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('rejected_by_talpa', 'Rejected by Talpa')], default='draft', max_length=64, verbose_name='status'),
+ model_name="historicalapplication",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status",
+ ),
),
migrations.AlterField(
- model_name='historicalapplicationlogentry',
- name='from_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('rejected_by_talpa', 'Rejected by Talpa')], max_length=64),
+ model_name="historicalapplicationlogentry",
+ name="from_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='historicalapplicationlogentry',
- name='to_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('rejected_by_talpa', 'Rejected by Talpa')], max_length=64),
+ model_name="historicalapplicationlogentry",
+ name="to_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ max_length=64,
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0051_alter_applicationbatch_status.py b/backend/benefit/applications/migrations/0051_alter_applicationbatch_status.py
index de75b331b3..ad6fd457fd 100644
--- a/backend/benefit/applications/migrations/0051_alter_applicationbatch_status.py
+++ b/backend/benefit/applications/migrations/0051_alter_applicationbatch_status.py
@@ -4,15 +4,32 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0050_add_rejected_by_talpa_status'),
+ ("applications", "0050_add_rejected_by_talpa_status"),
]
operations = [
migrations.AlterField(
- model_name='applicationbatch',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('exported_ahjo_report', 'Ahjo report created, not yet sent to AHJO'), ('awaiting_ahjo_decision', 'Sent to Ahjo, decision pending'), ('accepted', 'Accepted in Ahjo'), ('rejected', 'Rejected in Ahjo'), ('returned', 'Returned from Ahjo without decision'), ('sent_to_talpa', 'Sent to Talpa'), ('completed', 'Processing is completed'), ('rejected_by_talpa', 'Rejected by Talpa')], default='draft', max_length=64, verbose_name='status of batch'),
+ model_name="applicationbatch",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ (
+ "exported_ahjo_report",
+ "Ahjo report created, not yet sent to AHJO",
+ ),
+ ("awaiting_ahjo_decision", "Sent to Ahjo, decision pending"),
+ ("accepted", "Accepted in Ahjo"),
+ ("rejected", "Rejected in Ahjo"),
+ ("returned", "Returned from Ahjo without decision"),
+ ("sent_to_talpa", "Sent to Talpa"),
+ ("completed", "Processing is completed"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status of batch",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0052_application_talpa_status.py b/backend/benefit/applications/migrations/0052_application_talpa_status.py
index 3cdbd579b5..93c39b15a4 100644
--- a/backend/benefit/applications/migrations/0052_application_talpa_status.py
+++ b/backend/benefit/applications/migrations/0052_application_talpa_status.py
@@ -4,50 +4,155 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0051_alter_applicationbatch_status'),
+ ("applications", "0051_alter_applicationbatch_status"),
]
operations = [
migrations.AddField(
- model_name='application',
- name='talpa_status',
- field=models.CharField(choices=[('not_sent_to_talpa', 'Not sent to Talpa'), ('rejected_by_talpa', 'Rejected by Talpa'), ('successfully_sent_to_talpa', 'Successfully sent to Talpa')], default='not_sent_to_talpa', max_length=64, verbose_name='talpa_status'),
+ model_name="application",
+ name="talpa_status",
+ field=models.CharField(
+ choices=[
+ ("not_sent_to_talpa", "Not sent to Talpa"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ("successfully_sent_to_talpa", "Successfully sent to Talpa"),
+ ],
+ default="not_sent_to_talpa",
+ max_length=64,
+ verbose_name="talpa_status",
+ ),
),
migrations.AddField(
- model_name='historicalapplication',
- name='talpa_status',
- field=models.CharField(choices=[('not_sent_to_talpa', 'Not sent to Talpa'), ('rejected_by_talpa', 'Rejected by Talpa'), ('successfully_sent_to_talpa', 'Successfully sent to Talpa')], default='not_sent_to_talpa', max_length=64, verbose_name='talpa_status'),
+ model_name="historicalapplication",
+ name="talpa_status",
+ field=models.CharField(
+ choices=[
+ ("not_sent_to_talpa", "Not sent to Talpa"),
+ ("rejected_by_talpa", "Rejected by Talpa"),
+ ("successfully_sent_to_talpa", "Successfully sent to Talpa"),
+ ],
+ default="not_sent_to_talpa",
+ max_length=64,
+ verbose_name="talpa_status",
+ ),
),
migrations.AlterField(
- model_name='application',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected')], default='draft', max_length=64, verbose_name='status'),
+ model_name="application",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status",
+ ),
),
migrations.AlterField(
- model_name='applicationlogentry',
- name='from_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected')], max_length=64),
+ model_name="applicationlogentry",
+ name="from_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='applicationlogentry',
- name='to_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected')], max_length=64),
+ model_name="applicationlogentry",
+ name="to_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='historicalapplication',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected')], default='draft', max_length=64, verbose_name='status'),
+ model_name="historicalapplication",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status",
+ ),
),
migrations.AlterField(
- model_name='historicalapplicationlogentry',
- name='from_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected')], max_length=64),
+ model_name="historicalapplicationlogentry",
+ name="from_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='historicalapplicationlogentry',
- name='to_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected')], max_length=64),
+ model_name="historicalapplicationlogentry",
+ name="to_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ],
+ max_length=64,
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0053_historicalattachment.py b/backend/benefit/applications/migrations/0053_historicalattachment.py
index fd07987b92..2b8cfcb4b3 100644
--- a/backend/benefit/applications/migrations/0053_historicalattachment.py
+++ b/backend/benefit/applications/migrations/0053_historicalattachment.py
@@ -1,42 +1,115 @@
# Generated by Django 3.2.23 on 2023-12-28 21:40
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0052_application_talpa_status'),
+ ("applications", "0052_application_talpa_status"),
]
operations = [
migrations.CreateModel(
- name='HistoricalAttachment',
+ name="HistoricalAttachment",
fields=[
- ('created_at', models.DateTimeField(blank=True, editable=False, verbose_name='time created')),
- ('modified_at', models.DateTimeField(blank=True, editable=False, verbose_name='time modified')),
- ('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)),
- ('attachment_type', models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment')], max_length=64, verbose_name='attachment type in business rules')),
- ('content_type', models.CharField(choices=[('application/pdf', 'pdf'), ('image/png', 'png'), ('image/jpeg', 'jpeg')], max_length=100, verbose_name='technical content type of the attachment')),
- ('attachment_file', models.TextField(max_length=100, verbose_name='application attachment content')),
- ('history_id', models.AutoField(primary_key=True, serialize=False)),
- ('history_date', models.DateTimeField(db_index=True)),
- ('history_change_reason', models.CharField(max_length=100, null=True)),
- ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
- ('application', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='applications.application', verbose_name='application')),
- ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
+ (
+ "created_at",
+ models.DateTimeField(
+ blank=True, editable=False, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(
+ blank=True, editable=False, verbose_name="time modified"
+ ),
+ ),
+ (
+ "id",
+ models.UUIDField(db_index=True, default=uuid.uuid4, editable=False),
+ ),
+ (
+ "attachment_type",
+ models.CharField(
+ choices=[
+ ("employment_contract", "employment contract"),
+ ("pay_subsidy_decision", "pay subsidy decision"),
+ ("commission_contract", "commission contract"),
+ (
+ "education_contract",
+ "education contract of the apprenticeship office",
+ ),
+ ("helsinki_benefit_voucher", "helsinki benefit voucher"),
+ ("employee_consent", "employee consent"),
+ ("full_application", "full application"),
+ ("other_attachment", "other attachment"),
+ ],
+ max_length=64,
+ verbose_name="attachment type in business rules",
+ ),
+ ),
+ (
+ "content_type",
+ models.CharField(
+ choices=[
+ ("application/pdf", "pdf"),
+ ("image/png", "png"),
+ ("image/jpeg", "jpeg"),
+ ],
+ max_length=100,
+ verbose_name="technical content type of the attachment",
+ ),
+ ),
+ (
+ "attachment_file",
+ models.TextField(
+ max_length=100, verbose_name="application attachment content"
+ ),
+ ),
+ ("history_id", models.AutoField(primary_key=True, serialize=False)),
+ ("history_date", models.DateTimeField(db_index=True)),
+ ("history_change_reason", models.CharField(max_length=100, null=True)),
+ (
+ "history_type",
+ models.CharField(
+ choices=[("+", "Created"), ("~", "Changed"), ("-", "Deleted")],
+ max_length=1,
+ ),
+ ),
+ (
+ "application",
+ models.ForeignKey(
+ blank=True,
+ db_constraint=False,
+ null=True,
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ related_name="+",
+ to="applications.application",
+ verbose_name="application",
+ ),
+ ),
+ (
+ "history_user",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
],
options={
- 'verbose_name': 'historical attachment',
- 'verbose_name_plural': 'historical attachments',
- 'db_table': 'bf_applications_attachment_history',
- 'ordering': ('-history_date', '-history_id'),
- 'get_latest_by': ('history_date', 'history_id'),
+ "verbose_name": "historical attachment",
+ "verbose_name_plural": "historical attachments",
+ "db_table": "bf_applications_attachment_history",
+ "ordering": ("-history_date", "-history_id"),
+ "get_latest_by": ("history_date", "history_id"),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
diff --git a/backend/benefit/applications/migrations/0054_alter_historicalattachment_attachment_type.py b/backend/benefit/applications/migrations/0054_alter_historicalattachment_attachment_type.py
index 42111ec1a3..da3e3da961 100644
--- a/backend/benefit/applications/migrations/0054_alter_historicalattachment_attachment_type.py
+++ b/backend/benefit/applications/migrations/0054_alter_historicalattachment_attachment_type.py
@@ -4,15 +4,31 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0053_historicalattachment'),
+ ("applications", "0053_historicalattachment"),
]
operations = [
migrations.AlterField(
- model_name='historicalattachment',
- name='attachment_type',
- field=models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment'), ('pdf_summary', 'pdf summary')], max_length=64, verbose_name='attachment type in business rules'),
+ model_name="historicalattachment",
+ name="attachment_type",
+ field=models.CharField(
+ choices=[
+ ("employment_contract", "employment contract"),
+ ("pay_subsidy_decision", "pay subsidy decision"),
+ ("commission_contract", "commission contract"),
+ (
+ "education_contract",
+ "education contract of the apprenticeship office",
+ ),
+ ("helsinki_benefit_voucher", "helsinki benefit voucher"),
+ ("employee_consent", "employee consent"),
+ ("full_application", "full application"),
+ ("other_attachment", "other attachment"),
+ ("pdf_summary", "pdf summary"),
+ ],
+ max_length=64,
+ verbose_name="attachment type in business rules",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0055_add_attachment_version_id_and_hash_20240131_1620.py b/backend/benefit/applications/migrations/0055_add_attachment_version_id_and_hash_20240131_1620.py
index 338373312e..e8640259b7 100644
--- a/backend/benefit/applications/migrations/0055_add_attachment_version_id_and_hash_20240131_1620.py
+++ b/backend/benefit/applications/migrations/0055_add_attachment_version_id_and_hash_20240131_1620.py
@@ -4,30 +4,29 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0054_alter_historicalattachment_attachment_type'),
+ ("applications", "0054_alter_historicalattachment_attachment_type"),
]
operations = [
migrations.AddField(
- model_name='attachment',
- name='ahjo_hash_value',
+ model_name="attachment",
+ name="ahjo_hash_value",
field=models.CharField(blank=True, max_length=64, null=True),
),
migrations.AddField(
- model_name='attachment',
- name='ahjo_version_series_id',
+ model_name="attachment",
+ name="ahjo_version_series_id",
field=models.CharField(blank=True, max_length=64, null=True),
),
migrations.AddField(
- model_name='historicalattachment',
- name='ahjo_hash_value',
+ model_name="historicalattachment",
+ name="ahjo_hash_value",
field=models.CharField(blank=True, max_length=64, null=True),
),
migrations.AddField(
- model_name='historicalattachment',
- name='ahjo_version_series_id',
+ model_name="historicalattachment",
+ name="ahjo_version_series_id",
field=models.CharField(blank=True, max_length=64, null=True),
),
]
diff --git a/backend/benefit/applications/migrations/0056_decisionproposaltemplatesection.py b/backend/benefit/applications/migrations/0056_decisionproposaltemplatesection.py
index c5fbe36256..83ee532019 100644
--- a/backend/benefit/applications/migrations/0056_decisionproposaltemplatesection.py
+++ b/backend/benefit/applications/migrations/0056_decisionproposaltemplatesection.py
@@ -1,32 +1,100 @@
# Generated by Django 3.2.23 on 2024-02-14 08:57
-from django.db import migrations, models
import uuid
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0055_add_attachment_version_id_and_hash_20240131_1620'),
+ ("applications", "0055_add_attachment_version_id_and_hash_20240131_1620"),
]
operations = [
migrations.CreateModel(
- name='DecisionProposalTemplateSection',
+ name="DecisionProposalTemplateSection",
fields=[
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
- ('section_type', models.CharField(choices=[('decision_section', 'Template part for the decision section of a application decision proposal'), ('justification_section', 'Template part for the decision justification section of a decision proposal')], default='decision_section', max_length=64, verbose_name='type of the decision proposal template section')),
- ('decision_type', models.CharField(choices=[('accepted_decision', 'An accepted decision'), ('denied_decision', 'A denied decision')], default='accepted_decision', max_length=64, verbose_name='type of the decision')),
- ('language', models.CharField(choices=[('fi', 'suomi'), ('sv', 'svenska'), ('en', 'english')], default='fi', max_length=2)),
- ('template_text', models.TextField(verbose_name='decision proposal section text content')),
- ('name', models.CharField(max_length=256, verbose_name='name of the decision proposal template section')),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "section_type",
+ models.CharField(
+ choices=[
+ (
+ "decision_section",
+ (
+ "Template part for the decision section of a"
+ " application decision proposal"
+ ),
+ ),
+ (
+ "justification_section",
+ (
+ "Template part for the decision justification"
+ " section of a decision proposal"
+ ),
+ ),
+ ],
+ default="decision_section",
+ max_length=64,
+ verbose_name="type of the decision proposal template section",
+ ),
+ ),
+ (
+ "decision_type",
+ models.CharField(
+ choices=[
+ ("accepted_decision", "An accepted decision"),
+ ("denied_decision", "A denied decision"),
+ ],
+ default="accepted_decision",
+ max_length=64,
+ verbose_name="type of the decision",
+ ),
+ ),
+ (
+ "language",
+ models.CharField(
+ choices=[("fi", "suomi"), ("sv", "svenska"), ("en", "english")],
+ default="fi",
+ max_length=2,
+ ),
+ ),
+ (
+ "template_text",
+ models.TextField(
+ verbose_name="decision proposal section text content"
+ ),
+ ),
+ (
+ "name",
+ models.CharField(
+ max_length=256,
+ verbose_name="name of the decision proposal template section",
+ ),
+ ),
],
options={
- 'verbose_name': 'decision proposal template section',
- 'verbose_name_plural': 'decision proposal template sections',
- 'db_table': 'bf_applications_decision_proposal_template_section',
+ "verbose_name": "decision proposal template section",
+ "verbose_name_plural": "decision proposal template sections",
+ "db_table": "bf_applications_decision_proposal_template_section",
},
),
]
diff --git a/backend/benefit/applications/migrations/0057_attachment_type_decision_text.py b/backend/benefit/applications/migrations/0057_attachment_type_decision_text.py
index 8deac8cfb1..0007f7d85f 100644
--- a/backend/benefit/applications/migrations/0057_attachment_type_decision_text.py
+++ b/backend/benefit/applications/migrations/0057_attachment_type_decision_text.py
@@ -1,42 +1,130 @@
# Generated by Django 3.2.23 on 2024-02-14 10:34
-from django.db import migrations, models
-import django.db.models.deletion
import uuid
+import django.db.models.deletion
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0056_decisionproposaltemplatesection'),
+ ("applications", "0056_decisionproposaltemplatesection"),
]
operations = [
migrations.AlterField(
- model_name='attachment',
- name='attachment_type',
- field=models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment'), ('pdf_summary', 'pdf summary'), ('decision_text_xml', 'public decision text xml attachment'), ('decision_text_secret_xml', 'non-public decision text xml attachment')], max_length=64, verbose_name='attachment type in business rules'),
+ model_name="attachment",
+ name="attachment_type",
+ field=models.CharField(
+ choices=[
+ ("employment_contract", "employment contract"),
+ ("pay_subsidy_decision", "pay subsidy decision"),
+ ("commission_contract", "commission contract"),
+ (
+ "education_contract",
+ "education contract of the apprenticeship office",
+ ),
+ ("helsinki_benefit_voucher", "helsinki benefit voucher"),
+ ("employee_consent", "employee consent"),
+ ("full_application", "full application"),
+ ("other_attachment", "other attachment"),
+ ("pdf_summary", "pdf summary"),
+ ("decision_text_xml", "public decision text xml attachment"),
+ (
+ "decision_text_secret_xml",
+ "non-public decision text xml attachment",
+ ),
+ ],
+ max_length=64,
+ verbose_name="attachment type in business rules",
+ ),
),
migrations.AlterField(
- model_name='historicalattachment',
- name='attachment_type',
- field=models.CharField(choices=[('employment_contract', 'employment contract'), ('pay_subsidy_decision', 'pay subsidy decision'), ('commission_contract', 'commission contract'), ('education_contract', 'education contract of the apprenticeship office'), ('helsinki_benefit_voucher', 'helsinki benefit voucher'), ('employee_consent', 'employee consent'), ('full_application', 'full application'), ('other_attachment', 'other attachment'), ('pdf_summary', 'pdf summary'), ('decision_text_xml', 'public decision text xml attachment'), ('decision_text_secret_xml', 'non-public decision text xml attachment')], max_length=64, verbose_name='attachment type in business rules'),
+ model_name="historicalattachment",
+ name="attachment_type",
+ field=models.CharField(
+ choices=[
+ ("employment_contract", "employment contract"),
+ ("pay_subsidy_decision", "pay subsidy decision"),
+ ("commission_contract", "commission contract"),
+ (
+ "education_contract",
+ "education contract of the apprenticeship office",
+ ),
+ ("helsinki_benefit_voucher", "helsinki benefit voucher"),
+ ("employee_consent", "employee consent"),
+ ("full_application", "full application"),
+ ("other_attachment", "other attachment"),
+ ("pdf_summary", "pdf summary"),
+ ("decision_text_xml", "public decision text xml attachment"),
+ (
+ "decision_text_secret_xml",
+ "non-public decision text xml attachment",
+ ),
+ ],
+ max_length=64,
+ verbose_name="attachment type in business rules",
+ ),
),
migrations.CreateModel(
- name='AhjoDecisionText',
+ name="AhjoDecisionText",
fields=[
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
- ('decision_type', models.CharField(choices=[('accepted_decision', 'An accepted decision'), ('denied_decision', 'A denied decision')], default='accepted_decision', max_length=64, verbose_name='type of the decision')),
- ('language', models.CharField(choices=[('fi', 'suomi'), ('sv', 'svenska'), ('en', 'english')], default='fi', max_length=2)),
- ('decision_text', models.TextField(verbose_name='decision text content')),
- ('application', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='applications.application', verbose_name='application')),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "decision_type",
+ models.CharField(
+ choices=[
+ ("accepted_decision", "An accepted decision"),
+ ("denied_decision", "A denied decision"),
+ ],
+ default="accepted_decision",
+ max_length=64,
+ verbose_name="type of the decision",
+ ),
+ ),
+ (
+ "language",
+ models.CharField(
+ choices=[("fi", "suomi"), ("sv", "svenska"), ("en", "english")],
+ default="fi",
+ max_length=2,
+ ),
+ ),
+ (
+ "decision_text",
+ models.TextField(verbose_name="decision text content"),
+ ),
+ (
+ "application",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.CASCADE,
+ to="applications.application",
+ verbose_name="application",
+ ),
+ ),
],
options={
- 'verbose_name': 'ahjo decision text',
- 'verbose_name_plural': 'ahjo decision texts',
- 'db_table': 'bf_applications_ahjo_decision_text',
+ "verbose_name": "ahjo decision text",
+ "verbose_name_plural": "ahjo decision texts",
+ "db_table": "bf_applications_ahjo_decision_text",
},
),
]
diff --git a/backend/benefit/applications/migrations/0058_alter_historicalapplication_history_change_reason.py b/backend/benefit/applications/migrations/0058_alter_historicalapplication_history_change_reason.py
index f9017a3c72..a88d14180e 100644
--- a/backend/benefit/applications/migrations/0058_alter_historicalapplication_history_change_reason.py
+++ b/backend/benefit/applications/migrations/0058_alter_historicalapplication_history_change_reason.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0057_attachment_type_decision_text"),
]
diff --git a/backend/benefit/applications/migrations/0059_applicationalteration.py b/backend/benefit/applications/migrations/0059_applicationalteration.py
index a6bfb49772..cfcb278279 100644
--- a/backend/benefit/applications/migrations/0059_applicationalteration.py
+++ b/backend/benefit/applications/migrations/0059_applicationalteration.py
@@ -1,38 +1,134 @@
# Generated by Django 3.2.23 on 2024-02-22 08:04
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0058_alter_historicalapplication_history_change_reason'),
+ ("applications", "0058_alter_historicalapplication_history_change_reason"),
]
operations = [
migrations.CreateModel(
- name='ApplicationAlteration',
+ name="ApplicationAlteration",
fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('alteration_type', models.TextField(choices=[('termination', 'Termination'), ('suspension', 'Suspension')], verbose_name='type of alteration')),
- ('end_date', models.DateField(verbose_name='new benefit end date')),
- ('resume_date', models.DateField(blank=True, null=True, verbose_name='date when employment resumes after suspended')),
- ('reason', models.TextField(verbose_name='reason for alteration')),
- ('handled_at', models.DateField(blank=True, null=True, verbose_name='date when alteration notice was handled')),
- ('recovery_start_date', models.DateField(blank=True, null=True, verbose_name='the first day the unwarranted benefit will be collected from')),
- ('recovery_end_date', models.DateField(blank=True, null=True, verbose_name='the last day the unwarranted benefit will be collected from')),
- ('recovery_amount', models.DecimalField(decimal_places=2, max_digits=8, null=True, verbose_name='amount of unwarranted benefit to be collected')),
- ('use_alternate_einvoice_provider', models.BooleanField(default=False, verbose_name='whether to use a separate e-invoice address from the one of the applicant organization')),
- ('einvoice_provider_name', models.TextField(blank=True, verbose_name='name of the e-invoice provider')),
- ('einvoice_provider_identifier', models.TextField(blank=True, verbose_name='identifier of the e-invoice provider')),
- ('einvoice_address', models.TextField(blank=True, verbose_name='e-invoice address')),
- ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='alteration_set', to='applications.application', verbose_name='alteration of application')),
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ (
+ "alteration_type",
+ models.TextField(
+ choices=[
+ ("termination", "Termination"),
+ ("suspension", "Suspension"),
+ ],
+ verbose_name="type of alteration",
+ ),
+ ),
+ ("end_date", models.DateField(verbose_name="new benefit end date")),
+ (
+ "resume_date",
+ models.DateField(
+ blank=True,
+ null=True,
+ verbose_name="date when employment resumes after suspended",
+ ),
+ ),
+ ("reason", models.TextField(verbose_name="reason for alteration")),
+ (
+ "handled_at",
+ models.DateField(
+ blank=True,
+ null=True,
+ verbose_name="date when alteration notice was handled",
+ ),
+ ),
+ (
+ "recovery_start_date",
+ models.DateField(
+ blank=True,
+ null=True,
+ verbose_name=(
+ "the first day the unwarranted benefit will be collected"
+ " from"
+ ),
+ ),
+ ),
+ (
+ "recovery_end_date",
+ models.DateField(
+ blank=True,
+ null=True,
+ verbose_name=(
+ "the last day the unwarranted benefit will be collected"
+ " from"
+ ),
+ ),
+ ),
+ (
+ "recovery_amount",
+ models.DecimalField(
+ decimal_places=2,
+ max_digits=8,
+ null=True,
+ verbose_name="amount of unwarranted benefit to be collected",
+ ),
+ ),
+ (
+ "use_alternate_einvoice_provider",
+ models.BooleanField(
+ default=False,
+ verbose_name=(
+ "whether to use a separate e-invoice address from the one"
+ " of the applicant organization"
+ ),
+ ),
+ ),
+ (
+ "einvoice_provider_name",
+ models.TextField(
+ blank=True, verbose_name="name of the e-invoice provider"
+ ),
+ ),
+ (
+ "einvoice_provider_identifier",
+ models.TextField(
+ blank=True, verbose_name="identifier of the e-invoice provider"
+ ),
+ ),
+ (
+ "einvoice_address",
+ models.TextField(blank=True, verbose_name="e-invoice address"),
+ ),
+ (
+ "application",
+ models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="alteration_set",
+ to="applications.application",
+ verbose_name="alteration of application",
+ ),
+ ),
],
options={
- 'abstract': False,
+ "abstract": False,
},
),
]
diff --git a/backend/benefit/applications/migrations/0060_applicationalteration_state.py b/backend/benefit/applications/migrations/0060_applicationalteration_state.py
index d512b46c0c..779ab68081 100644
--- a/backend/benefit/applications/migrations/0060_applicationalteration_state.py
+++ b/backend/benefit/applications/migrations/0060_applicationalteration_state.py
@@ -4,15 +4,22 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0059_applicationalteration'),
+ ("applications", "0059_applicationalteration"),
]
operations = [
migrations.AddField(
- model_name='applicationalteration',
- name='state',
- field=models.TextField(choices=[('received', 'Received'), ('opened', 'Opened'), ('handled', 'Handled')], default='received', verbose_name='state of alteration'),
+ model_name="applicationalteration",
+ name="state",
+ field=models.TextField(
+ choices=[
+ ("received", "Received"),
+ ("opened", "Opened"),
+ ("handled", "Handled"),
+ ],
+ default="received",
+ verbose_name="state of alteration",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0061_auto_20240312_1150.py b/backend/benefit/applications/migrations/0061_auto_20240312_1150.py
index 3dcc61919d..0dc4a9f577 100644
--- a/backend/benefit/applications/migrations/0061_auto_20240312_1150.py
+++ b/backend/benefit/applications/migrations/0061_auto_20240312_1150.py
@@ -5,28 +5,34 @@
class Migration(migrations.Migration):
dependencies = [
- ('applications', '0060_applicationalteration_state'),
+ ("applications", "0060_applicationalteration_state"),
]
operations = [
migrations.RenameField(
- model_name='applicationalteration',
- old_name='use_alternate_einvoice_provider',
- new_name='use_einvoice',
+ model_name="applicationalteration",
+ old_name="use_alternate_einvoice_provider",
+ new_name="use_einvoice",
),
migrations.AlterField(
- model_name='applicationalteration',
- name='reason',
- field=models.TextField(blank=True, verbose_name='reason for alteration'),
+ model_name="applicationalteration",
+ name="reason",
+ field=models.TextField(blank=True, verbose_name="reason for alteration"),
),
migrations.AlterField(
- model_name='applicationalteration',
- name='use_einvoice',
- field=models.BooleanField(default=False, verbose_name='whether to use handle billing with an e-invoice instead of a bill sent to a physical address'),
+ model_name="applicationalteration",
+ name="use_einvoice",
+ field=models.BooleanField(
+ default=False,
+ verbose_name=(
+ "whether to use handle billing with an e-invoice instead of a bill"
+ " sent to a physical address"
+ ),
+ ),
),
migrations.AddField(
- model_name='applicationalteration',
- name='contact_person_name',
- field=models.TextField(verbose_name='contact person'),
+ model_name="applicationalteration",
+ name="contact_person_name",
+ field=models.TextField(verbose_name="contact person"),
),
]
diff --git a/backend/benefit/applications/migrations/0062_alter_applicationalteration_recovery_amount.py b/backend/benefit/applications/migrations/0062_alter_applicationalteration_recovery_amount.py
index 8fc995c8af..ba83144c4d 100644
--- a/backend/benefit/applications/migrations/0062_alter_applicationalteration_recovery_amount.py
+++ b/backend/benefit/applications/migrations/0062_alter_applicationalteration_recovery_amount.py
@@ -4,15 +4,20 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0061_auto_20240312_1150'),
+ ("applications", "0061_auto_20240312_1150"),
]
operations = [
migrations.AlterField(
- model_name='applicationalteration',
- name='recovery_amount',
- field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='amount of unwarranted benefit to be collected'),
+ model_name="applicationalteration",
+ name="recovery_amount",
+ field=models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=8,
+ null=True,
+ verbose_name="amount of unwarranted benefit to be collected",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0063_decision_proposal_template_changes.py b/backend/benefit/applications/migrations/0063_decision_proposal_template_changes.py
index 281aaa885d..b86bdc25ed 100644
--- a/backend/benefit/applications/migrations/0063_decision_proposal_template_changes.py
+++ b/backend/benefit/applications/migrations/0063_decision_proposal_template_changes.py
@@ -1,11 +1,9 @@
# Generated by Django 3.2.23 on 2024-04-09 12:02
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0062_alter_applicationalteration_recovery_amount"),
]
diff --git a/backend/benefit/applications/migrations/0064_decision_proposal_drafts.py b/backend/benefit/applications/migrations/0064_decision_proposal_drafts.py
index 68462de546..c73011d016 100644
--- a/backend/benefit/applications/migrations/0064_decision_proposal_drafts.py
+++ b/backend/benefit/applications/migrations/0064_decision_proposal_drafts.py
@@ -1,35 +1,112 @@
# Generated by Django 3.2.23 on 2024-04-09 12:02
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0063_decision_proposal_template_changes"),
]
operations = [
migrations.CreateModel(
- name='AhjoDecisionProposalDraft',
+ name="AhjoDecisionProposalDraft",
fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('review_step', models.CharField(blank=True, choices=[(1, 'step 1'), (2, 'step 2'), (3, 'step 3'), (4, 'submitted')], default=1, max_length=64, null=True, verbose_name='step of the draft proposal')),
- ('status', models.CharField(blank=True, choices=[('accepted', 'accepted'), ('rejected', 'rejected')], max_length=64, null=True, verbose_name='Proposal status')),
- ('log_entry_comment', models.TextField(blank=True, null=True, verbose_name='Log entry comment')),
- ('granted_as_de_minimis_aid', models.BooleanField(default=False, null=True)),
- ('handler_role', models.CharField(blank=True, choices=[('handler', 'Helsinki-benefit handler'), ('manager', 'Team manager')], max_length=64, null=True, verbose_name='Handler role')),
- ('decision_text', models.TextField(blank=True, null=True, verbose_name='Decision text content')),
- ('justification_text', models.TextField(blank=True, null=True, verbose_name='Justification text content')),
- ('application', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='decision_proposal_draft', to='applications.application', verbose_name='application')),
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ (
+ "review_step",
+ models.CharField(
+ blank=True,
+ choices=[
+ (1, "step 1"),
+ (2, "step 2"),
+ (3, "step 3"),
+ (4, "submitted"),
+ ],
+ default=1,
+ max_length=64,
+ null=True,
+ verbose_name="step of the draft proposal",
+ ),
+ ),
+ (
+ "status",
+ models.CharField(
+ blank=True,
+ choices=[("accepted", "accepted"), ("rejected", "rejected")],
+ max_length=64,
+ null=True,
+ verbose_name="Proposal status",
+ ),
+ ),
+ (
+ "log_entry_comment",
+ models.TextField(
+ blank=True, null=True, verbose_name="Log entry comment"
+ ),
+ ),
+ (
+ "granted_as_de_minimis_aid",
+ models.BooleanField(default=False, null=True),
+ ),
+ (
+ "handler_role",
+ models.CharField(
+ blank=True,
+ choices=[
+ ("handler", "Helsinki-benefit handler"),
+ ("manager", "Team manager"),
+ ],
+ max_length=64,
+ null=True,
+ verbose_name="Handler role",
+ ),
+ ),
+ (
+ "decision_text",
+ models.TextField(
+ blank=True, null=True, verbose_name="Decision text content"
+ ),
+ ),
+ (
+ "justification_text",
+ models.TextField(
+ blank=True, null=True, verbose_name="Justification text content"
+ ),
+ ),
+ (
+ "application",
+ models.OneToOneField(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="decision_proposal_draft",
+ to="applications.application",
+ verbose_name="application",
+ ),
+ ),
],
options={
- 'verbose_name': 'decision_proposal_draft',
- 'verbose_name_plural': 'decision_proposal_drafts',
- 'db_table': 'bf_applications_decision_proposal_draft',
+ "verbose_name": "decision_proposal_draft",
+ "verbose_name_plural": "decision_proposal_drafts",
+ "db_table": "bf_applications_decision_proposal_draft",
},
),
]
diff --git a/backend/benefit/applications/migrations/0065_downloaded_by_ahjo_timestamp.py b/backend/benefit/applications/migrations/0065_downloaded_by_ahjo_timestamp.py
index 75a0c2f856..135a7a7bd7 100644
--- a/backend/benefit/applications/migrations/0065_downloaded_by_ahjo_timestamp.py
+++ b/backend/benefit/applications/migrations/0065_downloaded_by_ahjo_timestamp.py
@@ -4,20 +4,19 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0064_decision_proposal_drafts'),
+ ("applications", "0064_decision_proposal_drafts"),
]
operations = [
migrations.AddField(
- model_name='attachment',
- name='downloaded_by_ahjo',
+ model_name="attachment",
+ name="downloaded_by_ahjo",
field=models.DateTimeField(blank=True, null=True),
),
migrations.AddField(
- model_name='historicalattachment',
- name='downloaded_by_ahjo',
+ model_name="historicalattachment",
+ name="downloaded_by_ahjo",
field=models.DateTimeField(blank=True, null=True),
),
]
diff --git a/backend/benefit/applications/migrations/0066_alter_ahjostatus_status.py b/backend/benefit/applications/migrations/0066_alter_ahjostatus_status.py
index a26c86e49d..80ea32945c 100644
--- a/backend/benefit/applications/migrations/0066_alter_ahjostatus_status.py
+++ b/backend/benefit/applications/migrations/0066_alter_ahjostatus_status.py
@@ -4,15 +4,38 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0065_downloaded_by_ahjo_timestamp'),
+ ("applications", "0065_downloaded_by_ahjo_timestamp"),
]
operations = [
migrations.AlterField(
- model_name='ahjostatus',
- name='status',
- field=models.CharField(choices=[('submitted_but_not_sent_to_ahjo', 'Submitted but not sent to AHJO'), ('request_to_open_case_sent', 'Request to open the case sent to AHJO'), ('case_opened', 'Case opened in AHJO'), ('update_request_sent', 'Update request sent'), ('update_request_received', 'Update request received'), ('decision_proposal_sent', 'Decision proposal sent'), ('decision_proposal_accepted', 'Decision proposal accepted'), ('decision_proposal_rejected', 'Decision proposal rejected'), ('delete_request_sent', 'Delete request sent'), ('delete_request_received', 'Delete request received'), ('new_record_request_sent', 'New record request sent'), ('new_record_received', 'New record received by Ahjo')], default='submitted_but_not_sent_to_ahjo', max_length=64, verbose_name='status'),
+ model_name="ahjostatus",
+ name="status",
+ field=models.CharField(
+ choices=[
+ (
+ "submitted_but_not_sent_to_ahjo",
+ "Submitted but not sent to AHJO",
+ ),
+ (
+ "request_to_open_case_sent",
+ "Request to open the case sent to AHJO",
+ ),
+ ("case_opened", "Case opened in AHJO"),
+ ("update_request_sent", "Update request sent"),
+ ("update_request_received", "Update request received"),
+ ("decision_proposal_sent", "Decision proposal sent"),
+ ("decision_proposal_accepted", "Decision proposal accepted"),
+ ("decision_proposal_rejected", "Decision proposal rejected"),
+ ("delete_request_sent", "Delete request sent"),
+ ("delete_request_received", "Delete request received"),
+ ("new_record_request_sent", "New record request sent"),
+ ("new_record_received", "New record received by Ahjo"),
+ ],
+ default="submitted_but_not_sent_to_ahjo",
+ max_length=64,
+ verbose_name="status",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0067_add_handler_to_application.py b/backend/benefit/applications/migrations/0067_add_handler_to_application.py
index f7afce3475..e1bc8c9106 100644
--- a/backend/benefit/applications/migrations/0067_add_handler_to_application.py
+++ b/backend/benefit/applications/migrations/0067_add_handler_to_application.py
@@ -6,21 +6,32 @@
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0066_alter_ahjostatus_status'),
+ ("applications", "0066_alter_ahjostatus_status"),
]
operations = [
migrations.AddField(
- model_name='application',
- name='handler',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
+ model_name="application",
+ name="handler",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ ),
),
migrations.AddField(
- model_name='historicalapplication',
- name='handler',
- field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL),
+ model_name="historicalapplication",
+ name="handler",
+ field=models.ForeignKey(
+ blank=True,
+ db_constraint=False,
+ null=True,
+ on_delete=django.db.models.deletion.DO_NOTHING,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0068_one_application_in_a_batch.py b/backend/benefit/applications/migrations/0068_one_application_in_a_batch.py
index 7794dfc422..dfd7c7ecb1 100644
--- a/backend/benefit/applications/migrations/0068_one_application_in_a_batch.py
+++ b/backend/benefit/applications/migrations/0068_one_application_in_a_batch.py
@@ -4,65 +4,122 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0067_add_handler_to_application'),
+ ("applications", "0067_add_handler_to_application"),
]
operations = [
migrations.AddField(
- model_name='applicationbatch',
- name='auto_generated_by_ahjo',
- field=models.BooleanField(blank=True, default=False, verbose_name='Batch created through Ahjo integration'),
+ model_name="applicationbatch",
+ name="auto_generated_by_ahjo",
+ field=models.BooleanField(
+ blank=True,
+ default=False,
+ verbose_name="Batch created through Ahjo integration",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='decision_maker_name',
- field=models.CharField(blank=True, max_length=128, null=True, verbose_name="decision maker's name in Ahjo"),
+ model_name="applicationbatch",
+ name="decision_maker_name",
+ field=models.CharField(
+ blank=True,
+ max_length=128,
+ null=True,
+ verbose_name="decision maker's name in Ahjo",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='decision_maker_title',
- field=models.CharField(blank=True, max_length=64, null=True, verbose_name="decision maker's title in Ahjo"),
+ model_name="applicationbatch",
+ name="decision_maker_title",
+ field=models.CharField(
+ blank=True,
+ max_length=64,
+ null=True,
+ verbose_name="decision maker's title in Ahjo",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='expert_inspector_email',
- field=models.EmailField(blank=True, max_length=254, null=True, verbose_name="Expert inspector's email address"),
+ model_name="applicationbatch",
+ name="expert_inspector_email",
+ field=models.EmailField(
+ blank=True,
+ max_length=254,
+ null=True,
+ verbose_name="Expert inspector's email address",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='expert_inspector_name',
- field=models.CharField(blank=True, max_length=128, null=True, verbose_name="Expert inspector's name"),
+ model_name="applicationbatch",
+ name="expert_inspector_name",
+ field=models.CharField(
+ blank=True,
+ max_length=128,
+ null=True,
+ verbose_name="Expert inspector's name",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='expert_inspector_title',
- field=models.CharField(blank=True, max_length=64, null=True, verbose_name="Expert inspector's title"),
+ model_name="applicationbatch",
+ name="expert_inspector_title",
+ field=models.CharField(
+ blank=True,
+ max_length=64,
+ null=True,
+ verbose_name="Expert inspector's title",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='p2p_checker_name',
- field=models.CharField(blank=True, max_length=64, null=True, verbose_name="P2P acceptor's title"),
+ model_name="applicationbatch",
+ name="p2p_checker_name",
+ field=models.CharField(
+ blank=True,
+ max_length=64,
+ null=True,
+ verbose_name="P2P acceptor's title",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='p2p_inspector_email',
- field=models.EmailField(blank=True, max_length=254, null=True, verbose_name="P2P inspector's email address"),
+ model_name="applicationbatch",
+ name="p2p_inspector_email",
+ field=models.EmailField(
+ blank=True,
+ max_length=254,
+ null=True,
+ verbose_name="P2P inspector's email address",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='p2p_inspector_name',
- field=models.CharField(blank=True, max_length=128, null=True, verbose_name="P2P inspector's name"),
+ model_name="applicationbatch",
+ name="p2p_inspector_name",
+ field=models.CharField(
+ blank=True,
+ max_length=128,
+ null=True,
+ verbose_name="P2P inspector's name",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='proposal_for_decision',
- field=models.CharField(blank=True, choices=[('accepted', 'Decided Accepted'), ('rejected', 'Decided Rejected')], max_length=64, null=True, verbose_name='proposal for decision'),
+ model_name="applicationbatch",
+ name="proposal_for_decision",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("accepted", "Decided Accepted"),
+ ("rejected", "Decided Rejected"),
+ ],
+ max_length=64,
+ null=True,
+ verbose_name="proposal for decision",
+ ),
),
migrations.AlterField(
- model_name='applicationbatch',
- name='section_of_the_law',
- field=models.CharField(blank=True, max_length=16, null=True, verbose_name='section of the law in Ahjo decision'),
+ model_name="applicationbatch",
+ name="section_of_the_law",
+ field=models.CharField(
+ blank=True,
+ max_length=16,
+ null=True,
+ verbose_name="section of the law in Ahjo decision",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0069_auto_20240422_1906.py b/backend/benefit/applications/migrations/0069_auto_20240422_1906.py
index 3acb84a338..0c1c5f0859 100644
--- a/backend/benefit/applications/migrations/0069_auto_20240422_1906.py
+++ b/backend/benefit/applications/migrations/0069_auto_20240422_1906.py
@@ -1,36 +1,56 @@
# Generated by Django 3.2.23 on 2024-04-22 16:06
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0068_one_application_in_a_batch'),
+ ("applications", "0068_one_application_in_a_batch"),
]
operations = [
migrations.AddField(
- model_name='applicationalteration',
- name='handled_by',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
+ model_name="applicationalteration",
+ name="handled_by",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ to=settings.AUTH_USER_MODEL,
+ ),
),
migrations.AddField(
- model_name='applicationalteration',
- name='is_recoverable',
- field=models.BooleanField(default=False, verbose_name='whether the alteration should be recovered'),
+ model_name="applicationalteration",
+ name="is_recoverable",
+ field=models.BooleanField(
+ default=False, verbose_name="whether the alteration should be recovered"
+ ),
),
migrations.AddField(
- model_name='applicationalteration',
- name='recovery_justification',
- field=models.TextField(blank=True, verbose_name='the justification provided in the recovering bill, if eligible'),
+ model_name="applicationalteration",
+ name="recovery_justification",
+ field=models.TextField(
+ blank=True,
+ verbose_name=(
+ "the justification provided in the recovering bill, if eligible"
+ ),
+ ),
),
migrations.AlterField(
- model_name='applicationalteration',
- name='state',
- field=models.TextField(choices=[('received', 'Received'), ('opened', 'Opened'), ('handled', 'Handled'), ('cancelled', 'Cancelled')], default='received', verbose_name='state of alteration'),
+ model_name="applicationalteration",
+ name="state",
+ field=models.TextField(
+ choices=[
+ ("received", "Received"),
+ ("opened", "Opened"),
+ ("handled", "Handled"),
+ ("cancelled", "Cancelled"),
+ ],
+ default="received",
+ verbose_name="state of alteration",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0070_alter_ahjostatus_status.py b/backend/benefit/applications/migrations/0070_alter_ahjostatus_status.py
index 99cb7bfda2..fadbf00c22 100644
--- a/backend/benefit/applications/migrations/0070_alter_ahjostatus_status.py
+++ b/backend/benefit/applications/migrations/0070_alter_ahjostatus_status.py
@@ -4,16 +4,42 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0069_auto_20240422_1906'),
+ ("applications", "0069_auto_20240422_1906"),
]
operations = [
migrations.AlterField(
- model_name='ahjostatus',
- name='status',
- field=models.CharField(choices=[('submitted_but_not_sent_to_ahjo', 'Submitted but not sent to AHJO'), ('request_to_open_case_sent', 'Request to open the case sent to AHJO'), ('case_opened', 'Case opened in AHJO'), ('update_request_sent', 'Update request sent'), ('update_request_received', 'Update request received'), ('decision_proposal_sent', 'Decision proposal sent'), ('decision_proposal_accepted', 'Decision proposal accepted'), ('decision_proposal_rejected', 'Decision proposal rejected'),('scheduled_for_deletion', 'Scheduled for deletion'),
- ('delete_request_sent', 'Delete request sent'), ('delete_request_received', 'Delete request received'), ('new_record_request_sent', 'New record request sent'), ('new_record_received', 'New record received by Ahjo'), ('removed', 'Decision cancelled in Ahjo'), ('signed', 'Decision signed and completed in Ahjo'), ('updated', 'Decision updated in Ahjo')], default='submitted_but_not_sent_to_ahjo', max_length=64, verbose_name='status'),
+ model_name="ahjostatus",
+ name="status",
+ field=models.CharField(
+ choices=[
+ (
+ "submitted_but_not_sent_to_ahjo",
+ "Submitted but not sent to AHJO",
+ ),
+ (
+ "request_to_open_case_sent",
+ "Request to open the case sent to AHJO",
+ ),
+ ("case_opened", "Case opened in AHJO"),
+ ("update_request_sent", "Update request sent"),
+ ("update_request_received", "Update request received"),
+ ("decision_proposal_sent", "Decision proposal sent"),
+ ("decision_proposal_accepted", "Decision proposal accepted"),
+ ("decision_proposal_rejected", "Decision proposal rejected"),
+ ("scheduled_for_deletion", "Scheduled for deletion"),
+ ("delete_request_sent", "Delete request sent"),
+ ("delete_request_received", "Delete request received"),
+ ("new_record_request_sent", "New record request sent"),
+ ("new_record_received", "New record received by Ahjo"),
+ ("removed", "Decision cancelled in Ahjo"),
+ ("signed", "Decision signed and completed in Ahjo"),
+ ("updated", "Decision updated in Ahjo"),
+ ],
+ default="submitted_but_not_sent_to_ahjo",
+ max_length=64,
+ verbose_name="status",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0071_auto_20240507_0226.py b/backend/benefit/applications/migrations/0071_auto_20240507_0226.py
index 7dea1cb891..1520a2f8cf 100644
--- a/backend/benefit/applications/migrations/0071_auto_20240507_0226.py
+++ b/backend/benefit/applications/migrations/0071_auto_20240507_0226.py
@@ -1,120 +1,206 @@
# Generated by Django 3.2.23 on 2024-05-08 06:47
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
- ('applications', '0070_alter_ahjostatus_status'),
+ ("applications", "0070_alter_ahjostatus_status"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
- model_name='applicationalteration',
- name='handled_by',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='alteration_type',
- field=models.TextField(choices=[('termination', 'Termination'), ('suspension', 'Suspension')], verbose_name='Type of alteration'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='application',
- field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='alteration_set', to='applications.application', verbose_name='Alteration of application'),
+ model_name="applicationalteration",
+ name="handled_by",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="alteration_type",
+ field=models.TextField(
+ choices=[("termination", "Termination"), ("suspension", "Suspension")],
+ verbose_name="Type of alteration",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="application",
+ field=models.ForeignKey(
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="alteration_set",
+ to="applications.application",
+ verbose_name="Alteration of application",
+ ),
),
migrations.AddField(
- model_name='applicationalteration',
- name='cancelled_at',
- field=models.DateField(blank=True, null=True, verbose_name='The date the alteration was cancelled after it had been handled'),
+ model_name="applicationalteration",
+ name="cancelled_at",
+ field=models.DateField(
+ blank=True,
+ null=True,
+ verbose_name=(
+ "The date the alteration was cancelled after it had been handled"
+ ),
+ ),
),
migrations.AddField(
- model_name='applicationalteration',
- name='cancelled_by',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Cancelled by'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='contact_person_name',
- field=models.TextField(verbose_name='Contact person'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='einvoice_address',
- field=models.TextField(blank=True, verbose_name='E-invoice address'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='einvoice_provider_identifier',
- field=models.TextField(blank=True, verbose_name='Identifier of the e-invoice provider'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='einvoice_provider_name',
- field=models.TextField(blank=True, verbose_name='Name of the e-invoice provider'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='end_date',
- field=models.DateField(verbose_name='New benefit end date'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='handled_at',
- field=models.DateField(blank=True, null=True, verbose_name='Date when alteration notice was handled'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='handled_by',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL, verbose_name='Handled by'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='is_recoverable',
- field=models.BooleanField(default=False, verbose_name='Whether the alteration should be recovered'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='reason',
- field=models.TextField(blank=True, verbose_name='Reason for alteration'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='recovery_amount',
- field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True, verbose_name='Amount of unwarranted benefit to be recovered'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='recovery_end_date',
- field=models.DateField(blank=True, null=True, verbose_name='The last day the unwarranted benefit will be recovered from'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='recovery_justification',
- field=models.TextField(blank=True, verbose_name='The justification provided in the recovering bill, if eligible'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='recovery_start_date',
- field=models.DateField(blank=True, null=True, verbose_name='The first day the unwarranted benefit will be collected from'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='resume_date',
- field=models.DateField(blank=True, null=True, verbose_name='Date when employment resumes after suspended'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='state',
- field=models.TextField(choices=[('received', 'Received'), ('opened', 'Opened'), ('handled', 'Handled'), ('cancelled', 'Cancelled')], default='received', verbose_name='State of alteration'),
- ),
- migrations.AlterField(
- model_name='applicationalteration',
- name='use_einvoice',
- field=models.BooleanField(default=False, verbose_name='Whether to use handle billing with an e-invoice instead of a bill sent to a physical address'),
+ model_name="applicationalteration",
+ name="cancelled_by",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="Cancelled by",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="contact_person_name",
+ field=models.TextField(verbose_name="Contact person"),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="einvoice_address",
+ field=models.TextField(blank=True, verbose_name="E-invoice address"),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="einvoice_provider_identifier",
+ field=models.TextField(
+ blank=True, verbose_name="Identifier of the e-invoice provider"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="einvoice_provider_name",
+ field=models.TextField(
+ blank=True, verbose_name="Name of the e-invoice provider"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="end_date",
+ field=models.DateField(verbose_name="New benefit end date"),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="handled_at",
+ field=models.DateField(
+ blank=True,
+ null=True,
+ verbose_name="Date when alteration notice was handled",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="handled_by",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="+",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="Handled by",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="is_recoverable",
+ field=models.BooleanField(
+ default=False, verbose_name="Whether the alteration should be recovered"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="reason",
+ field=models.TextField(blank=True, verbose_name="Reason for alteration"),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="recovery_amount",
+ field=models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ max_digits=8,
+ null=True,
+ verbose_name="Amount of unwarranted benefit to be recovered",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="recovery_end_date",
+ field=models.DateField(
+ blank=True,
+ null=True,
+ verbose_name=(
+ "The last day the unwarranted benefit will be recovered from"
+ ),
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="recovery_justification",
+ field=models.TextField(
+ blank=True,
+ verbose_name=(
+ "The justification provided in the recovering bill, if eligible"
+ ),
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="recovery_start_date",
+ field=models.DateField(
+ blank=True,
+ null=True,
+ verbose_name=(
+ "The first day the unwarranted benefit will be collected from"
+ ),
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="resume_date",
+ field=models.DateField(
+ blank=True,
+ null=True,
+ verbose_name="Date when employment resumes after suspended",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="state",
+ field=models.TextField(
+ choices=[
+ ("received", "Received"),
+ ("opened", "Opened"),
+ ("handled", "Handled"),
+ ("cancelled", "Cancelled"),
+ ],
+ default="received",
+ verbose_name="State of alteration",
+ ),
+ ),
+ migrations.AlterField(
+ model_name="applicationalteration",
+ name="use_einvoice",
+ field=models.BooleanField(
+ default=False,
+ verbose_name=(
+ "Whether to use handle billing with an e-invoice instead of a bill"
+ " sent to a physical address"
+ ),
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0072_install_trigram_functions.py b/backend/benefit/applications/migrations/0072_install_trigram_functions.py
index 0f6fd4945d..f389f98a74 100644
--- a/backend/benefit/applications/migrations/0072_install_trigram_functions.py
+++ b/backend/benefit/applications/migrations/0072_install_trigram_functions.py
@@ -1,7 +1,7 @@
# Generated by Django 3.2.23 on 2024-05-08 06:47
-from django.db import migrations
from django.contrib.postgres.operations import TrigramExtension
+from django.db import migrations
class Migration(migrations.Migration):
diff --git a/backend/benefit/applications/migrations/0073_alter_ahjostatus_status.py b/backend/benefit/applications/migrations/0073_alter_ahjostatus_status.py
index bf9f4f1180..dc8d0034ba 100644
--- a/backend/benefit/applications/migrations/0073_alter_ahjostatus_status.py
+++ b/backend/benefit/applications/migrations/0073_alter_ahjostatus_status.py
@@ -4,15 +4,43 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0072_install_trigram_functions'),
+ ("applications", "0072_install_trigram_functions"),
]
operations = [
migrations.AlterField(
- model_name='ahjostatus',
- name='status',
- field=models.CharField(choices=[('submitted_but_not_sent_to_ahjo', 'Submitted but not sent to AHJO'), ('request_to_open_case_sent', 'Request to open the case sent to AHJO'), ('case_opened', 'Case opened in AHJO'), ('update_request_sent', 'Update request sent'), ('update_request_received', 'Update request received'), ('decision_proposal_sent', 'Decision proposal sent'), ('decision_proposal_accepted', 'Decision proposal accepted'), ('decision_proposal_rejected', 'Decision proposal rejected'), ('scheduled_for_deletion', 'Scheduled for deletion'), ('delete_request_sent', 'Delete request sent'), ('delete_request_received', 'Delete request received'), ('new_record_request_sent', 'New record request sent'), ('new_record_received', 'New record received by Ahjo'), ('removed', 'Decision cancelled in Ahjo'), ('signed', 'Decision signed and completed in Ahjo'), ('updated', 'Decision updated in Ahjo'), ('details_received', 'Decision details received from Ahjo')], default='submitted_but_not_sent_to_ahjo', max_length=64, verbose_name='status'),
+ model_name="ahjostatus",
+ name="status",
+ field=models.CharField(
+ choices=[
+ (
+ "submitted_but_not_sent_to_ahjo",
+ "Submitted but not sent to AHJO",
+ ),
+ (
+ "request_to_open_case_sent",
+ "Request to open the case sent to AHJO",
+ ),
+ ("case_opened", "Case opened in AHJO"),
+ ("update_request_sent", "Update request sent"),
+ ("update_request_received", "Update request received"),
+ ("decision_proposal_sent", "Decision proposal sent"),
+ ("decision_proposal_accepted", "Decision proposal accepted"),
+ ("decision_proposal_rejected", "Decision proposal rejected"),
+ ("scheduled_for_deletion", "Scheduled for deletion"),
+ ("delete_request_sent", "Delete request sent"),
+ ("delete_request_received", "Delete request received"),
+ ("new_record_request_sent", "New record request sent"),
+ ("new_record_received", "New record received by Ahjo"),
+ ("removed", "Decision cancelled in Ahjo"),
+ ("signed", "Decision signed and completed in Ahjo"),
+ ("updated", "Decision updated in Ahjo"),
+ ("details_received", "Decision details received from Ahjo"),
+ ],
+ default="submitted_but_not_sent_to_ahjo",
+ max_length=64,
+ verbose_name="status",
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0074_auto_20240606_1252.py b/backend/benefit/applications/migrations/0074_auto_20240606_1252.py
index 76941f0445..ea13eadbcf 100644
--- a/backend/benefit/applications/migrations/0074_auto_20240606_1252.py
+++ b/backend/benefit/applications/migrations/0074_auto_20240606_1252.py
@@ -1,72 +1,273 @@
# Generated by Django 3.2.23 on 2024-06-06 09:52
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import encrypted_fields.fields
-import uuid
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('companies', '0004_localized_iban_field'),
- ('applications', '0073_alter_ahjostatus_status'),
+ ("companies", "0004_localized_iban_field"),
+ ("applications", "0073_alter_ahjostatus_status"),
]
operations = [
migrations.AlterField(
- model_name='application',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], default='draft', max_length=64, verbose_name='status'),
+ model_name="application",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status",
+ ),
),
migrations.AlterField(
- model_name='applicationlogentry',
- name='from_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], max_length=64),
+ model_name="applicationlogentry",
+ name="from_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='applicationlogentry',
- name='to_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], max_length=64),
+ model_name="applicationlogentry",
+ name="to_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='historicalapplication',
- name='status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], default='draft', max_length=64, verbose_name='status'),
+ model_name="historicalapplication",
+ name="status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ default="draft",
+ max_length=64,
+ verbose_name="status",
+ ),
),
migrations.AlterField(
- model_name='historicalapplicationlogentry',
- name='from_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], max_length=64),
+ model_name="historicalapplicationlogentry",
+ name="from_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ max_length=64,
+ ),
),
migrations.AlterField(
- model_name='historicalapplicationlogentry',
- name='to_status',
- field=models.CharField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], max_length=64),
+ model_name="historicalapplicationlogentry",
+ name="to_status",
+ field=models.CharField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ max_length=64,
+ ),
),
migrations.CreateModel(
- name='ArchivalApplication',
+ name="ArchivalApplication",
fields=[
- ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='time created')),
- ('modified_at', models.DateTimeField(auto_now=True, verbose_name='time modified')),
- ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
- ('application_number', models.TextField(blank=True, null=True, verbose_name='application_number')),
- ('submitted_at', models.TextField(blank=True, null=True, verbose_name='submitted_at')),
- ('encrypted_employee_first_name', encrypted_fields.fields.EncryptedCharField(blank=True, max_length=128, verbose_name='first name')),
- ('encrypted_employee_last_name', encrypted_fields.fields.EncryptedCharField(blank=True, max_length=128, verbose_name='last name')),
- ('employee_first_name', encrypted_fields.fields.SearchField(blank=True, db_index=True, encrypted_field_name='encrypted_employee_first_name', hash_key='02c5b8605cd4f9c188eee422209069b7bd3a607f0ae0a166eab0da223d1b6735', max_length=66, null=True)),
- ('employee_last_name', encrypted_fields.fields.SearchField(blank=True, db_index=True, encrypted_field_name='encrypted_employee_last_name', hash_key='af1b5a67d11197865a731c26bf9659716b9ded71c2802b4363856fe613b6b527', max_length=66, null=True)),
- ('start_date', models.DateField(blank=True, null=True, verbose_name='start_date')),
- ('end_date', models.DateField(blank=True, null=True, verbose_name='end_date')),
- ('benefit_type', models.TextField(blank=True, null=True, verbose_name='benefit_type')),
- ('months_total', models.TextField(blank=True, null=True, verbose_name='months_total')),
- ('year_of_birth', models.TextField(blank=True, null=True, verbose_name='day_of_birth')),
- ('status', models.TextField(choices=[('draft', 'Draft'), ('received', 'Received'), ('handling', 'Handling'), ('additional_information_needed', 'Additional information requested'), ('cancelled', 'Cancelled'), ('accepted', 'Accepted'), ('rejected', 'Rejected'), ('archival', 'Archival')], default='archival')),
- ('handled_at', models.DateField(blank=True, null=True, verbose_name='handled_at')),
- ('company', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='archival_applications', to='companies.company', verbose_name='company')),
+ (
+ "created_at",
+ models.DateTimeField(
+ auto_now_add=True, verbose_name="time created"
+ ),
+ ),
+ (
+ "modified_at",
+ models.DateTimeField(auto_now=True, verbose_name="time modified"),
+ ),
+ (
+ "id",
+ models.UUIDField(
+ default=uuid.uuid4,
+ editable=False,
+ primary_key=True,
+ serialize=False,
+ ),
+ ),
+ (
+ "application_number",
+ models.TextField(
+ blank=True, null=True, verbose_name="application_number"
+ ),
+ ),
+ (
+ "submitted_at",
+ models.TextField(
+ blank=True, null=True, verbose_name="submitted_at"
+ ),
+ ),
+ (
+ "encrypted_employee_first_name",
+ encrypted_fields.fields.EncryptedCharField(
+ blank=True, max_length=128, verbose_name="first name"
+ ),
+ ),
+ (
+ "encrypted_employee_last_name",
+ encrypted_fields.fields.EncryptedCharField(
+ blank=True, max_length=128, verbose_name="last name"
+ ),
+ ),
+ (
+ "employee_first_name",
+ encrypted_fields.fields.SearchField(
+ blank=True,
+ db_index=True,
+ encrypted_field_name="encrypted_employee_first_name",
+ hash_key="02c5b8605cd4f9c188eee422209069b7bd3a607f0ae0a166eab0da223d1b6735",
+ max_length=66,
+ null=True,
+ ),
+ ),
+ (
+ "employee_last_name",
+ encrypted_fields.fields.SearchField(
+ blank=True,
+ db_index=True,
+ encrypted_field_name="encrypted_employee_last_name",
+ hash_key="af1b5a67d11197865a731c26bf9659716b9ded71c2802b4363856fe613b6b527",
+ max_length=66,
+ null=True,
+ ),
+ ),
+ (
+ "start_date",
+ models.DateField(blank=True, null=True, verbose_name="start_date"),
+ ),
+ (
+ "end_date",
+ models.DateField(blank=True, null=True, verbose_name="end_date"),
+ ),
+ (
+ "benefit_type",
+ models.TextField(
+ blank=True, null=True, verbose_name="benefit_type"
+ ),
+ ),
+ (
+ "months_total",
+ models.TextField(
+ blank=True, null=True, verbose_name="months_total"
+ ),
+ ),
+ (
+ "year_of_birth",
+ models.TextField(
+ blank=True, null=True, verbose_name="day_of_birth"
+ ),
+ ),
+ (
+ "status",
+ models.TextField(
+ choices=[
+ ("draft", "Draft"),
+ ("received", "Received"),
+ ("handling", "Handling"),
+ (
+ "additional_information_needed",
+ "Additional information requested",
+ ),
+ ("cancelled", "Cancelled"),
+ ("accepted", "Accepted"),
+ ("rejected", "Rejected"),
+ ("archival", "Archival"),
+ ],
+ default="archival",
+ ),
+ ),
+ (
+ "handled_at",
+ models.DateField(blank=True, null=True, verbose_name="handled_at"),
+ ),
+ (
+ "company",
+ models.ForeignKey(
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="archival_applications",
+ to="companies.company",
+ verbose_name="company",
+ ),
+ ),
],
options={
- 'db_table': 'bf_applications_archival_application',
+ "db_table": "bf_applications_archival_application",
},
),
]
diff --git a/backend/benefit/applications/migrations/0077_alter_attachment_attachment_file.py b/backend/benefit/applications/migrations/0077_alter_attachment_attachment_file.py
index 0f414cfad2..b6b1132317 100644
--- a/backend/benefit/applications/migrations/0077_alter_attachment_attachment_file.py
+++ b/backend/benefit/applications/migrations/0077_alter_attachment_attachment_file.py
@@ -1,8 +1,9 @@
# Generated by Django 4.2.11 on 2024-08-01 10:09
-import applications.models
from django.db import migrations, models
+import applications.models
+
class Migration(migrations.Migration):
dependencies = [
diff --git a/backend/benefit/applications/migrations/0086_alter_ahjodecisionproposaldraft_handler_role.py b/backend/benefit/applications/migrations/0086_alter_ahjodecisionproposaldraft_handler_role.py
index 9d8c274a7e..e382a5281f 100644
--- a/backend/benefit/applications/migrations/0086_alter_ahjodecisionproposaldraft_handler_role.py
+++ b/backend/benefit/applications/migrations/0086_alter_ahjodecisionproposaldraft_handler_role.py
@@ -4,15 +4,26 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0085_alter_ahjostatus_status'),
+ ("applications", "0085_alter_ahjostatus_status"),
]
operations = [
migrations.AlterField(
- model_name='ahjodecisionproposaldraft',
- name='handler_role',
- field=models.CharField(blank=True, choices=[('handler', 'Helsinki-benefit handler'), ('manager', 'Team manager')], max_length=64, null=True, verbose_name='Handler role (deprecated, was used before dynamic fetch of decision makers)'),
+ model_name="ahjodecisionproposaldraft",
+ name="handler_role",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("handler", "Helsinki-benefit handler"),
+ ("manager", "Team manager"),
+ ],
+ max_length=64,
+ null=True,
+ verbose_name=(
+ "Handler role (deprecated, was used before dynamic fetch of"
+ " decision makers)"
+ ),
+ ),
),
]
diff --git a/backend/benefit/applications/migrations/0087_alter_ahjodecisionproposaldraft_handler_role.py b/backend/benefit/applications/migrations/0087_alter_ahjodecisionproposaldraft_handler_role.py
index 403f8853a6..ed03b55ce8 100644
--- a/backend/benefit/applications/migrations/0087_alter_ahjodecisionproposaldraft_handler_role.py
+++ b/backend/benefit/applications/migrations/0087_alter_ahjodecisionproposaldraft_handler_role.py
@@ -4,15 +4,26 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0086_alter_ahjodecisionproposaldraft_handler_role'),
+ ("applications", "0086_alter_ahjodecisionproposaldraft_handler_role"),
]
operations = [
migrations.AlterField(
- model_name='ahjodecisionproposaldraft',
- name='handler_role',
- field=models.CharField(blank=True, choices=[('handler', 'Helsinki-benefit handler'), ('manager', 'Team manager')], max_length=64, null=True, verbose_name='Handler role (DEPRECATED, was used before dynamic fetch of decision makers)'),
+ model_name="ahjodecisionproposaldraft",
+ name="handler_role",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("handler", "Helsinki-benefit handler"),
+ ("manager", "Team manager"),
+ ],
+ max_length=64,
+ null=True,
+ verbose_name=(
+ "Handler role (DEPRECATED, was used before dynamic fetch of"
+ " decision makers)"
+ ),
+ ),
),
]
diff --git a/backend/benefit/applications/models.py b/backend/benefit/applications/models.py
index 5a061de119..3c08a62cd8 100755
--- a/backend/benefit/applications/models.py
+++ b/backend/benefit/applications/models.py
@@ -17,7 +17,6 @@
from applications.enums import (
AhjoDecision,
AhjoDecisionDetails,
- AhjoStatus as AhjoStatusEnum,
ApplicationAlterationState,
ApplicationAlterationType,
ApplicationBatchStatus,
@@ -31,6 +30,9 @@
HandlerRole,
PaySubsidyGranted,
)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
+)
from applications.exceptions import (
BatchCompletionDecisionDateError,
BatchCompletionRequiredFieldsError,
@@ -115,7 +117,7 @@ def get_queryset(self):
"""
Annotate the queryset with information about timestamps of past status transitions.
If multiple transitions to the same status have occurred, then use the latest status transition timestamp.
- """
+ """ # noqa: E501
qs = super().get_queryset()
qs = self._annotate_with_log_timestamp(qs, "handled_at", self.HANDLED_STATUSES)
qs = self._annotate_with_log_timestamp(
@@ -133,7 +135,7 @@ def with_non_downloaded_attachments(self):
Returns applications with only those attachments that have
null in 'downloaded_by_ahjo' and where the applications have a non-null ahjo_case_id,
which means that a case has been opened for them in AHJO.
- """
+ """ # noqa: E501
# Define a queryset for attachments where downloaded_by_ahjo is NULL
attachments_queryset = Attachment.objects.filter(
@@ -154,7 +156,8 @@ def with_non_downloaded_attachments(self):
attachments_queryset.filter(application_id=OuterRef("pk"))
)
- # Annotate applications with a boolean indicating the existence of undownloaded attachments
+ # Annotate applications with a boolean indicating the existence of undownloaded
+ # attachments
qs = (
self.get_queryset()
.annotate(has_undownloaded_attachments=attachment_exists)
@@ -167,11 +170,12 @@ def with_non_downloaded_attachments(self):
# Use Prefetch to specify the filtered queryset for prefetching attachments
attachments_prefetch = Prefetch("attachments", queryset=attachments_queryset)
- # Return the filtered applications with the specified prefetched related attachments
+ # Return the filtered applications with the specified prefetched related
+ # attachments
return qs.prefetch_related(attachments_prefetch)
def with_due_instalments(self, status: InstalmentStatus):
- """Query applications with instalments with past due date and a specific status."""
+ """Query applications with instalments with past due date and a specific status.""" # noqa: E501
return (
self.filter(
status=ApplicationStatus.ACCEPTED,
@@ -199,8 +203,9 @@ def get_by_statuses(
AhjoStatusEnum.DECISION_PROPOSAL_ACCEPTED,
or
AhjoStatusEnum.NEW_RECORDS_RECEIVED
- """
- # if hours are specified, then the retry_status is used to query the applications for the re-attempt
+ """ # noqa: E501
+ # if hours are specified, then the retry_status is used to query the
+ # applications for the re-attempt
if retry_failed_older_than_hours > 0 and retry_status:
ahjo_statuses = [retry_status]
@@ -269,7 +274,7 @@ def get_for_ahjo_decision(
Get applications that are in a state where a decision proposal should be sent to Ahjo.
This means applications that have been accepted or rejected, their talpa status is not_processed_by_talpa,
have a ahjo_case_id, a decisiontext and their latest ahjo_status is case_opened.
- """
+ """ # noqa: E501
if retry_failed_older_than_hours > 0 and retry_status:
ahjo_statuses = [retry_status]
@@ -327,7 +332,7 @@ class Application(UUIDModel, TimeStampedModel, DurationMixin):
multiple applications.
For additional descriptions of the fields, see the API documentation (serializers.py)
- """
+ """ # noqa: E501
objects = ApplicationManager()
@@ -405,7 +410,8 @@ class Application(UUIDModel, TimeStampedModel, DurationMixin):
max_length=256, verbose_name=_("company post code"), blank=True
)
- # the following property values are evaluated based on use_alternative_address setting
+ # the following property values are evaluated based on use_alternative_address
+ # setting
effective_company_street_address = property(
address_property("company_street_address")
)
@@ -436,7 +442,7 @@ class Application(UUIDModel, TimeStampedModel, DurationMixin):
"""
Only required if the applicant company form is an association or something else that might not have
business activities. For "normal" businesses, this field has no effect and should always be set to None.
- """
+ """ # noqa: E501
association_has_business_activities = models.BooleanField(null=True)
"""
@@ -448,7 +454,7 @@ class Application(UUIDModel, TimeStampedModel, DurationMixin):
if language is swedish, then the decision text in Ahjo must be also in swedish
if language is english, then an english translation of the decision is included
in Ahjo as attachment
- """
+ """ # noqa: E501
applicant_language = models.CharField(
choices=APPLICATION_LANGUAGE_CHOICES,
default=APPLICATION_LANGUAGE_CHOICES[0][0],
@@ -545,7 +551,7 @@ def get_available_benefit_types(self):
de_minimis_aid is only applicable to applicants with business activities, otherwise it should be None.
If value is set to True, then this application must have at least one DeMinimisAid, and if False,
then the application must have no DeMinimisAid objects.
- """
+ """ # noqa: E501
de_minimis_aid = models.BooleanField(null=True)
batch = models.ForeignKey(
@@ -641,7 +647,10 @@ def total_deminimis_amount(self):
@property
def contact_person(self):
- return f"{self.company_contact_person_first_name} {self.company_contact_person_last_name}"
+ return (
+ f"{self.company_contact_person_first_name}"
+ f" {self.company_contact_person_last_name}"
+ )
def get_log_entry_field(self, to_statuses, field_name):
if (
@@ -765,7 +774,7 @@ class ApplicationBatch(UUIDModel, TimeStampedModel):
If Ahjo automation / integration is in use, a single application batch will be created for each
application, after a case has been opened in Ahjo after which auto_generated_by ahjo is set to True.
- """
+ """ # noqa: E501
handler = models.ForeignKey(
User,
@@ -858,9 +867,7 @@ def _clean_one_draft_per_decision(self):
).exclude(id=self.id)
if len(drafts) > 0:
raise BatchTooManyDraftsError(
- (
- f"Too many existing drafts of type {self.proposal_for_decision}"
- )
+ f"Too many existing drafts of type {self.proposal_for_decision}"
)
def _clean_require_batch_data_on_completion(self):
@@ -916,11 +923,12 @@ def update_batch_after_details_request(
"""
Update the application batch with the details received from the Ahjo decision request and with
details from the applications_ahjo_setting table.
- """
+ """ # noqa: E501
try:
if not self.auto_generated_by_ahjo:
raise ImproperlyConfigured(
- "This batch was not auto-generated by Ahjo, so it should not be updated"
+ "This batch was not auto-generated by Ahjo, so it should not be"
+ " updated"
)
self.decision_maker_name = details.decision_maker_name
self.decision_maker_title = details.decision_maker_title
@@ -948,7 +956,7 @@ def applications_can_be_modified(self):
After the applications have been sent to Ahjo, the handlers should not be able to modify
the applications. If the batch is returned without decision (as might theoretically happen),
then the handlers may need to make changes again.
- """
+ """ # noqa: E501
return self.status in [
ApplicationBatchStatus.DRAFT,
ApplicationBatchStatus.RETURNED,
@@ -960,7 +968,9 @@ def is_decided(self):
AHJO_DECISION_LOGIC = {
ApplicationBatchStatus.DRAFT: None,
- ApplicationBatchStatus.RETURNED: None, # decision was not made, the applications are returned for processing
+ ApplicationBatchStatus.RETURNED: (
+ None
+ ), # decision was not made, the applications are returned for processing
ApplicationBatchStatus.AWAITING_AHJO_DECISION: None,
ApplicationBatchStatus.DECIDED_ACCEPTED: AhjoDecision.DECIDED_ACCEPTED,
ApplicationBatchStatus.DECIDED_REJECTED: AhjoDecision.DECIDED_REJECTED,
@@ -991,7 +1001,7 @@ class ApplicationBasis(UUIDModel, TimeStampedModel):
basis/justification for the application.
The identifier is not meant to be displayed to the end user. The actual name that is shown to the applicant
is determined by the UI, and localized as needed.
- """
+ """ # noqa: E501
identifier = models.CharField(max_length=64, unique=True)
is_active = models.BooleanField(default=True)
@@ -1060,7 +1070,7 @@ class Employee(UUIDModel, TimeStampedModel):
choices=APPLICATION_LANGUAGE_CHOICES,
default=APPLICATION_LANGUAGE_CHOICES[0][0],
max_length=2,
- blank=True, # as of 2021-06, only required for power of attorney, so it's optional
+ blank=True, # as of 2021-06, only required for power of attorney, so it's optional # noqa: E501
)
job_title = models.CharField(
@@ -1252,9 +1262,11 @@ class AhjoStatus(TimeStampedModel):
)
def __str__(self):
- return f"{self.status} for application {self.application.application_number}, \
-created_at: {self.created_at}, modified_at: {self.modified_at}, \
-ahjo_request_id: {self.ahjo_request_id}"
+ return (
+ f"{self.status} for application {self.application.application_number},"
+ f" created_at: {self.created_at}, modified_at: {self.modified_at},"
+ f" ahjo_request_id: {self.ahjo_request_id}"
+ )
class Meta:
db_table = "bf_applications_ahjo_status"
@@ -1268,7 +1280,7 @@ class Meta:
class DecisionProposalTemplateSection(UUIDModel, TimeStampedModel):
"""Model representing a template section of a decision proposal text, usually either the decision
text or the following justification text.
- """
+ """ # noqa: E501
decision_type = models.CharField(
max_length=64,
@@ -1305,7 +1317,7 @@ class Meta:
class AhjoDecisionText(UUIDModel, TimeStampedModel):
- """Model representing a submitted decision text submitted to Ahjo for an application."""
+ """Model representing a submitted decision text submitted to Ahjo for an application.""" # noqa: E501
decision_type = models.CharField(
max_length=64,
@@ -1430,7 +1442,8 @@ class ApplicationAlteration(TimeStampedModel):
use_einvoice = models.BooleanField(
verbose_name=_(
- "Whether to use handle billing with an e-invoice instead of a bill sent to a physical address"
+ "Whether to use handle billing with an e-invoice instead of a bill sent to"
+ " a physical address"
),
default=False,
)
@@ -1544,7 +1557,8 @@ class Meta:
handler_role = models.CharField(
max_length=64,
verbose_name=_(
- "Handler role (DEPRECATED, was used before dynamic fetch of decision makers)"
+ "Handler role (DEPRECATED, was used before dynamic fetch of decision"
+ " makers)"
),
blank=True,
null=True,
diff --git a/backend/benefit/applications/services/ahjo/exceptions.py b/backend/benefit/applications/services/ahjo/exceptions.py
index 0e92da20d6..128e5aefb8 100644
--- a/backend/benefit/applications/services/ahjo/exceptions.py
+++ b/backend/benefit/applications/services/ahjo/exceptions.py
@@ -4,8 +4,6 @@
class DecisionProposalError(Exception):
"""Custom exception for errors in the sending of decision proposals."""
- pass
-
class DecisionProposalAlreadyAcceptedError(DecisionProposalError):
"""
@@ -22,84 +20,64 @@ def __init__(self, message: str, ahjo_status: AhjoStatus) -> None:
super().__init__(self.message)
-class AhjoApiClientException(Exception):
+class AhjoApiClientError(Exception):
"""
Raised when an error occurs in the AhjoApiClient.
"""
- pass
-
-class MissingAhjoCaseIdError(AhjoApiClientException):
+class MissingAhjoCaseIdError(AhjoApiClientError):
"""
Raised when a Ahjo request that requires a case id is missing the case id.
"""
- pass
-
-class MissingHandlerIdError(AhjoApiClientException):
+class MissingHandlerIdError(AhjoApiClientError):
"""
Raised when a Ahjo request that requires a handler id is missing the handler id.
"""
- pass
-
-class MissingOrganizationIdentifier(Exception):
+class MissingOrganizationIdentifierError(Exception):
"""
Raised when an organization identifier is missing from AhjoSettings in the database.
"""
- pass
-
-class AhjoTokenExpiredException(Exception):
+class AhjoTokenExpiredError(Exception):
"""
Raised when the Ahjo token has expired. The token should be re-configured manually, see instructions at:
https://helsinkisolutionoffice.atlassian.net/wiki/spaces/KAN/pages/8687517756/Siirto+yll+pitoon#Ahjo-autentikaatio-tokenin-haku-ja-asettaminen-manuaalisesti.
- """
-
- pass
+ """ # noqa: E501
-class AhjoTokenRetrievalException(Exception):
+class AhjoTokenRetrievalError(Exception):
"""
Raised when the Ahjo token has expired or it could not be otherwise refreshed automatically.
The token should be re-configured manually, see instructions at:
https://helsinkisolutionoffice.atlassian.net/wiki/spaces/KAN/pages/8687517756/Siirto+yll+pitoon#Ahjo-autentikaatio-tokenin-haku-ja-asettaminen-manuaalisesti.
- """
-
- pass
+ """ # noqa: E501
-class InvalidAhjoTokenException(Exception):
+class InvalidAhjoTokenError(Exception):
"""
Raised when the Ahjo token is missing data or is otherwise invalid.
"""
- pass
-
class AhjoCallbackError(Exception):
"""
Raised when an error occurs in the Ahjo callback.
"""
- pass
-
class AhjoDecisionError(Exception):
"""
Raised when an error occurs in substituting application data into the decision text.
"""
- pass
-
class AhjoDecisionDetailsParsingError(Exception):
"""
Raised when an error occurs in parsing the decision details after a details query to Ahjo.
- """
-
- pass
+ """ # noqa: E501
diff --git a/backend/benefit/applications/services/ahjo/response_handler.py b/backend/benefit/applications/services/ahjo/response_handler.py
index d2b8d86632..fb14db9cd1 100644
--- a/backend/benefit/applications/services/ahjo/response_handler.py
+++ b/backend/benefit/applications/services/ahjo/response_handler.py
@@ -8,10 +8,12 @@
from applications.enums import (
AhjoDecisionDetails,
- AhjoStatus as AhjoStatusEnum,
ApplicationBatchStatus,
ApplicationStatus,
)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
+)
from applications.models import AhjoSetting, AhjoStatus, Application
from applications.services.ahjo.enums import AhjoSettingName
from applications.services.ahjo.exceptions import (
@@ -42,14 +44,16 @@ def handle_ahjo_query_response(
if not data:
raise ValueError(
- f"Failed to process Ahjo API response for setting {setting_name}, no data received from Ahjo."
+ f"Failed to process Ahjo API response for setting {setting_name}, no"
+ " data received from Ahjo."
)
try:
# Validate response structure
if not isinstance(data, dict):
raise ValidationError(
- f"Invalid response format for setting {setting_name}: expected dictionary"
+ f"Invalid response format for setting {setting_name}: expected"
+ " dictionary"
)
if setting_name == AhjoSettingName.DECISION_MAKER:
filtered_data = AhjoResponseHandler.filter_decision_makers(data)
@@ -69,7 +73,8 @@ def handle_ahjo_query_response(
except Exception as e:
LOGGER.error(
- f"Failed to process Ahjo api response for setting {setting_name}: {str(e)}",
+ f"Failed to process Ahjo api response for setting {setting_name}:"
+ f" {str(e)}",
exc_info=True,
)
raise
@@ -194,8 +199,10 @@ def handle_details_request_success(
application=application, status=AhjoStatusEnum.DETAILS_RECEIVED_FROM_AHJO
)
- return f"Successfully received and updated decision details \
-for application {application.id} and batch {batch.id} from Ahjo"
+ return (
+ "Successfully received and updated decision details for application"
+ f" {application.id} and batch {batch.id} from Ahjo"
+ )
def _update_instalments_as_accepted(self, application: Application):
"""
diff --git a/backend/benefit/applications/services/ahjo_application_service.py b/backend/benefit/applications/services/ahjo_application_service.py
index 201f7a31d8..bb38cef38d 100644
--- a/backend/benefit/applications/services/ahjo_application_service.py
+++ b/backend/benefit/applications/services/ahjo_application_service.py
@@ -2,9 +2,11 @@
from applications.enums import (
AhjoRequestType,
- AhjoStatus as AhjoStatusEnum,
ApplicationStatus,
)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
+)
from applications.models import Application
diff --git a/backend/benefit/applications/services/ahjo_authentication.py b/backend/benefit/applications/services/ahjo_authentication.py
index 3a5a28efc8..0ef77b84bc 100644
--- a/backend/benefit/applications/services/ahjo_authentication.py
+++ b/backend/benefit/applications/services/ahjo_authentication.py
@@ -8,8 +8,8 @@
from applications.models import AhjoSetting
from applications.services.ahjo.exceptions import (
- AhjoTokenExpiredException,
- AhjoTokenRetrievalException,
+ AhjoTokenExpiredError,
+ AhjoTokenRetrievalError,
)
AUTH_TOKEN_GRANT_TYPE = "authorization_code"
@@ -64,7 +64,7 @@ def get_initial_token(self) -> AhjoToken:
"""Retrieve the initial access token from Ahjo API using the auth code,
this is only used when getting and setting the initial token manually.
If the initial token fails for some reason, a new ahjo_code must be saved into django.
- """
+ """ # noqa: E501
try:
auth_code = AhjoSetting.objects.get(name="ahjo_code")
@@ -82,7 +82,7 @@ def get_initial_token(self) -> AhjoToken:
def refresh_token(self) -> AhjoToken:
"""Refresh access token from Ahjo API using the refresh token of an existing token.
This should be used by, for example, a cron job to keep the token up to date.
- """
+ """ # noqa: E501
token = self.get_token_from_db()
if not token.refresh_token:
@@ -104,7 +104,7 @@ def do_token_request(self, payload: Dict[str, str]) -> Union[AhjoToken, None]:
self.token_url, headers=self.headers, data=payload, timeout=self.timeout
)
except requests.exceptions.RequestException as e:
- raise AhjoTokenRetrievalException(
+ raise AhjoTokenRetrievalError(
f"Failed to get or refresh token from Ahjo: {e}"
)
@@ -122,8 +122,9 @@ def do_token_request(self, payload: Dict[str, str]) -> Union[AhjoToken, None]:
return self.create_token(token_from_api)
else:
- raise AhjoTokenRetrievalException(
- f"Failed to retrieve or refresh token: {response.status_code} {response.content.decode()}"
+ raise AhjoTokenRetrievalError(
+ f"Failed to retrieve or refresh token: {response.status_code}"
+ f" {response.content.decode()}"
)
def get_token_from_db(self) -> Union[AhjoToken, None]:
@@ -137,7 +138,7 @@ def get_token_from_db(self) -> Union[AhjoToken, None]:
created_at=token.created_at,
)
if ahjo_token.has_expired():
- raise AhjoTokenExpiredException(
+ raise AhjoTokenExpiredError(
f"Ahjo access token has expired in {ahjo_token.expiry_datetime()}"
)
return ahjo_token
@@ -156,7 +157,8 @@ def create_token(
"expires_in": token.expires_in,
}
- # Delete old access token if it exists, so that only one token is stored and there will be
+ # Delete old access token if it exists, so that only one token is stored and
+ # there will be
# no need to calculate the expiry time of the token from the modified_at field
AhjoSetting.objects.filter(name="ahjo_access_token").delete()
diff --git a/backend/benefit/applications/services/ahjo_client.py b/backend/benefit/applications/services/ahjo_client.py
index 7c2b0a1cf3..6393b79d33 100644
--- a/backend/benefit/applications/services/ahjo_client.py
+++ b/backend/benefit/applications/services/ahjo_client.py
@@ -8,15 +8,16 @@
from django.conf import settings
from django.urls import reverse
-from applications.enums import AhjoRequestType, AhjoStatus as AhjoStatusEnum
+from applications.enums import AhjoRequestType
+from applications.enums import AhjoStatus as AhjoStatusEnum
from applications.models import AhjoSetting, AhjoStatus, Application
from applications.services.ahjo.enums import AhjoSettingName
from applications.services.ahjo.exceptions import (
- AhjoApiClientException,
- InvalidAhjoTokenException,
+ AhjoApiClientError,
+ InvalidAhjoTokenError,
MissingAhjoCaseIdError,
MissingHandlerIdError,
- MissingOrganizationIdentifier,
+ MissingOrganizationIdentifierError,
)
from applications.services.ahjo_authentication import AhjoToken
from applications.services.ahjo_error_writer import AhjoErrorWriter, AhjoFormattedError
@@ -44,7 +45,8 @@ def __str__(self):
def api_url(self) -> str:
if not self.application.calculation.handler.ad_username:
raise MissingHandlerIdError(
- f"Application {self.application.id} handler does not have an ad_username"
+ f"Application {self.application.id} handler does not have an"
+ " ad_username"
)
if not self.application.ahjo_case_id:
raise MissingAhjoCaseIdError("Application does not have an Ahjo case id")
@@ -64,7 +66,8 @@ class AhjoOpenCaseRequest(AhjoRequest):
def api_url(self) -> str:
if not self.application.calculation.handler.ad_username:
raise MissingHandlerIdError(
- f"Application {self.application.id} handler does not have an ad_username"
+ f"Application {self.application.id} handler does not have an"
+ " ad_username"
)
return f"{self.url_base}{API_CASES_BASE}"
@@ -108,13 +111,14 @@ class AhjoDeleteCaseRequest(AhjoRequest):
def api_url(self) -> str:
if not self.application.calculation.handler.ad_username:
raise MissingHandlerIdError(
- f"Application {self.application.id} handler does not have an ad_username"
+ f"Application {self.application.id} handler does not have an"
+ " ad_username"
)
if not self.application.ahjo_case_id:
raise MissingAhjoCaseIdError("Application does not have an Ahjo case id")
url = f"{self.url_base}{API_CASES_BASE}/{self.application.ahjo_case_id}"
draftsman_id = self.application.calculation.handler.ad_username
- return f"{url}?draftsmanid={draftsman_id}&reason={self.reason}&apireqlang={self.lang}"
+ return f"{url}?draftsmanid={draftsman_id}&reason={self.reason}&apireqlang={self.lang}" # noqa: E501
@dataclass
@@ -156,7 +160,7 @@ def org_identifier() -> str:
name=AhjoSettingName.DECISION_MAKER_ORG_ID
).data["id"]
except AhjoSetting.DoesNotExist:
- raise MissingOrganizationIdentifier(
+ raise MissingOrganizationIdentifierError(
"No organization identifier found in the database."
)
@@ -177,7 +181,8 @@ def org_identifier() -> str:
if not setting.data:
raise ValueError("Signer organization identifier list is empty")
- # If data is string or other type, you might want to validate it's actually a list
+ # If data is string or other type, you might want to validate it's actually
+ # a list
if not isinstance(setting.data, list):
raise ValueError("Signer organization identifier must be a list")
@@ -222,11 +227,9 @@ def request(self) -> AhjoRequest:
@ahjo_token.setter
def ahjo_token(self, token: AhjoToken) -> None:
if not isinstance(token, AhjoToken):
- raise InvalidAhjoTokenException(
- "Invalid token, not an instance of AhjoToken"
- )
+ raise InvalidAhjoTokenError("Invalid token, not an instance of AhjoToken")
if not token.access_token or not token.expires_in or not token.refresh_token:
- raise InvalidAhjoTokenException("Invalid token, token is missing data")
+ raise InvalidAhjoTokenError("Invalid token, token is missing data")
self._ahjo_token = token
def prepare_ahjo_headers(self) -> dict:
@@ -235,7 +238,7 @@ def prepare_ahjo_headers(self) -> dict:
If the request is a subscription request, the headers are prepared \
without a callback address in the JSON payload and the Accept and X-CallbackURL headers \
are not needed.
- """
+ """ # noqa: E501
headers_dict = {
"Authorization": f"Bearer {self.ahjo_token.access_token}",
@@ -287,7 +290,8 @@ def send_request_to_ahjo(
timeout=self._timeout,
data=data,
)
- # Create new ahjo status or update the last ahjo_status if a similar status exists,
+ # Create new ahjo status or update the last ahjo_status if a similar status
+ # exists,
# which means that this is a retry
if hasattr(self._request, "result_status") and self._request.result_status:
AhjoStatus.objects.update_or_create(
@@ -309,14 +313,20 @@ def send_request_to_ahjo(
else:
return self._request.application, response.json()
except MissingHandlerIdError as e:
- error_message = f"Missing handler id for application {self.request.application.application_number}: {e}"
+ error_message = (
+ "Missing handler id for application"
+ f" {self.request.application.application_number}: {e}"
+ )
LOGGER.error(error_message)
self.write_error_to_ahjo_status(
context=error_message,
message_to_handler="Hakemuksen käsittelijältä puuttuu AD-tunnus.",
)
except MissingAhjoCaseIdError as e:
- error_message = f"Missing Ahjo case id for application {self.request.application.application_number}: {e}"
+ error_message = (
+ "Missing Ahjo case id for application"
+ f" {self.request.application.application_number}: {e}"
+ )
LOGGER.error(error_message)
self.write_error_to_ahjo_status(
context=error_message,
@@ -333,7 +343,7 @@ def send_request_to_ahjo(
message_to_handler="Ahjo-pyynnössä tapahtui verkkoyhteysvirhe.",
)
LOGGER.error(error_message)
- except AhjoApiClientException as e:
+ except AhjoApiClientError as e:
LOGGER.error(
f"An error occurred while sending {self._request} to Ahjo: {e}"
)
@@ -361,7 +371,9 @@ def handle_http_error(self, e: requests.exceptions.HTTPError) -> None:
error_message += f"{error_json}"
self.write_error_to_ahjo_status(
context=error_json,
- message_to_handler="Ahjo palautti validaatiovirheen tai muun HTTP-virheen.",
+ message_to_handler=(
+ "Ahjo palautti validaatiovirheen tai muun HTTP-virheen."
+ ),
)
LOGGER.error(error_message)
@@ -371,13 +383,15 @@ def format_error_message(
e: Union[requests.exceptions.HTTPError, requests.exceptions.RequestException],
application_number: Union[int, None] = None,
) -> str:
- return f"A HTTP or network error occurred while sending {self.request} for application \
- {application_number} to Ahjo: {e}"
+ return (
+ f"A HTTP or network error occurred while sending {self.request} for"
+ f" application {application_number} to Ahjo: {e}"
+ )
def write_error_to_ahjo_status(self, context: str, message_to_handler: str) -> None:
"""Write the error message to the Ahjo status of the application for all requests that have an application.
The DecisionMaker request does not have an application, so it does not have an Ahjo status.
- """
+ """ # noqa: E501
if self.request.has_application:
AhjoErrorWriter.write_to_validation_error(
AhjoFormattedError(
diff --git a/backend/benefit/applications/services/ahjo_decision_service.py b/backend/benefit/applications/services/ahjo_decision_service.py
index f33904c259..788d2d0e8b 100644
--- a/backend/benefit/applications/services/ahjo_decision_service.py
+++ b/backend/benefit/applications/services/ahjo_decision_service.py
@@ -22,7 +22,7 @@ def replace_decision_template_placeholders(
application: Application,
decision_maker=None,
) -> str:
- """Replace the placeholders starting with $ in the decision template with real data"""
+ """Replace the placeholders starting with $ in the decision template with real data""" # noqa: E501
text_to_replace = Template(text_to_replace)
start_date = (
application.calculation.start_date.strftime("%d.%m.%Y")
@@ -43,7 +43,7 @@ def replace_decision_template_placeholders(
if decision_type == DecisionType.ACCEPTED
else ""
),
- benefit_date_range=(f"{start_date} - {end_date}"),
+ benefit_date_range=f"{start_date} - {end_date}",
)
except AhjoDecisionError as e:
raise ValueError(f"Error in preparing the decision proposal template: {e}")
diff --git a/backend/benefit/applications/services/ahjo_integration.py b/backend/benefit/applications/services/ahjo_integration.py
index b4df349cc0..24a19b5d4b 100644
--- a/backend/benefit/applications/services/ahjo_integration.py
+++ b/backend/benefit/applications/services/ahjo_integration.py
@@ -19,6 +19,8 @@
from applications.enums import (
AhjoStatus as AhjoStatusEnum,
+)
+from applications.enums import (
ApplicationStatus,
AttachmentType,
)
@@ -91,15 +93,15 @@ class ExportFileInfo:
ACCEPTED_TITLE = "Työllisyydenhoidon Helsinki-lisän myöntäminen työnantajille"
-REJECTED_TITLE = (
- "Työllisyydenhoidon Helsinki-lisä, kielteiset päätökset työnantajille"
-)
+REJECTED_TITLE = "Työllisyydenhoidon Helsinki-lisä, kielteiset päätökset työnantajille"
JINJA_TEMPLATES_COMPOSED = {
TEMPLATE_ID_COMPOSED_ACCEPTED_PUBLIC: {
"path": BENEFIT_TEMPLATE_FILENAME,
- "file_name": "Liite 1 Helsinki-lisä hyväksytyt päätökset koontiliite julkinen.pdf",
+ "file_name": (
+ "Liite 1 Helsinki-lisä hyväksytyt päätökset koontiliite julkinen.pdf"
+ ),
"context": {
"title": ACCEPTED_TITLE,
"show_ahjo_rows": True,
@@ -110,7 +112,9 @@ class ExportFileInfo:
},
TEMPLATE_ID_COMPOSED_DECLINED_PUBLIC: {
"path": BENEFIT_TEMPLATE_FILENAME,
- "file_name": "Liite 1 Helsinki-lisä kielteiset päätökset koontiliite julkinen.pdf",
+ "file_name": (
+ "Liite 1 Helsinki-lisä kielteiset päätökset koontiliite julkinen.pdf"
+ ),
"context": {
"title": REJECTED_TITLE,
"show_ahjo_rows": False,
@@ -121,8 +125,10 @@ class ExportFileInfo:
},
TEMPLATE_ID_COMPOSED_ACCEPTED_PRIVATE: {
"path": BENEFIT_TEMPLATE_FILENAME,
- "file_name": "Liite 2 Helsinki-lisä hyväksytyt päätökset "
- "koontiliite salassa pidettävä.pdf",
+ "file_name": (
+ "Liite 2 Helsinki-lisä hyväksytyt päätökset "
+ "koontiliite salassa pidettävä.pdf"
+ ),
"context": {
"title": ACCEPTED_TITLE,
"show_ahjo_rows": True,
@@ -134,8 +140,10 @@ class ExportFileInfo:
},
TEMPLATE_ID_COMPOSED_DECLINED_PRIVATE: {
"path": BENEFIT_TEMPLATE_FILENAME,
- "file_name": "Liite 2 Helsinki-lisä kielteiset päätökset "
- "koontiliite salassa pidettävä.pdf",
+ "file_name": (
+ "Liite 2 Helsinki-lisä kielteiset päätökset "
+ "koontiliite salassa pidettävä.pdf"
+ ),
"context": {
"title": REJECTED_TITLE,
"show_ahjo_rows": False,
@@ -150,7 +158,9 @@ class ExportFileInfo:
JINJA_TEMPLATES_SINGLE = {
TEMPLATE_ID_BENEFIT_WITH_DE_MINIMIS_AID: {
"path": BENEFIT_TEMPLATE_FILENAME,
- "file_name": "Liite {attachment_number} [{company_name}] hakemukset (de minimis).pdf",
+ "file_name": (
+ "Liite {attachment_number} [{company_name}] hakemukset (de minimis).pdf"
+ ),
"context": {
"title": ACCEPTED_TITLE,
"show_ahjo_rows": True,
@@ -172,8 +182,10 @@ class ExportFileInfo:
},
TEMPLATE_ID_BENEFIT_DECLINED: {
"path": BENEFIT_TEMPLATE_FILENAME,
- "file_name": "Liite {attachment_number} [{company_name}] Työllisyydenhoidon Helsinki-lisä, "
- "kielteiset päätökset.pdf",
+ "file_name": (
+ "Liite {attachment_number} [{company_name}] Työllisyydenhoidon"
+ " Helsinki-lisä, kielteiset päätökset.pdf"
+ ),
"context": {
"title": REJECTED_TITLE,
"show_ahjo_rows": False,
@@ -343,9 +355,11 @@ def generate_single_approved_file(
return generate_pdf(
apps=apps,
template_config=JINJA_TEMPLATES_SINGLE[
- TEMPLATE_ID_BENEFIT_WITH_DE_MINIMIS_AID
- if any(filter(_get_granted_as_de_minimis_aid, apps))
- else TEMPLATE_ID_BENEFIT_WITHOUT_DE_MINIMIS_AID
+ (
+ TEMPLATE_ID_BENEFIT_WITH_DE_MINIMIS_AID
+ if any(filter(_get_granted_as_de_minimis_aid, apps))
+ else TEMPLATE_ID_BENEFIT_WITHOUT_DE_MINIMIS_AID
+ )
],
company=company,
attachment_number=attachment_number,
@@ -407,7 +421,7 @@ def export_application_batch(batch) -> bytes:
def generate_application_attachment(
application: Application, type: AttachmentType, decision: AhjoDecisionText = None
) -> Attachment:
- """Generate and save an Attachment of the requested type for the given application"""
+ """Generate and save an Attachment of the requested type for the given application""" # noqa: E501
if type == AttachmentType.PDF_SUMMARY:
attachment_data = generate_application_summary_file(application)
attachment_filename = (
@@ -433,7 +447,8 @@ def generate_application_attachment(
attachment_file = ContentFile(attachment_data, attachment_filename)
if type == AttachmentType.PDF_SUMMARY:
- # As there should only exist one pdf summary, update or create the attachment if it is one
+ # As there should only exist one pdf summary, update or create the attachment if
+ # it is one
attachment, _ = Attachment.objects.update_or_create(
application=application,
attachment_type=type,
@@ -518,8 +533,8 @@ def update_application_summary_record_in_ahjo(
if application.ahjo_status.latest().error_from_ahjo:
# If there are errors from Ahjo, do not send the update request
raise ValueError(
- f"Application {application.id} has errors \
-in Ahjo status {application.ahjo_status.latest().status}, not sending {ahjo_request}."
+ f"Application {application.id} has errors in Ahjo status"
+ f" {application.ahjo_status.latest().status}, not sending {ahjo_request}."
)
ahjo_client = AhjoApiClient(ahjo_token, ahjo_request)
@@ -568,8 +583,8 @@ def send_decision_proposal_to_ahjo(
status=AhjoStatusEnum.DECISION_PROPOSAL_ACCEPTED
)
raise DecisionProposalAlreadyAcceptedError(
- f"The application \
-already has a decision proposal accepted in Ahjo at {existing_status.created_at}. Not sending a new one.",
+ "The application already has a decision proposal accepted in Ahjo at"
+ f" {existing_status.created_at}. Not sending a new one.",
existing_status,
)
@@ -611,8 +626,8 @@ def send_decision_proposal_to_ahjo(
return (None, None)
except DecisionProposalError as e:
LOGGER.error(
- f"Error in sending decision proposal payload\
- for application {application.application_number}: {e}"
+ "Error in sending decision proposal payload for application"
+ f" {application.application_number}: {e}"
)
return (None, None)
response, response_text = ahjo_client.send_request_to_ahjo(data)
diff --git a/backend/benefit/applications/services/ahjo_payload.py b/backend/benefit/applications/services/ahjo_payload.py
index dc68fb1567..442c5da874 100644
--- a/backend/benefit/applications/services/ahjo_payload.py
+++ b/backend/benefit/applications/services/ahjo_payload.py
@@ -7,9 +7,9 @@
from applications.enums import AhjoRecordTitle, AhjoRecordType, AttachmentType
from applications.models import (
+ APPLICATION_LANGUAGE_CHOICES,
AhjoDecisionText,
Application,
- APPLICATION_LANGUAGE_CHOICES,
Attachment,
)
from common.utils import hash_file
@@ -28,7 +28,7 @@ class AhjoTitle:
like created or modified date, and application number.
prefix (str): A string to be added before the date in the title.
suffix (str): A string to be added after the date in the title.
- """
+ """ # noqa: E501
application: Application = None
prefix: str = ""
@@ -44,8 +44,11 @@ def format_title_string(self, formatted_date: str, application_number: str) -> s
Returns:
str: A formatted title string that includes the prefix, date, suffix, and application number.
- """
- return f"{AhjoRecordTitle.APPLICATION}{self.prefix} {formatted_date},{self.suffix} {application_number}"
+ """ # noqa: E501
+ return (
+ f"{AhjoRecordTitle.APPLICATION}{self.prefix} {formatted_date},{self.suffix}"
+ f" {application_number}"
+ )
@dataclass
@@ -57,7 +60,7 @@ class OpenCaseRecordTitle(AhjoTitle):
Methods:
__str__(): Returns the formatted string representation of the open case title.
- """
+ """ # noqa: E501
def __str__(self):
"""
@@ -65,7 +68,7 @@ def __str__(self):
Returns:
str: The formatted title string.
- """
+ """ # noqa: E501
formatted_date = self.application.created_at.strftime("%d.%m.%Y")
return self.format_title_string(
formatted_date, self.application.application_number
@@ -86,7 +89,7 @@ class UpdateRecordsRecordTitle(AhjoTitle):
Methods:
__str__(): Returns the formatted string representation of the update record title.
- """
+ """ # noqa: E501
prefix: str = field(default=", täydennys")
attachment_created_at: datetime = None
@@ -119,7 +122,7 @@ class AddRecordsRecordTitle(AhjoTitle):
Methods:
__str__(): Returns the formatted string representation of the additional record title.
- """
+ """ # noqa: E501
prefix: str = field(default=", täydennys")
attachment_created_at: datetime = None
@@ -154,7 +157,7 @@ class AhjoBaseRecordTitle(AhjoTitle):
Methods:
set_suffix(): Updates the suffix to include the current and total numbers.
__str__(): Returns the formatted string representation of the base record title.
- """
+ """ # noqa: E501
current: int = 0
total: int = 0
@@ -162,7 +165,7 @@ class AhjoBaseRecordTitle(AhjoTitle):
def set_suffix(self):
"""
Updates the suffix with the current and total items, forming a string like "liite 1/5".
- """
+ """ # noqa: E501
self.suffix = f" liite {self.current}/{self.total},"
def __str__(self):
@@ -183,15 +186,16 @@ def __str__(self):
def prepare_case_title(application: Application, company_name: str) -> str:
"""Prepare the case title for Ahjo"""
- full_title = f"Avustukset työnantajille, työllisyyspalvelut, \
-Helsinki-lisä, {company_name}, \
-hakemus {application.application_number}"
+ full_title = (
+ f"Avustukset työnantajille, työllisyyspalvelut, Helsinki-lisä, {company_name},"
+ f" hakemus {application.application_number}"
+ )
return full_title
def prepare_final_case_title(application: Application, limit: int = 150) -> str:
"""Prepare the final case title for Ahjo, if the full title length is over the given limit, \
- truncate the company name to fit the limit."""
+ truncate the company name to fit the limit.""" # noqa: E501
full_case_title = prepare_case_title(application, application.company.name)
length_of_full_title = len(full_case_title)
@@ -218,7 +222,7 @@ def truncate_from_end_of_string(string_to_truncate: str, limit: int):
def resolve_payload_language(application: Application) -> str:
- """Ahjo cannot at the moment handle en and sv language cases, so if always return fi"""
+ """Ahjo cannot at the moment handle en and sv language cases, so if always return fi""" # noqa: E501
return APPLICATION_LANGUAGE_CHOICES[0][0]
@@ -301,7 +305,7 @@ def _prepare_record(
handler: User,
publicity_class: str = "Salassa pidettävä",
ahjo_version_series_id: str = None,
- language: str = "fi", # TODO refactor so all these parameters are passes as a dataclass
+ language: str = "fi", # TODO refactor so all these parameters are passes as a dataclass # noqa: E501
):
"""Prepare a single record dict for Ahjo."""
@@ -372,7 +376,9 @@ def _prepare_case_records(
)
document_record = _prepare_record(
- record_title=f"{AhjoBaseRecordTitle(application=application, current=position, total=total_attachments)}",
+ record_title=(
+ f"{AhjoBaseRecordTitle(application=application, current=position, total=total_attachments)}" # noqa: E501
+ ),
record_type=AhjoRecordType.ATTACHMENT,
acquired=attachment.created_at.isoformat("T", "seconds"),
documents=[_prepare_record_document_dict(attachment)],
@@ -437,7 +443,8 @@ def prepare_update_application_payload(
in this case it only contains a Records dict"""
if not pdf_summary.ahjo_version_series_id:
raise ValueError(
- f"Attachment for {application.application_number} must have a ahjo_version_series_id for update."
+ f"Attachment for {application.application_number} must have a"
+ " ahjo_version_series_id for update."
)
language = resolve_payload_language(application)
title = UpdateRecordsRecordTitle(
diff --git a/backend/benefit/applications/services/ahjo_xml_builder.py b/backend/benefit/applications/services/ahjo_xml_builder.py
index f3c040dcbb..55d48e6ce9 100644
--- a/backend/benefit/applications/services/ahjo_xml_builder.py
+++ b/backend/benefit/applications/services/ahjo_xml_builder.py
@@ -14,9 +14,9 @@
from applications.enums import ApplicationStatus
from applications.models import (
+ APPLICATION_LANGUAGE_CHOICES,
AhjoDecisionText,
Application,
- APPLICATION_LANGUAGE_CHOICES,
)
from calculator.enums import RowType
from calculator.models import Calculation, CalculationRow
@@ -70,17 +70,20 @@ def validate_against_schema(
return True # Return True if no exception was raised
except XMLSchemaParseError as e:
LOGGER.error(
- f"Decision proposal XML Schema Error for application {self.application.application_number}: {e}"
+ "Decision proposal XML Schema Error for application"
+ f" {self.application.application_number}: {e}"
)
raise
except XMLSyntaxError as e:
LOGGER.error(
- f"Decision proposal XML Syntax Error for application {self.application.application_number}: {e}"
+ "Decision proposal XML Syntax Error for application"
+ f" {self.application.application_number}: {e}"
)
raise
except etree.DocumentInvalid as e:
LOGGER.error(
- f"Decision proposal Validation Error for application {self.application.application_number}: {e}"
+ "Decision proposal Validation Error for application"
+ f" {self.application.application_number}: {e}"
)
raise
@@ -149,7 +152,10 @@ def generate_xml(self) -> AhjoXMLString:
def _get_period_rows_for_xml(
self,
calculation: Calculation,
- ) -> Tuple[CalculationRow, List[CalculationRow],]:
+ ) -> Tuple[
+ CalculationRow,
+ List[CalculationRow],
+ ]:
total_amount_row = calculation.rows.filter(
row_type=RowType.HELSINKI_BENEFIT_TOTAL_EUR
).first()
@@ -172,7 +178,7 @@ def _prepare_multiple_period_rows(
there will be multiple pairs of sub total rows and a corresponding monthly eur rows.
Here we prepare the calculation rows per payment period by looping through the calculation rows
and parsing the data into a list of BenefitPeriodRows.
- """
+ """ # noqa: E501
calculation_rows_for_xml = []
for idx, r in enumerate(calculation_rows):
@@ -202,7 +208,7 @@ def _prepare_single_period_row(
) -> List[BenefitPeriodRow]:
"""In the case where there is only one benefit period,
we combine the monthly eur row and the salary benefit total row into a single BenefitPeriodRow.
- """
+ """ # noqa: E501
calculation_rows_for_xml = []
calculation_rows_for_xml.append(
BenefitPeriodRow(
@@ -233,7 +239,8 @@ def get_context_for_accepted_decision_xml(self) -> dict:
total_amount_row, calculation_rows = self._get_period_rows_for_xml(
self.application.calculation
)
- # If there is only one period, we can combine the monthly eur row and the total row into a single row
+ # If there is only one period, we can combine the monthly eur row and the total
+ # row into a single row
if (
len(calculation_rows) == 1
and calculation_rows[0].row_type == RowType.HELSINKI_BENEFIT_MONTHLY_EUR
@@ -252,4 +259,7 @@ def get_context_for_accepted_decision_xml(self) -> dict:
def generate_xml_file_name(self) -> str:
date_str = self.application.created_at.strftime("%d.%m.%Y")
- return f"Hakemus {date_str} päätöksen liite {self.application.application_number}.xml"
+ return (
+ f"Hakemus {date_str} päätöksen liite"
+ f" {self.application.application_number}.xml"
+ )
diff --git a/backend/benefit/applications/services/application_alteration_csv_report.py b/backend/benefit/applications/services/application_alteration_csv_report.py
index de200badd9..9d64d8fdd4 100644
--- a/backend/benefit/applications/services/application_alteration_csv_report.py
+++ b/backend/benefit/applications/services/application_alteration_csv_report.py
@@ -59,14 +59,18 @@ def get_company_address(self, alteration: ApplicationAlteration) -> str:
def get_company_contact_person(self, alteration: ApplicationAlteration) -> str:
application = alteration.application
- return f"{application.company_contact_person_first_name} {application.company_contact_person_last_name} \
- {application.company_contact_person_email} {application.company_contact_person_phone_number}"
+ return (
+ f"{application.company_contact_person_first_name}"
+ f" {application.company_contact_person_last_name} "
+ f" {application.company_contact_person_email}"
+ f" {application.company_contact_person_phone_number}"
+ )
def get_recovery_justification(self, alteration: ApplicationAlteration) -> str:
return alteration.recovery_justification
@property
- def CSV_COLUMNS(self):
+ def csv_columns(self):
columns = [
CsvColumn("Viitetiedot", "application.application_number"),
CsvColumn(
diff --git a/backend/benefit/applications/services/applications_csv_report.py b/backend/benefit/applications/services/applications_csv_report.py
index dfbf241c50..306fdb6ce0 100644
--- a/backend/benefit/applications/services/applications_csv_report.py
+++ b/backend/benefit/applications/services/applications_csv_report.py
@@ -32,7 +32,7 @@ def get_export_notes(application):
"""
Report situations where the data does not fit in the fixed number of CSV columns.
These cases should not happen, but if they do, then it's important to have some kind of notification about it.
- """
+ """ # noqa: E501
notes = []
if (
application.de_minimis_aid_set.count()
@@ -102,7 +102,7 @@ class ApplicationsCsvService(CsvExportBase):
For easier processing, if an application would need two Ahjo rows, the two rows are produced in the output.
- """
+ """ # noqa: E501
def __init__(self, applications, prune_sensitive_data=False):
self.applications = applications
@@ -112,7 +112,7 @@ def __init__(self, applications, prune_sensitive_data=False):
def query_instalment_by_number(
self, application: Application, number: int
) -> Instalment:
- """Return the actual payable amount of the currently accepted and due instalment"""
+ """Return the actual payable amount of the currently accepted and due instalment""" # noqa: E501
try:
instalment = application.calculation.instalments.get(
instalment_number=number,
@@ -120,12 +120,13 @@ def query_instalment_by_number(
return instalment
except ObjectDoesNotExist:
LOGGER.info(
- f"Valid payable Instalment not found for application {application.application_number}"
+ "Valid payable Instalment not found for application"
+ f" {application.application_number}"
)
except MultipleObjectsReturned:
LOGGER.error(
- f"Multiple payable Instalments found for application \
- {application.application_number}, there should be only one"
+ "Multiple payable Instalments found for application "
+ f" {application.application_number}, there should be only one"
)
def get_instalment_1_amount(self, application: Application) -> decimal.Decimal:
@@ -172,7 +173,7 @@ def get_instalment_2_due_date(self, application: Application) -> date:
return ""
@property
- def CSV_COLUMNS(self) -> List[CsvColumn]:
+ def csv_columns(self) -> List[CsvColumn]:
calculated_benefit_amount = "calculation.calculated_benefit_amount"
columns = [
@@ -332,9 +333,10 @@ def CSV_COLUMNS(self) -> List[CsvColumn]:
"Tarkastajan sähköposti, P2P", "batch.p2p_inspector_email"
),
csv_default_column("Hyväksyjän nimi P2P", "batch.p2p_checker_name"),
- # In case there are multiple rows per application, always have the nth ahjo row
- # in the same column.
- # The row data here comes from calculation.ahjo_rows[application_row_idx - 1]
+ # In case there are multiple rows per application, always have the nth ahjo
+ # row in the same column.
+ # The row data here comes from
+ # calculation.ahjo_rows[application_row_idx - 1]
CsvColumn(
"Siirrettävä Ahjo-rivi / tyyppi",
current_ahjo_row_field_getter("row_type"),
@@ -489,14 +491,14 @@ def get_applications(self):
def get_row_items(self):
with translation.override("fi"):
for application in self.get_applications():
- for application_row_idx, unused in enumerate(
+ for application_row_idx, _ in enumerate(
application.ahjo_rows or [None]
):
# The CSV output is easier to process in PowerBI
# if the rows belonging to the same application are numbered.
- # application_row_idx is also used for storing the "current" ahjo row.
- # application_row_idx starts at 1, which must be taken into account
- # when indexing application.ahjo_rows
+ # application_row_idx is also used for storing the "current" ahjo
+ # row. application_row_idx starts at 1, which must be taken into
+ # account when indexing application.ahjo_rows
application.application_row_idx = application_row_idx + 1
yield application
diff --git a/backend/benefit/applications/services/applications_power_bi_csv_report.py b/backend/benefit/applications/services/applications_power_bi_csv_report.py
index faa1d62ead..3b96695f93 100644
--- a/backend/benefit/applications/services/applications_power_bi_csv_report.py
+++ b/backend/benefit/applications/services/applications_power_bi_csv_report.py
@@ -20,7 +20,7 @@
class ApplicationsPowerBiCsvService(ApplicationsCsvService):
"""
- This subclass customizes the CSV_COLUMNS for a different export format.
+ This subclass customizes the csv_columns for a different export format.
"""
def get_completed_in_talpa_date(
@@ -42,7 +42,7 @@ def get_alteration_amount(self, application: Application) -> float:
return sum
@property
- def CSV_COLUMNS(self):
+ def csv_columns(self):
calculated_benefit_amount = "calculation.calculated_benefit_amount"
columns = [
diff --git a/backend/benefit/applications/services/change_history.py b/backend/benefit/applications/services/change_history.py
index e06dfa99d3..54bcb96475 100644
--- a/backend/benefit/applications/services/change_history.py
+++ b/backend/benefit/applications/services/change_history.py
@@ -55,7 +55,8 @@ def _get_change_set_base(new_record: ModelChange):
"user": {
"staff": getattr(new_record.history_user, "is_staff", False),
"name": (
- f"{new_record.history_user.first_name} {new_record.history_user.last_name[0]}."
+ f"{new_record.history_user.first_name}"
+ f" {new_record.history_user.last_name[0]}."
if new_record.history_user
and new_record.history_user.first_name
and new_record.history_user.last_name
@@ -75,11 +76,11 @@ def _filter_and_format_changes(
return list(
map(
lambda change: _format_change_dict(change, relation_name),
- filter( # Only accept those changes that are within the threshold delta_time and/or not excluded field
+ filter( # Only accept those changes that are within the threshold delta_time and/or not excluded field # noqa: E501
lambda change: not _is_history_change_excluded(change, excluded_fields)
and (
delta_time
- is None # We'll ignore this check for application changes as delta_time's not present
+ is None # We'll ignore this check for application changes as delta_time's not present # noqa: E501
or 0 <= delta_time <= look_up_for_application_save_in_seconds
),
changes,
@@ -139,7 +140,7 @@ def get_application_change_history(application: Application) -> list:
application_diffs = []
- for i in range(0, len(application_history) - 1):
+ for i in range(len(application_history) - 1):
diff = application_history[i].diff_against(application_history[i + 1])
application_diffs.append(diff)
@@ -154,7 +155,7 @@ def get_application_change_history(application: Application) -> list:
employee_history = application.employee.history.filter(employee_q_objects)
employee_diffs = []
- for i in range(0, len(employee_history) - 1):
+ for i in range(len(employee_history) - 1):
diff = employee_history[i].diff_against(employee_history[i + 1])
employee_diffs.append(diff)
diff --git a/backend/benefit/applications/services/clamav.py b/backend/benefit/applications/services/clamav.py
index 428ba900c7..603be244db 100644
--- a/backend/benefit/applications/services/clamav.py
+++ b/backend/benefit/applications/services/clamav.py
@@ -36,11 +36,11 @@ def scan(self, name, _bytes):
or response.status_code != 200
or not response.json()["success"]
):
- raise FileScanException(name)
+ raise FileScanError(name)
for entry in response.json()["data"]["result"]:
if bool(entry["is_infected"]):
- raise FileInfectedException(entry["name"], entry["viruses"])
+ raise FileInfectedError(entry["name"], entry["viruses"])
def version(self):
if not self.BASE_URL:
@@ -57,12 +57,12 @@ def ping(self):
return response.json()
-class FileScanException(Exception):
+class FileScanError(Exception):
def __init__(self, file_name):
self.file_name = file_name
-class FileInfectedException(Exception):
+class FileInfectedError(Exception):
def __init__(self, file_name, viruses):
self.file_name = file_name
self.viruses = viruses
diff --git a/backend/benefit/applications/services/clone_application.py b/backend/benefit/applications/services/clone_application.py
index 019691b9de..e5ecba2d96 100644
--- a/backend/benefit/applications/services/clone_application.py
+++ b/backend/benefit/applications/services/clone_application.py
@@ -5,6 +5,8 @@
from applications.enums import (
AhjoStatus as AhjoStatusEnum,
+)
+from applications.enums import (
ApplicationOrigin,
ApplicationStatus,
ApplicationStep,
@@ -38,41 +40,39 @@ def clone_application_based_on_other(
company.city = company.city if len(company.city) > 0 else "Testilä"
cloned_application = Application(
- **{
- "alternative_company_city": application_base.alternative_company_city,
- "alternative_company_postcode": application_base.alternative_company_postcode,
- "alternative_company_street_address": application_base.alternative_company_street_address,
- "applicant_language": "fi",
- "application_origin": (
- application_base.application_origin
- if clone_all_data
- else ApplicationOrigin.APPLICANT
- ),
- "application_step": ApplicationStep.STEP_1,
- "archived": False,
- "association_has_business_activities": application_base.association_has_business_activities
- or False,
- "association_immediate_manager_check": application_base.association_immediate_manager_check
- or False,
- "benefit_type": "salary_benefit",
- "co_operation_negotiations": application_base.co_operation_negotiations,
- "co_operation_negotiations_description": application_base.co_operation_negotiations_description,
- "company_bank_account_number": application_base.company_bank_account_number,
- "company_contact_person_email": application_base.company_contact_person_email,
- "company_contact_person_first_name": application_base.company_contact_person_first_name,
- "company_contact_person_last_name": application_base.company_contact_person_last_name,
- "company_contact_person_phone_number": application_base.company_contact_person_phone_number,
- "company_department": application_base.company_department,
- "company_form": application_base.company_form,
- "company_form_code": company.company_form_code,
- "company_name": application_base.company_name,
- "de_minimis_aid": application_base.de_minimis_aid,
- "status": ApplicationStatus.DRAFT,
- "official_company_street_address": company.street_address,
- "official_company_city": application_base.official_company_city,
- "official_company_postcode": application_base.official_company_postcode,
- "use_alternative_address": application_base.use_alternative_address,
- }
+ alternative_company_city=application_base.alternative_company_city,
+ alternative_company_postcode=application_base.alternative_company_postcode,
+ alternative_company_street_address=application_base.alternative_company_street_address,
+ applicant_language="fi",
+ application_origin=(
+ application_base.application_origin
+ if clone_all_data
+ else ApplicationOrigin.APPLICANT
+ ),
+ application_step=ApplicationStep.STEP_1,
+ archived=False,
+ association_has_business_activities=application_base.association_has_business_activities
+ or False,
+ association_immediate_manager_check=application_base.association_immediate_manager_check
+ or False,
+ benefit_type="salary_benefit",
+ co_operation_negotiations=application_base.co_operation_negotiations,
+ co_operation_negotiations_description=application_base.co_operation_negotiations_description,
+ company_bank_account_number=application_base.company_bank_account_number,
+ company_contact_person_email=application_base.company_contact_person_email,
+ company_contact_person_first_name=application_base.company_contact_person_first_name,
+ company_contact_person_last_name=application_base.company_contact_person_last_name,
+ company_contact_person_phone_number=application_base.company_contact_person_phone_number,
+ company_department=application_base.company_department,
+ company_form=application_base.company_form,
+ company_form_code=company.company_form_code,
+ company_name=application_base.company_name,
+ de_minimis_aid=application_base.de_minimis_aid,
+ status=ApplicationStatus.DRAFT,
+ official_company_street_address=company.street_address,
+ official_company_city=application_base.official_company_city,
+ official_company_postcode=application_base.official_company_postcode,
+ use_alternative_address=application_base.use_alternative_address,
)
company.save()
diff --git a/backend/benefit/applications/services/csv_export_base.py b/backend/benefit/applications/services/csv_export_base.py
index 79734faf3d..947301bbe4 100644
--- a/backend/benefit/applications/services/csv_export_base.py
+++ b/backend/benefit/applications/services/csv_export_base.py
@@ -37,7 +37,7 @@ def nested_queryset_attr(
* returns item.attr_name[idx].nested_attr_name
* In case the attribute is missing, return the default value
* dotted attribute access (like "a.b" is supported for attr_name and nested_attr_name
- """
+ """ # noqa: E501
def getter(item):
try:
@@ -57,16 +57,16 @@ class CsvExportBase:
Common code for CSV export interfaces.
Classes deriving from CsvExportBase need to define:
- * CSV_COLUMNS: a list of CsvColumn objects
+ * csv_columns: a list of CsvColumn objects
* get_row_items: a function that returns a sequence of any objects. These objects
must be compatible with the CsvColumn.cell_data_source (see get_csv_cell_list_lines_generator)
- """
+ """ # noqa: E501
CSV_DELIMITER = ";"
FILE_ENCODING = "utf-8"
def _get_header_row(self) -> List[str]:
- return [col.heading for col in self.CSV_COLUMNS]
+ return [col.heading for col in self.csv_columns]
def write_csv_file(self, path) -> None:
csv_string = self.get_csv_string()
@@ -84,17 +84,17 @@ def get_csv_cell_list_lines_generator(
self,
) -> Generator[List[Union[str, int, decimal.Decimal, datetime.date]], None, None]:
"""
- Iterate through the objects returned by get_row_items. Use the CsvColumn objects in CSV_COLUMNS to
+ Iterate through the objects returned by get_row_items. Use the CsvColumn objects in csv_columns to
construct a CSV row from each item. Notes:
* If cell_data_source is callable, then each item is passed as a paremeter to it,
and the resulting value is used to construct the CSV cell value
* if cell_data_source is a string, then it is treated as a dotted attribute reference (like "x" or "a.b")
and the corresponding attribute should be found in the item
- """
+ """ # noqa: E501
yield self._get_header_row()
for item in self.get_row_items():
line = []
- for column in self.CSV_COLUMNS:
+ for column in self.csv_columns:
if callable(column.cell_data_source):
cell_value = column.cell_data_source(item)
else:
@@ -127,7 +127,7 @@ def get_csv_string_lines_generator(
:return: Generator which generates list of strings that each end with '\r\n'.
Passing remove_quotes=True will disable quoting of values as it is required by the Talpa integration.
Passing add_bom=True will add a BOM (Byte Order Mark) at the beginning of the file.
- """
+ """ # noqa: E501
quoting = csv.QUOTE_NONE if remove_quotes else csv.QUOTE_NONNUMERIC
io = StringIO()
@@ -140,9 +140,9 @@ def get_csv_string_lines_generator(
for line in self.get_csv_cell_list_lines_generator():
line_length_set.add(len(line))
- assert (
- len(line_length_set) == 1
- ), "Each CSV line must have same column count"
+ assert len(line_length_set) == 1, (
+ "Each CSV line must have same column count"
+ )
csv_writer.writerow(line)
yield io.getvalue()
# Reset StringIO object
diff --git a/backend/benefit/applications/services/generate_application_summary.py b/backend/benefit/applications/services/generate_application_summary.py
index 36e3bacd87..8ea374ea9a 100644
--- a/backend/benefit/applications/services/generate_application_summary.py
+++ b/backend/benefit/applications/services/generate_application_summary.py
@@ -45,7 +45,7 @@ def generate_summary_pdf(context) -> bytes:
context = get_context_for_summary_context(application)
return generate_summary_pdf(context)
except Exception as e:
- print(
+ print( # noqa: T201
f"Cannot generate application summary PDF for application {application.id}",
e,
)
diff --git a/backend/benefit/applications/services/talpa_csv_service.py b/backend/benefit/applications/services/talpa_csv_service.py
index 5724158daf..7baf3c5519 100644
--- a/backend/benefit/applications/services/talpa_csv_service.py
+++ b/backend/benefit/applications/services/talpa_csv_service.py
@@ -22,7 +22,7 @@ class TalpaCsvService(ApplicationsCsvService):
def get_relevant_instalment_amount(
self, application: Application
) -> decimal.Decimal:
- """Return the actual payable amount of the currently accepted and due instalment"""
+ """Return the actual payable amount of the currently accepted and due instalment""" # noqa: E501
# TODO remove this flag when the feature is enabled ready for production
if settings.PAYMENT_INSTALMENTS_ENABLED:
try:
@@ -33,18 +33,19 @@ def get_relevant_instalment_amount(
return instalment.amount_after_recoveries
except ObjectDoesNotExist:
LOGGER.error(
- f"Valid payable Instalment not found for application {application.application_number}"
+ "Valid payable Instalment not found for application"
+ f" {application.application_number}"
)
except MultipleObjectsReturned:
LOGGER.error(
- f"Multiple payable Instalments found for application \
-{application.application_number}, there should be only one"
+ "Multiple payable Instalments found for application"
+ f" {application.application_number}, there should be only one"
)
else:
return application.calculation.calculated_benefit_amount
@property
- def CSV_COLUMNS(self):
+ def csv_columns(self):
columns = [
CsvColumn("Hakemusnumero", "application_number"),
CsvColumn("Työnantajan tyyppi", get_organization_type),
diff --git a/backend/benefit/applications/tests/before_after.py b/backend/benefit/applications/tests/before_after.py
index 8c84815397..f2046a5614 100644
--- a/backend/benefit/applications/tests/before_after.py
+++ b/backend/benefit/applications/tests/before_after.py
@@ -1,9 +1,10 @@
import os
+from typing import Optional
from common.tests.conftest import reseed
-def before_test_reseed(no_reseed_for_tests: list[str] = []):
+def before_test_reseed(no_reseed_for_tests: Optional[list[str]] = None):
"""
Tests would fail in CI if same seed is used throughout all tests.
Factories create too many similar objects and database will fail on unique
@@ -11,11 +12,14 @@ def before_test_reseed(no_reseed_for_tests: list[str] = []):
:param no_reseed_for_tests: list of test names that should use the default seed defined in conftest.py
"""
+ if no_reseed_for_tests is None:
+ no_reseed_for_tests = []
+
current_test = os.environ.get("PYTEST_CURRENT_TEST")
for test in no_reseed_for_tests:
if test in current_test:
- print("passing reseed for", current_test)
+ print("passing reseed for", current_test) # noqa: T201
else:
- print("reseeding with", current_test)
+ print("reseeding with", current_test) # noqa: T201
reseed(current_test)
diff --git a/backend/benefit/applications/tests/common.py b/backend/benefit/applications/tests/common.py
index b007446732..995bebae47 100644
--- a/backend/benefit/applications/tests/common.py
+++ b/backend/benefit/applications/tests/common.py
@@ -23,7 +23,7 @@ def check_csv_cell_list_lines_generator(
assert isinstance(column, (str, int, decimal.Decimal, datetime.date))
header_row = rows[0]
- assert header_row == [column.heading for column in csv_export.CSV_COLUMNS]
+ assert header_row == [column.heading for column in csv_export.csv_columns]
def check_csv_string_lines_generator(
@@ -46,7 +46,7 @@ def check_csv_string_lines_generator(
assert (
header_row
== csv_export.CSV_DELIMITER.join(
- (f'"{column.heading}"' for column in csv_export.CSV_COLUMNS)
+ (f'"{column.heading}"' for column in csv_export.csv_columns)
)
+ default_csv_dialect.lineterminator
)
diff --git a/backend/benefit/applications/tests/conftest.py b/backend/benefit/applications/tests/conftest.py
index f08490255d..7228c779a0 100755
--- a/backend/benefit/applications/tests/conftest.py
+++ b/backend/benefit/applications/tests/conftest.py
@@ -20,9 +20,9 @@
DecisionType,
)
from applications.models import (
+ APPLICATION_LANGUAGE_CHOICES,
AhjoSetting,
Application,
- APPLICATION_LANGUAGE_CHOICES,
ApplicationAlteration,
ApplicationBatch,
)
@@ -521,8 +521,8 @@ def pytest_sessionfinish(session, exitstatus):
try:
os.remove(os.path.join(settings.MEDIA_ROOT, file))
except OSError as e:
- print(f"Error while deleting file in media folder: {e}")
- print(f"\nTests finished, deleted {number_of_files} files in the media folder")
+ 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
@pytest.fixture
@@ -611,132 +611,153 @@ def ahjo_decision_detail_response(application_with_ahjo_decision):
name = f"{handler.first_name} {handler.last_name}"
company = application_with_ahjo_decision.company
today = date.today()
- content = f'
\
-\
-\
-Avustuksen myöntäminen, Työllisyyspalvelut, työllisyydenhoidon Helsinki-lisä\
-\
-
16 §
\
-
Avustuksen myöntäminen, Työllisyyspalvelut, työllisyydenhoidon Helsinki-lisä
\
-
HEL 2024-004415 T 02 05 01 00
\
-
Päätös
\
-
Helsinki-lisä-suunnittelija päätti myöntää {company}:lle \
-työnantajan Helsinki-lisää käytettäväksi helsinkiläisen työllistämiseksi \
-448 euroa kuukaudessa palkkatuetulle \
-ajalle 4.12.2023-3.10.2024 ja 800 euroa kuukaudessa ajalle 4.10.2024-3.12.2024, \
-jolta työnantaja ei saa palkkatukea. Yhteensä Helsinki-lisää myönnetään 6080 euroa. \
-
Helsinki-lisään on varattu talousarviossa Helsingin kaupungin \
-Työllisyyspalveluille vuosittain budjetoitu määräraha. Avustuksen kustannukset maksetaan \
-kaupungin Työllisyyspalveluille osoitetusta määrärahasta talousarvion erikseen määritellyltä kohdalta. \
-Työnantajan Helsinki-lisä on aina harkinnanvarainen.
\
-
Päätösteksti
\
-
Helsingin kaupunginhallituksen elinkeinojaosto on 11.9.2023 § 30 päättänyt \
-tukea rahallisesti yksityisen ja kolmannen sektorin työnantajia, \
-jotka tarjoavat työtä kaupungin työllisyydenhoidon kohderyhmiin kuuluville helsinkiläisille.
\
-
Avustus
Kaupunginhallituksen elinkeinojaosto on päätöksellään 11.9.2023 § 30 \
-hyväksynyt työnantajan Helsinki-lisän myöntämistä koskevat ehdot. \
-Helsinki-lisän myöntämisessä noudatetaan lisäksi kaupunginhallituksen 28.10.2019 § 723 \
-hyväksymiä Helsingin kaupungin avustusten yleisohjeita.
\
-
Helsinki-lisä on myönnetty työllistettävän henkilön palkkauksesta aiheutuviin kustannuksiin, \
-ei kuitenkaan bruttopalkkaan siltä ajalta, \
-jolta työnantaja saa myös palkkatukea. Tuen määrään vaikuttavat samoihin kustannuksiin \
-myönnetyt muut tuet (esim. palkkatuki ja oppisopimuksen koulutuskorvaus). \
-Yritykselle ja taloudellista toimintaa harjoittavalle yhteisölle avustus \
-myönnetään vähämerkityksisenä tukena eli ns. de minimis -tukena, ei koskaan yleisen ryhmäpoikkeusasetuksen \
-(komission asetus (EU) N:o 651/2014) perusteella eli ns. RPA-tukena. Yleishyödyllisille yhteisöille avustus myönnetään \
-valtiontukisääntelyn ulkopuolisena tukena, \
-jos yhdistys ei harjoita taloudellista toimintaa.
Avustusta myönnetään valtiontukisäännöissä määrätyn \
-kasautumissäännön sekä tuen enimmäisintensiteetin mukaisesti \
-(tuen määrä suhteessa tukikelpoisiin kustannuksiin). Helsinki-lisä voi olla enintään 800 euroa kuukaudessa. \
-Avustusta ei saa siirtää toisen tahon tai henkilön käytettäväksi. \
-Avustus maksetaan hakemuksessa ilmoitetulle pankkitilille.
\
-
Helsinki-lisää saa käyttää ainoastaan kaupunginhallituksen \
-elinkeinojaoston päätöksen 11.9.2023 §30 mukaisiin tarkoituksiin. \
-Avustuksen saajan tulee viipymättä palauttaa virheellisesti, \
-liikaa tai ilmeisen perusteettomasti saamansa avustus. \
-Väärinkäyttötapauksessa kaupunki voi periä maksetun avustuksen takaisin. \
-Avustuksen saaja sitoutuu antamaan tarvittaessa kaupungille \
-tarvittavat tiedot sen varmistamiseksi, että avustusta ei ole käytetty ehtojen vastaisesti. \
-Mikäli avustus maksetaan ennen päätöksen lainvoimaisuutta, avustuksen saaja sitoutuu palauttamaan \
-jo maksetut avustukset, jos päätös muutoksenhaun johdosta muuttuu.
\
-
Valtiontukiarviointi
Yritykselle ja taloudellista toimintaa harjoittavalle yhteisölle \
-avustus myönnetään vähämerkityksisenä tukena eli ns. de minimis -tukena. \
-Tuen myöntämisessä noudatetaan komission asetusta (EU) 2023/2831, annettu 13.12.2023, \
-Euroopan unionista tehdyn sopimuksen 107 ja 108 artiklan soveltamisesta vähämerkityksiseen \
-tukeen (EUVL L2023/281, 15.12.2023).
\
-
Kullekin hakijalle myönnettävän de minimis -tuen määrä ilmenee hakijakohtaisesta liitteestä. \
-Avustuksen saajalle voidaan myöntää de minimis -tukena enintään 300 000 euroa kuluvan vuoden ja \
-kahden sitä edeltäneen kahden vuoden muodostaman jakson aikana. \
-Avustuksen saaja vastaa siitä, että eri tahojen (mm. ministeriöt, ministeriöiden alaiset viranomaiset, \
-Business Finland, Finnvera Oyj, kunnat, maakuntien liitot) \
-myöntämien de minimis -tukien yhteismäärä ei ylitä tätä määrää. Avustuksen saaja on avustushakemuksessa \
-ilmoittanut kaupungille kaikkien saamiensa de minimis -tukien määrät \
-ja myöntöajankohdat.
\
-
Lisätiedot
\
-
{name}, suunnittelija, puhelin: 12345789
testi@testi.test
\
-
\
-
Päätös on sähköisesti allekirjoitettu.
\
-
{name}
\
-
helsinki-lisä-suunnittelija
\
-
Liitteet
\
-
1 Salassa pidettävä (Salassa pidettävä, JulkL (621/1999) 24.1 § 25 k)
\
-
Muutoksenhaku
OHJEET OIKAISUVAATIMUKSEN TEKEMISEKSI
\
-
Tähän päätökseen tyytymätön voi tehdä kirjallisen oikaisuvaatimuksen. \
-Päätökseen ei saa hakea muutosta valittamalla tuomioistuimeen.
\
-
Oikaisuvaatimusoikeus
Oikaisuvaatimuksen saa tehdä
\
-
- se, johon päätös on kohdistettu tai jonka oikeuteen, velvollisuuteen tai etuun päätös \
-välittömästi vaikuttaa (asianosainen)
\
-- kunnan jäsen.
\
-
Oikaisuvaatimusaika
Oikaisuvaatimus on tehtävä 14 päivän kuluessa päätöksen tiedoksisaannista.
\
-
Oikaisuvaatimuksen on saavuttava Helsingin kaupungin kirjaamoon määräajan viimeisenä päivänä \
-ennen kirjaamon aukioloajan päättymistä.
\
-
Mikäli päätös on annettu tiedoksi postitse, asianosaisen katsotaan saaneen päätöksestä tiedon, \
-jollei muuta näytetä, seitsemän päivän kuluttua kirjeen lähettämisestä. \
-Kunnan jäsenen katsotaan saaneen päätöksestä tiedon seitsemän päivän \
-kuluttua siitä, kun pöytäkirja on nähtävänä yleisessä tietoverkossa.
\
-
Mikäli päätös on annettu tiedoksi sähköisenä viestinä, asianosaisen katsotaan saaneen päätöksestä tiedon, \
-jollei muuta näytetä, kolmen päivän kuluttua viestin lähettämisestä.
\
-
Tiedoksisaantipäivää ei lueta oikaisuvaatimusaikaan. Jos oikaisuvaatimusajan viimeinen päivä on pyhäpäivä, \
-itsenäisyyspäivä, vapunpäivä, joulu- tai juhannusaatto tai arkilauantai, \
-saa oikaisuvaatimuksen tehdä ensimmäisenä arkipäivänä sen jälkeen.
\
-
Oikaisuvaatimusviranomainen
Viranomainen, jolle oikaisuvaatimus tehdään, on Helsingin kaupunginhallitus.
\
-
Oikaisuvaatimusviranomaisen asiointiosoite on seuraava:
\
-
Suojattu sähköposti: https://securemail.hel.fi/
\
-
Käytäthän aina suojattua sähköpostia, kun lähetät henkilökohtaisia tietojasi.
\
-
Muistathan asioinnin yhteydessä mainita kirjaamisnumeron (esim. HEL 2021-000123), \
-mikäli asiasi on jo vireillä Helsingin kaupungissa.
\
-
\
-| \
- Sähköpostiosoite: | helsinki.kirjaamo@hel.fi |
\
-Postiosoite: | PL 10 |
\
- | 00099 HELSINGIN KAUPUNKI |
\
-Käyntiosoite: | Pohjoisesplanadi 11-13 |
\
-Puhelinnumero: | 09 310 13700 |
\
-
\
-
Kirjaamon aukioloaika on maanantaista perjantaihin klo 08.15-16.00.
\
-
Oikaisuvaatimuksen muoto ja sisältö
Oikaisuvaatimus on tehtävä kirjallisena. \
-Myös sähköinen asiakirja täyttää vaatimuksen kirjallisesta muodosta.
\
-
Oikaisuvaatimuksessa on ilmoitettava
- päätös, johon oikaisuvaatimus kohdistuu
\
-- miten päätöstä halutaan oikaistavaksi
- millä perusteella päätöstä halutaan oikaistavaksi
\
-- oikaisuvaatimuksen tekijä
\
-- millä perusteella oikaisuvaatimuksen tekijä on oikeutettu tekemään vaatimuksen
\
-- oikaisuvaatimuksen tekijän yhteystiedot
\
-
Pöytäkirja
Päätöstä koskevia pöytäkirjan otteita ja liitteitä lähetetään pyynnöstä. \
-Asiakirjoja voi tilata Helsingin kaupungin kirjaamosta.
\
-
Otteet
| Ote | Otteen liitteet |
\
-| {company} | Oikaisuvaatimusohje, kaupunginhallitus Liite 1 |
\
-
'
+ content = (
+ 'Avustuksen myöntäminen,'
+ " Työllisyyspalvelut, työllisyydenhoidon"
+ ' Helsinki-lisä16 §
Avustuksen myöntäminen,'
+ " Työllisyyspalvelut, työllisyydenhoidon Helsinki-lisä
HEL 2024-004415 T 02 05 01 00
Päätös
Helsinki-lisä-suunnittelija päätti'
+ f" myöntää {company}:lle työnantajan Helsinki-lisää käytettäväksi"
+ " helsinkiläisen työllistämiseksi 448 euroa kuukaudessa palkkatuetulle ajalle"
+ " 4.12.2023-3.10.2024 ja 800 euroa kuukaudessa ajalle 4.10.2024-3.12.2024,"
+ " jolta työnantaja ei saa palkkatukea. Yhteensä Helsinki-lisää myönnetään 6080"
+ " euroa.
Helsinki-lisään on varattu talousarviossa Helsingin"
+ " kaupungin Työllisyyspalveluille vuosittain budjetoitu määräraha. Avustuksen"
+ " kustannukset maksetaan kaupungin Työllisyyspalveluille osoitetusta"
+ " määrärahasta talousarvion erikseen määritellyltä kohdalta. Työnantajan"
+ " Helsinki-lisä on aina harkinnanvarainen.
Päätösteksti
Helsingin'
+ " kaupunginhallituksen elinkeinojaosto on 11.9.2023 § 30 päättänyt tukea"
+ " rahallisesti yksityisen ja kolmannen sektorin työnantajia, jotka tarjoavat"
+ " työtä kaupungin työllisyydenhoidon kohderyhmiin kuuluville"
+ " helsinkiläisille.
Avustus
Kaupunginhallituksen elinkeinojaosto"
+ " on päätöksellään 11.9.2023 § 30 hyväksynyt työnantajan Helsinki-lisän"
+ " myöntämistä koskevat ehdot. Helsinki-lisän myöntämisessä noudatetaan lisäksi"
+ " kaupunginhallituksen 28.10.2019 § 723 hyväksymiä Helsingin kaupungin"
+ " avustusten yleisohjeita.
Helsinki-lisä on myönnetty työllistettävän"
+ " henkilön palkkauksesta aiheutuviin kustannuksiin, ei kuitenkaan"
+ " bruttopalkkaan siltä ajalta, jolta työnantaja saa myös palkkatukea. Tuen"
+ " määrään vaikuttavat samoihin kustannuksiin myönnetyt muut tuet (esim."
+ " palkkatuki ja oppisopimuksen koulutuskorvaus). Yritykselle ja taloudellista"
+ " toimintaa harjoittavalle yhteisölle avustus myönnetään vähämerkityksisenä"
+ " tukena eli ns. de minimis -tukena, ei koskaan yleisen ryhmäpoikkeusasetuksen"
+ " (komission asetus (EU) N:o 651/2014) perusteella eli ns. RPA-tukena."
+ " Yleishyödyllisille yhteisöille avustus myönnetään valtiontukisääntelyn"
+ " ulkopuolisena tukena, jos yhdistys ei harjoita taloudellista"
+ " toimintaa.
Avustusta myönnetään valtiontukisäännöissä määrätyn"
+ " kasautumissäännön sekä tuen enimmäisintensiteetin mukaisesti (tuen määrä"
+ " suhteessa tukikelpoisiin kustannuksiin). Helsinki-lisä voi olla enintään 800"
+ " euroa kuukaudessa. Avustusta ei saa siirtää toisen tahon tai henkilön"
+ " käytettäväksi. Avustus maksetaan hakemuksessa ilmoitetulle"
+ " pankkitilille.
Helsinki-lisää saa käyttää ainoastaan"
+ " kaupunginhallituksen elinkeinojaoston päätöksen 11.9.2023 §30 mukaisiin"
+ " tarkoituksiin. Avustuksen saajan tulee viipymättä palauttaa virheellisesti,"
+ " liikaa tai ilmeisen perusteettomasti saamansa avustus."
+ " Väärinkäyttötapauksessa kaupunki voi periä maksetun avustuksen takaisin."
+ " Avustuksen saaja sitoutuu antamaan tarvittaessa kaupungille tarvittavat"
+ " tiedot sen varmistamiseksi, että avustusta ei ole käytetty ehtojen"
+ " vastaisesti. Mikäli avustus maksetaan ennen päätöksen lainvoimaisuutta,"
+ " avustuksen saaja sitoutuu palauttamaan jo maksetut avustukset, jos päätös"
+ " muutoksenhaun johdosta"
+ " muuttuu.
Valtiontukiarviointi
Yritykselle ja taloudellista"
+ " toimintaa harjoittavalle yhteisölle avustus myönnetään vähämerkityksisenä"
+ " tukena eli ns. de minimis -tukena. Tuen myöntämisessä noudatetaan komission"
+ " asetusta (EU) 2023/2831, annettu 13.12.2023, Euroopan unionista tehdyn"
+ " sopimuksen 107 ja 108 artiklan soveltamisesta vähämerkityksiseen tukeen"
+ " (EUVL L2023/281, 15.12.2023).
Kullekin hakijalle myönnettävän de"
+ " minimis -tuen määrä ilmenee hakijakohtaisesta liitteestä. Avustuksen"
+ " saajalle voidaan myöntää de minimis -tukena enintään 300 000 euroa kuluvan"
+ " vuoden ja kahden sitä edeltäneen kahden vuoden muodostaman jakson aikana."
+ " Avustuksen saaja vastaa siitä, että eri tahojen (mm. ministeriöt,"
+ " ministeriöiden alaiset viranomaiset, Business Finland, Finnvera Oyj, kunnat,"
+ " maakuntien liitot) myöntämien de minimis -tukien yhteismäärä ei ylitä tätä"
+ " määrää. Avustuksen saaja on avustushakemuksessa ilmoittanut kaupungille"
+ " kaikkien saamiensa de minimis -tukien määrät ja"
+ " myöntöajankohdat.
Lisätiedot
{name}, suunnittelija, puhelin:'
+ " 12345789
testi@testi.test
Päätös on sähköisesti'
+ f' allekirjoitettu.
{name}
helsinki-lisä-suunnittelija
Liitteet
1 Salassa pidettävä (Salassa'
+ " pidettävä, JulkL (621/1999) 24.1 § 25 k)
Muutoksenhaku
OHJEET OIKAISUVAATIMUKSEN'
+ " TEKEMISEKSI
Tähän päätökseen tyytymätön voi tehdä kirjallisen"
+ " oikaisuvaatimuksen. Päätökseen ei saa hakea muutosta valittamalla"
+ " tuomioistuimeen.
Oikaisuvaatimusoikeus
Oikaisuvaatimuksen saa"
+ " tehdä
- se, johon päätös on kohdistettu tai jonka oikeuteen,"
+ " velvollisuuteen tai etuun päätös välittömästi vaikuttaa"
+ " (asianosainen)
- kunnan"
+ " jäsen.
Oikaisuvaatimusaika
Oikaisuvaatimus on"
+ " tehtävä 14 päivän kuluessa päätöksen"
+ " tiedoksisaannista.
Oikaisuvaatimuksen on saavuttava Helsingin"
+ " kaupungin kirjaamoon määräajan viimeisenä päivänä ennen kirjaamon"
+ " aukioloajan päättymistä.
Mikäli päätös on annettu tiedoksi postitse,"
+ " asianosaisen katsotaan saaneen päätöksestä tiedon, jollei muuta näytetä,"
+ " seitsemän päivän kuluttua kirjeen lähettämisestä. Kunnan jäsenen katsotaan"
+ " saaneen päätöksestä tiedon seitsemän päivän kuluttua siitä, kun pöytäkirja"
+ " on nähtävänä yleisessä tietoverkossa.
Mikäli päätös on annettu"
+ " tiedoksi sähköisenä viestinä, asianosaisen katsotaan saaneen päätöksestä"
+ " tiedon, jollei muuta näytetä, kolmen päivän kuluttua viestin"
+ " lähettämisestä.
Tiedoksisaantipäivää ei lueta oikaisuvaatimusaikaan."
+ " Jos oikaisuvaatimusajan viimeinen päivä on pyhäpäivä, itsenäisyyspäivä,"
+ " vapunpäivä, joulu- tai juhannusaatto tai arkilauantai, saa"
+ " oikaisuvaatimuksen tehdä ensimmäisenä arkipäivänä sen"
+ " jälkeen.
Oikaisuvaatimusviranomainen
Viranomainen, jolle"
+ " oikaisuvaatimus tehdään, on Helsingin"
+ " kaupunginhallitus.
Oikaisuvaatimusviranomaisen asiointiosoite on"
+ " seuraava:
Suojattu sähköposti: https://securemail.hel.fi/"
+ "
Käytäthän aina suojattua sähköpostia, kun lähetät henkilökohtaisia"
+ " tietojasi.
Muistathan asioinnin yhteydessä mainita kirjaamisnumeron"
+ " (esim. HEL 2021-000123), mikäli asiasi on jo vireillä Helsingin"
+ ' kaupungissa.
Sähköpostiosoite: | helsinki.kirjaamo@hel.fi |
Postiosoite: | PL'
+ " 10 |
| 00099 HELSINGIN"
+ " KAUPUNKI |
Käyntiosoite: | Pohjoisesplanadi"
+ " 11-13 |
Puhelinnumero: | 09 310"
+ " 13700 |
Kirjaamon aukioloaika on"
+ " maanantaista perjantaihin klo 08.15-16.00.
Oikaisuvaatimuksen muoto"
+ " ja sisältö
Oikaisuvaatimus on tehtävä kirjallisena. Myös sähköinen"
+ " asiakirja täyttää vaatimuksen kirjallisesta"
+ " muodosta.
Oikaisuvaatimuksessa on ilmoitettava
- päätös,"
+ " johon oikaisuvaatimus kohdistuu
- miten päätöstä halutaan"
+ " oikaistavaksi
- millä perusteella päätöstä halutaan"
+ " oikaistavaksi
- oikaisuvaatimuksen tekijä
- millä perusteella"
+ " oikaisuvaatimuksen tekijä on oikeutettu tekemään"
+ " vaatimuksen
- oikaisuvaatimuksen tekijän"
+ " yhteystiedot
Pöytäkirja
Päätöstä koskevia"
+ " pöytäkirjan otteita ja liitteitä lähetetään pyynnöstä. Asiakirjoja voi"
+ " tilata Helsingin kaupungin kirjaamosta.
Otteet
| Ote | Otteen'
+ f" liitteet |
|---|
| {company} | Oikaisuvaatimusohje,"
+ " kaupunginhallitus Liite"
+ " 1 |
"
+ )
return [
{
"links": [
{
"rel": "self",
- "href": "https://ahjo.hel.fi:9802/ahjorest/v1/decisions/%7B02A081B6-7B7C-4309-B95A-3A53D222B4CE%7D",
+ "href": (
+ "https://ahjo.hel.fi:9802/ahjorest/v1/decisions/%7B02A081B6-7B7C-4309-B95A-3A53D222B4CE%7D"
+ ),
}
],
"NativeId": "{02A081B6-7B7C-4309-B95A-3A53D222B4CE}",
- "Title": "Avustuksen myöntäminen, Työllisyyspalvelut, työllisyydenhoidon Helsinki-lisä",
+ "Title": (
+ "Avustuksen myöntäminen, Työllisyyspalvelut, työllisyydenhoidon"
+ " Helsinki-lisä"
+ ),
"CaseIDLabel": f"{application_with_ahjo_decision.ahjo_case_id}",
"Section": "16",
"Content": content,
@@ -747,7 +768,9 @@ def ahjo_decision_detail_response(application_with_ahjo_decision):
"links": [
{
"rel": "self",
- "href": "https://ahjo.hel.fi:9802/ahjorest/v1/organization?orgid=U02120013070VH2&apireqlang=fi",
+ "href": (
+ "https://ahjo.hel.fi:9802/ahjorest/v1/organization?orgid=U02120013070VH2&apireqlang=fi"
+ ),
}
],
"Name": "Helsinki-lisä-suunnittelija",
@@ -812,29 +835,38 @@ def ahjo_decision_detail_response(application_with_ahjo_decision):
"href": "https://test.test",
}
],
- "Title": "Avustuksen myöntäminen, Työllisyyspalvelut, työllisyydenhoidon Helsinki-lisä",
+ "Title": (
+ "Avustuksen myöntäminen, Työllisyyspalvelut, työllisyydenhoidon"
+ " Helsinki-lisä"
+ ),
"AttachmentNumber": None,
"PublicityClass": "Julkinen",
"SecurityReasons": None,
"VersionSeriesId": "{6176A8B5-B5D3-CB83-86F4-8EC1DCA00004}",
"NativeId": "{02A081B6-7B7C-4309-B95A-3A53D222B4CE}",
"Type": "viranhaltijan päätös",
- "FileURI": "https://ahjojulkaisu.hel.fi/6176A8B5-B5D3-CB83-86F4-8EC1DCA00004.pdf",
+ "FileURI": (
+ "https://ahjojulkaisu.hel.fi/6176A8B5-B5D3-CB83-86F4-8EC1DCA00004.pdf"
+ ),
"Language": "fi",
"PersonalData": "Sisältää henkilötietoja",
"Issued": "2024-04-09T03:00:00.000",
},
"MinutesPDF": {
"links": [],
- "Title": "Helsinki-lisä-suunnittelija viranhaltijan pöytäkirja 09.04.2024/16, \
-julkinen, julkaisujärjestelmä",
+ "Title": (
+ "Helsinki-lisä-suunnittelija viranhaltijan pöytäkirja"
+ " 09.04.2024/16, julkinen, julkaisujärjestelmä"
+ ),
"AttachmentNumber": None,
"PublicityClass": "Julkinen",
"SecurityReasons": None,
"VersionSeriesId": "{157BBFB1-D9D8-C132-996B-8EC1DD100001}",
"NativeId": "{15E07229-9B33-437D-BEAB-F0FE1F5C5F94}",
"Type": "viranhaltijan pöytäkirja",
- "FileURI": "https://ahjojulkaisu.hel.fi/157BBFB1-D9D8-C132-996B-8EC1DD100001.pdf",
+ "FileURI": (
+ "https://ahjojulkaisu.hel.fi/157BBFB1-D9D8-C132-996B-8EC1DD100001.pdf"
+ ),
"Language": "fi",
"PersonalData": "Sisältää henkilötietoja",
"Issued": "2024-04-09T03:00:00.000",
@@ -966,7 +998,10 @@ def decisionmaker_response():
{
"Organization": {
"links": [],
- "Name": "Tiimipäällikkö, työnantajille myönnettävät taloudelliset tuet",
+ "Name": (
+ "Tiimipäällikkö, työnantajille myönnettävät taloudelliset"
+ " tuet"
+ ),
"ID": "XYZÅÄÖ123",
"TypeId": "12",
"Existing": "true",
@@ -988,7 +1023,9 @@ def decisionmaker_response():
"href": "https://dummy.url",
}
],
- "Name": "Työnantajille myönnettävät taloudelliset tuet",
+ "Name": (
+ "Työnantajille myönnettävät taloudelliset tuet"
+ ),
"ID": "XYZÅÄÖ123",
"TypeId": "20",
"Existing": "true",
@@ -1039,7 +1076,9 @@ def decisionmaker_response():
"href": "https://dummy.url",
}
],
- "Name": "Työnantajille myönnettävät taloudelliset tuet",
+ "Name": (
+ "Työnantajille myönnettävät taloudelliset tuet"
+ ),
"ID": "XYZÅÄÖ123",
"TypeId": "5",
"Existing": "true",
@@ -1110,7 +1149,10 @@ def decisionmaker_response():
"href": "https://dummy.url",
}
],
- "Name": "Tiimipäällikkö, työnantajille myönnettävät taloudelliset tuet",
+ "Name": (
+ "Tiimipäällikkö, työnantajille myönnettävät"
+ " taloudelliset tuet"
+ ),
"ID": "ABCDEFG3456",
"TypeId": "11",
"Existing": "true",
diff --git a/backend/benefit/applications/tests/factories.py b/backend/benefit/applications/tests/factories.py
index fd7f1fab2b..b0099f63f4 100755
--- a/backend/benefit/applications/tests/factories.py
+++ b/backend/benefit/applications/tests/factories.py
@@ -14,16 +14,16 @@
PaySubsidyGranted,
)
from applications.models import (
+ APPLICATION_LANGUAGE_CHOICES,
+ ATTACHMENT_CONTENT_TYPE_CHOICES,
AhjoDecision,
AhjoDecisionProposalDraft,
AhjoDecisionText,
Application,
- APPLICATION_LANGUAGE_CHOICES,
ApplicationAlteration,
ApplicationBasis,
ApplicationBatch,
Attachment,
- ATTACHMENT_CONTENT_TYPE_CHOICES,
AttachmentType,
DecisionProposalTemplateSection,
DeMinimisAid,
@@ -216,10 +216,6 @@ class ReceivedApplicationFactory(ApplicationWithAttachmentFactory):
"terms.tests.factories.ApplicantTermsApprovalFactory",
factory_related_name="application",
)
- calculation = factory.RelatedFactory(
- "calculator.tests.factories.CalculationFactory",
- factory_related_name="application",
- )
@factory.post_generation
def received_log_event(self, created, extracted, **kwargs):
diff --git a/backend/benefit/applications/tests/test_ahjo_authentication.py b/backend/benefit/applications/tests/test_ahjo_authentication.py
index b8a350d296..82824b2e88 100644
--- a/backend/benefit/applications/tests/test_ahjo_authentication.py
+++ b/backend/benefit/applications/tests/test_ahjo_authentication.py
@@ -8,7 +8,8 @@
from applications.services.ahjo_authentication import (
AhjoConnector,
AhjoToken,
- AhjoTokenExpiredException,
+ AhjoTokenExpiredError,
+ AhjoTokenRetrievalError,
)
TOKEN_EXPIRY_SECONDS = 30000
@@ -124,7 +125,7 @@ def test_refresh_expired_token(ahjo_connector, ahjo_setting, token_response):
json=token_response,
)
- with pytest.raises(AhjoTokenExpiredException):
+ with pytest.raises(AhjoTokenExpiredError):
ahjo_connector.refresh_token()
@@ -144,7 +145,7 @@ def test_do_token_request(ahjo_connector: AhjoConnector, token_response):
# Test with failed request
m.post("https://johdontyopoytahyte.hel.fi/ids4/connect/token", status_code=400)
- with pytest.raises(Exception):
+ with pytest.raises(AhjoTokenRetrievalError):
ahjo_connector.do_token_request({})
diff --git a/backend/benefit/applications/tests/test_ahjo_decision_proposal_drafts.py b/backend/benefit/applications/tests/test_ahjo_decision_proposal_drafts.py
index 7f46c4115a..a5bf068f33 100644
--- a/backend/benefit/applications/tests/test_ahjo_decision_proposal_drafts.py
+++ b/backend/benefit/applications/tests/test_ahjo_decision_proposal_drafts.py
@@ -148,9 +148,9 @@ def test_decision_proposal_drafting(
if review_step == 4:
final_ahjo_text = AhjoDecisionText.objects.get(application=application)
assert (
- final_ahjo_text.decision_text
- == f'{_("Päätös")}
{decision_text}\
-{_("Päätöksen perustelut")}
{justification_text}'
+ final_ahjo_text.decision_text == "{_("Päätös")}
{decision_text}{_("Päätöksen perustelut")}
{justification_text}'
)
assert final_ahjo_text.decision_maker_id == fake_decisionmakers[0]["ID"]
diff --git a/backend/benefit/applications/tests/test_ahjo_integration.py b/backend/benefit/applications/tests/test_ahjo_integration.py
index f0030281dc..69b2a33a89 100644
--- a/backend/benefit/applications/tests/test_ahjo_integration.py
+++ b/backend/benefit/applications/tests/test_ahjo_integration.py
@@ -14,16 +14,18 @@
from applications.api.v1.ahjo_integration_views import AhjoAttachmentView
from applications.enums import (
+ DEFAULT_AHJO_CALLBACK_ERROR_MESSAGE,
AhjoCallBackStatus,
AhjoDecisionUpdateType,
AhjoRequestType,
- AhjoStatus as AhjoStatusEnum,
ApplicationBatchStatus,
ApplicationStatus,
ApplicationTalpaStatus,
AttachmentType,
BenefitType,
- DEFAULT_AHJO_CALLBACK_ERROR_MESSAGE,
+)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
)
from applications.models import (
AhjoDecisionText,
@@ -38,14 +40,14 @@
)
from applications.services.ahjo_integration import (
ACCEPTED_TITLE,
- export_application_batch,
+ REJECTED_TITLE,
ExportFileInfo,
+ export_application_batch,
generate_application_attachment,
generate_composed_files,
generate_single_approved_file,
generate_single_declined_file,
get_application_for_ahjo,
- REJECTED_TITLE,
)
from applications.tests.factories import ApplicationFactory, DecidedApplicationFactory
from calculator.models import Calculation
@@ -273,7 +275,8 @@ def test_export_application_batch(application_batch):
def test_multiple_benefit_per_application(mock_pdf_convert):
mock_pdf_convert.return_value = {}
# Test case data and expected results collected from
- # calculator/tests/Helsinki-lisa laskurin testitapaukset.xlsx/ Sheet Palkan Helsinki-lisä / Column E
+ # calculator/tests/Helsinki-lisa laskurin testitapaukset.xlsx/ Sheet Palkan
+ # Helsinki-lisä / Column E
application = ApplicationFactory(
association_has_business_activities=True,
company__company_form="ry",
@@ -310,7 +313,7 @@ def test_multiple_benefit_per_application(mock_pdf_convert):
assert (
html.count(application.ahjo_application_number) == 2
) # Make sure there are two rows in the report
- print(html)
+ print(html) # noqa: T201
_assert_html_content(
html,
(
@@ -591,7 +594,10 @@ def test_subscribe_to_decisions_callback_success(
{
"id": "INVALID_RECORD_TYPE",
"message": "Asiakirjan tyyppi ei ole sallittu.",
- "context": "(Tähän tulisi tietoa virheen esiintymispaikasta jos mahdollista antaa.)",
+ "context": (
+ "(Tähän tulisi tietoa virheen esiintymispaikasta jos"
+ " mahdollista antaa.)"
+ ),
}
],
),
@@ -602,7 +608,10 @@ def test_subscribe_to_decisions_callback_success(
{
"id": "INVALID_RECORD_TYPE",
"message": "Asiakirjan tyyppi ei ole sallittu.",
- "context": "(Tähän tulisi tietoa virheen esiintymispaikasta jos mahdollista antaa.)",
+ "context": (
+ "(Tähän tulisi tietoa virheen esiintymispaikasta jos"
+ " mahdollista antaa.)"
+ ),
}
],
),
@@ -738,7 +747,10 @@ def test_ahjo_callback_raises_error_without_batch(
response = ahjo_client.post(url, **auth_headers, data=ahjo_callback_payload)
assert response.status_code == 500
assert response.data == {
- "error": f"Application {decided_application.id} has no batch when Ahjo has received a decision proposal request"
+ "error": (
+ f"Application {decided_application.id} has no batch when Ahjo has received"
+ " a decision proposal request"
+ )
}
@@ -1127,7 +1139,8 @@ def test_get_applications_for_open_case_request(
for a in attachments:
assert a.attachment_type in wanted_open_case_attachments
assert a.attachment_type not in unwanted_open_case_attachments
- # only handled_applications should be returned as their last AhjoStatus is SUBMITTED_BUT_NOT_SENT_TO_AHJO
+ # only handled_applications should be returned as their last AhjoStatus is
+ # SUBMITTED_BUT_NOT_SENT_TO_AHJO
# and their application status is HANDLING
assert applications_for_open_case.count() == len(wanted_applications_for_open_case)
@@ -1173,7 +1186,7 @@ def test_get_applications_for_update_request(
AhjoRequestType.UPDATE_APPLICATION, retry_failed_older_than_hours
)
for application in multiple_applications_with_ahjo_case_id:
- print(application.ahjo_status.latest().status)
+ print(application.ahjo_status.latest().status) # noqa: T201
applications_for_ahjo_update = Application.objects.get_by_statuses(**parameters)
@@ -1426,7 +1439,8 @@ def test_get_applications_for_ahjo_decision_proposal_request(
@pytest.mark.parametrize(
- "application_status, latest_ahjo_status, talpa_status, retry_failed_older_than_hours, wanted_count",
+ "application_status, latest_ahjo_status, talpa_status,"
+ " retry_failed_older_than_hours, wanted_count",
[
(
ApplicationStatus.ACCEPTED,
diff --git a/backend/benefit/applications/tests/test_ahjo_payload.py b/backend/benefit/applications/tests/test_ahjo_payload.py
index b4cafe05ee..1edb9f9506 100644
--- a/backend/benefit/applications/tests/test_ahjo_payload.py
+++ b/backend/benefit/applications/tests/test_ahjo_payload.py
@@ -14,21 +14,21 @@
)
from applications.models import AhjoDecisionText, Application, Attachment
from applications.services.ahjo_payload import (
- _prepare_case_records,
- _prepare_record,
- _prepare_record_document_dict,
- _prepare_top_level_dict,
AddRecordsRecordTitle,
AhjoBaseRecordTitle,
AhjoTitle,
OpenCaseRecordTitle,
+ UpdateRecordsRecordTitle,
+ _prepare_case_records,
+ _prepare_record,
+ _prepare_record_document_dict,
+ _prepare_top_level_dict,
prepare_case_title,
prepare_decision_proposal_payload,
prepare_final_case_title,
prepare_update_application_payload,
resolve_payload_language,
truncate_string_to_limit,
- UpdateRecordsRecordTitle,
)
from common.utils import hash_file
@@ -108,9 +108,10 @@ def test_ahjo_base_record_title_str():
def test_prepare_case_title(decided_application):
application = decided_application
- wanted_title = f"Avustukset työnantajille, työllisyyspalvelut, \
-Helsinki-lisä, {application.company.name}, \
-hakemus {application.application_number}"
+ wanted_title = (
+ "Avustukset työnantajille, työllisyyspalvelut, Helsinki-lisä,"
+ f" {application.company.name}, hakemus {application.application_number}"
+ )
got = prepare_case_title(application, decided_application.company.name)
assert wanted_title == got
@@ -155,7 +156,8 @@ def test_prepare_final_case_title_truncate(
@pytest.mark.parametrize(
- "title_class, record_title, record_type, request_type, wanted_title_addition, part, total",
+ "title_class, record_title, record_type, request_type, wanted_title_addition, part,"
+ " total",
[
(
OpenCaseRecordTitle,
@@ -210,10 +212,15 @@ def test_prepare_record_title(
formatted_date = application.submitted_at.strftime("%d.%m.%Y")
if part and total:
- wanted_title = f"{record_title}{wanted_title_addition} {formatted_date},\
- liite {part}/{total}, {application.application_number}"
+ wanted_title = (
+ f"{record_title}{wanted_title_addition} {formatted_date}, liite"
+ f" {part}/{total}, {application.application_number}"
+ )
else:
- wanted_title = f"{record_title}{wanted_title_addition} {formatted_date}, {application.application_number}"
+ wanted_title = (
+ f"{record_title}{wanted_title_addition} {formatted_date},"
+ f" {application.application_number}"
+ )
if (
record_type == AhjoRecordType.ATTACHMENT
and request_type == AhjoRequestType.OPEN_CASE
@@ -230,7 +237,10 @@ def test_prepare_record_title_for_attachment(decided_application):
application = Application.objects.get(pk=decided_application.pk)
formatted_date = application.created_at.strftime("%d.%m.%Y")
- wanted_title = f"{AhjoRecordTitle.APPLICATION} {formatted_date}, liite 1/3, {application.application_number}"
+ wanted_title = (
+ f"{AhjoRecordTitle.APPLICATION} {formatted_date}, liite 1/3,"
+ f" {application.application_number}"
+ )
got = f"{AhjoBaseRecordTitle(application=application, current=1, total=3)}"
assert wanted_title == got
@@ -355,7 +365,7 @@ def test_prepare_case_records(decided_application, settings):
for attachment in open_case_attachments:
document_record = _prepare_record(
- f"{AhjoBaseRecordTitle(application=application,current=pos,total=total_attachments,)}",
+ f"{AhjoBaseRecordTitle(application=application, current=pos, total=total_attachments)}",
AhjoRecordType.ATTACHMENT,
attachment.created_at.isoformat("T", "seconds"),
[_prepare_record_document_dict(attachment)],
diff --git a/backend/benefit/applications/tests/test_ahjo_requests.py b/backend/benefit/applications/tests/test_ahjo_requests.py
index 7767741025..60299c18fd 100644
--- a/backend/benefit/applications/tests/test_ahjo_requests.py
+++ b/backend/benefit/applications/tests/test_ahjo_requests.py
@@ -7,12 +7,13 @@
from django.urls import reverse
from django.utils import timezone
-from applications.enums import AhjoRequestType, AhjoStatus as AhjoStatusEnum
+from applications.enums import AhjoRequestType
+from applications.enums import AhjoStatus as AhjoStatusEnum
from applications.models import AhjoSetting, AhjoStatus
from applications.services.ahjo.enums import AhjoSettingName
from applications.services.ahjo.exceptions import (
- AhjoApiClientException,
- InvalidAhjoTokenException,
+ AhjoApiClientError,
+ InvalidAhjoTokenError,
MissingHandlerIdError,
)
from applications.services.ahjo_authentication import AhjoToken
@@ -105,7 +106,8 @@ def test_ahjo_requests_without_application(
@pytest.mark.parametrize(
- "ahjo_request_class, request_type, request_method, callback_route, ahjo_status_after_request",
+ "ahjo_request_class, request_type, request_method, callback_route,"
+ " ahjo_status_after_request",
[
(
AhjoOpenCaseRequest,
@@ -314,10 +316,10 @@ def test_requests_exceptions(
with pytest.raises(MissingHandlerIdError):
ahjo_request_without_ad_username.api_url()
- with pytest.raises(InvalidAhjoTokenException):
+ with pytest.raises(InvalidAhjoTokenError):
AhjoApiClient(ahjo_token="foo", ahjo_request=ahjo_request_without_ad_username)
- with pytest.raises(InvalidAhjoTokenException):
+ with pytest.raises(InvalidAhjoTokenError):
AhjoApiClient(
ahjo_token=AhjoToken(access_token=None),
ahjo_request=ahjo_request_without_ad_username,
@@ -333,17 +335,20 @@ def test_requests_exceptions(
with requests_mock.Mocker() as m:
# an example of a real validation error response from ahjo
- validation_error = [
+ validation_errors = [
{"message": "/Title: does not match the regex pattern [a-zA-Z0-9åäöÅÄÖ]+"},
{
- "message": "/Records/0/SecurityReasons/0: does not match the regex pattern [a-zA-Z0-9åäöÅÄÖ]+"
+ "message": (
+ "/Records/0/SecurityReasons/0: does not match the regex pattern"
+ " [a-zA-Z0-9åäöÅÄÖ]+"
+ )
},
]
m.register_uri(
configured_request.request_method,
configured_request.api_url(),
status_code=400,
- json=validation_error,
+ json=validation_errors,
)
client.send_request_to_ahjo()
mock_logger.error.assert_called()
@@ -351,7 +356,7 @@ def test_requests_exceptions(
assert ahjo_status.status == previous_status
assert ahjo_status.validation_error_from_ahjo is not None
- for validation_error in validation_error:
+ for validation_error in validation_errors:
assert validation_error in ahjo_status.validation_error_from_ahjo["context"]
exception = requests.exceptions.RequestException
@@ -364,7 +369,7 @@ def test_requests_exceptions(
client.send_request_to_ahjo()
mock_logger.error.assert_called()
- exception = AhjoApiClientException
+ exception = AhjoApiClientError
with requests_mock.Mocker() as m:
m.register_uri(
configured_request.request_method,
diff --git a/backend/benefit/applications/tests/test_ahjo_response_handler.py b/backend/benefit/applications/tests/test_ahjo_response_handler.py
index ea7e195845..6c3f3e539c 100644
--- a/backend/benefit/applications/tests/test_ahjo_response_handler.py
+++ b/backend/benefit/applications/tests/test_ahjo_response_handler.py
@@ -7,10 +7,12 @@
from applications.enums import (
AhjoDecision,
AhjoDecisionDetails,
- AhjoStatus as AhjoStatusEnum,
ApplicationBatchStatus,
ApplicationStatus,
)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
+)
from applications.services.ahjo.enums import AhjoSettingName
from applications.services.ahjo.response_handler import (
AhjoDecisionDetailsResponseHandler,
@@ -203,9 +205,9 @@ def test_parse_details_from_decision_response(
@pytest.mark.parametrize(
- "instalments_enabled,application_status,\
- expected_batch_status, expected_proposal_for_decision, expected_instalment_1_status, \
- expected_instalment_2_status",
+ "instalments_enabled,application_status, expected_batch_status,"
+ " expected_proposal_for_decision, expected_instalment_1_status, "
+ " expected_instalment_2_status",
[
(
True,
@@ -273,8 +275,8 @@ def test_handle_details_request_success(
assert (
success_text
- == f"Successfully received and updated decision details \
-for application {application.id} and batch {application.batch.id} from Ahjo"
+ == "Successfully received and updated decision details for application"
+ f" {application.id} and batch {application.batch.id} from Ahjo"
)
assert instalment_1.status == expected_instalment_1_status
assert instalment_2.status == expected_instalment_2_status
diff --git a/backend/benefit/applications/tests/test_ahjo_settings.py b/backend/benefit/applications/tests/test_ahjo_settings.py
index 0087251c74..c5a5471800 100644
--- a/backend/benefit/applications/tests/test_ahjo_settings.py
+++ b/backend/benefit/applications/tests/test_ahjo_settings.py
@@ -13,7 +13,7 @@ def test_get_decision_maker_ahjo_setting_for_applicant(api_client):
assert response.status_code == 403
-@pytest.mark.parametrize("setting_name", [("ahjo_decision_maker"), ("ahjo_signer")])
+@pytest.mark.parametrize("setting_name", ["ahjo_decision_maker", "ahjo_signer"])
def test_get_ahjo_setting_for_handler(
handler_api_client, decision_maker_settings, setting_name, signer_settings
):
diff --git a/backend/benefit/applications/tests/test_ahjo_xml_builder.py b/backend/benefit/applications/tests/test_ahjo_xml_builder.py
index abf840f4f4..11aa36277f 100644
--- a/backend/benefit/applications/tests/test_ahjo_xml_builder.py
+++ b/backend/benefit/applications/tests/test_ahjo_xml_builder.py
@@ -109,8 +109,10 @@ def test_public_xml_file_name(decided_application, public_xml_builder):
application = decided_application
xml_file_name = public_xml_builder.generate_xml_file_name()
- wanted_file_name = f"Hakemus {application.created_at.strftime('%d.%m.%Y')} \
-päätösteksti {application.application_number}.xml"
+ wanted_file_name = (
+ f"Hakemus {application.created_at.strftime('%d.%m.%Y')} päätösteksti"
+ f" {application.application_number}.xml"
+ )
assert xml_file_name == wanted_file_name
@@ -146,7 +148,10 @@ def test_secret_xml_decision_string(
decided_application.company.business_id,
decided_application.employee.last_name,
decided_application.employee.first_name,
- f"{row.start_date.strftime('%d.%m.%Y')} - {row.end_date.strftime('%d.%m.%Y')}",
+ (
+ f"{row.start_date.strftime('%d.%m.%Y')} -"
+ f" {row.end_date.strftime('%d.%m.%Y')}"
+ ),
str(int(row.amount)),
str(int(calculation.calculated_benefit_amount)),
]
@@ -162,7 +167,10 @@ def test_secret_xml_decision_string(
decided_application.employee.first_name,
]
unwanted_replacements = [
- f"{row.start_date.strftime('%d.%m.%Y')} - {row.end_date.strftime('%d.%m.%Y')}",
+ (
+ f"{row.start_date.strftime('%d.%m.%Y')} -"
+ f" {row.end_date.strftime('%d.%m.%Y')}"
+ ),
str(int(row.amount)),
str(int(calculation.calculated_benefit_amount)),
]
@@ -177,8 +185,10 @@ def test_secret_xml_file_name(decided_application, secret_xml_builder):
application = decided_application
xml_file_name = secret_xml_builder.generate_xml_file_name()
- wanted_file_name = f"Hakemus {application.created_at.strftime('%d.%m.%Y')} \
-päätöksen liite {application.application_number}.xml"
+ wanted_file_name = (
+ f"Hakemus {application.created_at.strftime('%d.%m.%Y')} päätöksen liite"
+ f" {application.application_number}.xml"
+ )
assert xml_file_name == wanted_file_name
diff --git a/backend/benefit/applications/tests/test_application_batch_api.py b/backend/benefit/applications/tests/test_application_batch_api.py
index 7d21a7c024..d34de55267 100755
--- a/backend/benefit/applications/tests/test_application_batch_api.py
+++ b/backend/benefit/applications/tests/test_application_batch_api.py
@@ -315,10 +315,12 @@ def test_batch_status_change(
def test_batch_too_many_drafts(application_batch):
# Create a second batch to get to two batch limit
- ApplicationBatchFactory(
- status=ApplicationBatchStatus.DRAFT,
- proposal_for_decision=ApplicationStatus.REJECTED,
- ),
+ (
+ ApplicationBatchFactory(
+ status=ApplicationBatchStatus.DRAFT,
+ proposal_for_decision=ApplicationStatus.REJECTED,
+ ),
+ )
# Create a batch with different status and try putting it in draft
batch_with_status_change = ApplicationBatchFactory(
@@ -777,7 +779,8 @@ def test_application_delete(handler_api_client, application_batch):
@patch("applications.api.v1.application_batch_views.export_application_batch")
def test_application_batch_export(mock_export, handler_api_client, application_batch):
- # Mock export pdf function to reduce test time, the unittest for the export feature will be run separately
+ # Mock export pdf function to reduce test time, the unittest for the export feature
+ # will be run separately
mock_export.return_value = {}
# Export invalid batch
application_batch.status = ApplicationBatchStatus.SENT_TO_TALPA
diff --git a/backend/benefit/applications/tests/test_application_change_sets.py b/backend/benefit/applications/tests/test_application_change_sets.py
index 578822000c..2ea174aa7c 100755
--- a/backend/benefit/applications/tests/test_application_change_sets.py
+++ b/backend/benefit/applications/tests/test_application_change_sets.py
@@ -40,7 +40,9 @@ def _flatten_dict(d, parent_key="", sep="."):
handler_edit_payloads = [
{
- "change_reason": "Change employee first & last name, company contact's phone number",
+ "change_reason": (
+ "Change employee first & last name, company contact's phone number"
+ ),
"company_contact_person_phone_number": "+35850000000",
"employee": {
"first_name": "Firstname1",
@@ -262,7 +264,8 @@ def update_applicant_application(application_payload, frozen_datetime):
"changes"
]
- # Just split from the head of changes - we don't want to check handler's changes again
+ # Just split from the head of changes - we don't want to check handler's changes
+ # again
# Plus one for the attachment change
applicant_changes = changes[0 : len(applicant_edit_payloads) + 1]
diff --git a/backend/benefit/applications/tests/test_application_clone.py b/backend/benefit/applications/tests/test_application_clone.py
index dbf3782744..4945c18da4 100755
--- a/backend/benefit/applications/tests/test_application_clone.py
+++ b/backend/benefit/applications/tests/test_application_clone.py
@@ -203,7 +203,8 @@ def test_application_full_clone(api_client, handler_api_client, settings):
)
assert response.status_code == 403
- # Access endpoint as a handler and a bit later than the original application created at
+ # Access endpoint as a handler and a bit later than the original application created
+ # at
with freeze_time("2024-10-23"):
response = handler_api_client.get(
reverse(
@@ -290,18 +291,21 @@ def _check_fields(original, cloned, fields):
else getattr(cloned, field.name)
)
if field.name in fields["copied"]:
- assert (
- original_value == cloned_value
- ), f"Field {field.name} should match, {original_value} != {cloned_value}"
+ assert original_value == cloned_value, (
+ f"Field {field.name} should match, {original_value} != {cloned_value}"
+ )
if field.name in fields["not_copied"]:
- assert (
- original_value != cloned_value
- ), f"Field {field.name} should not match, {original_value} != {cloned_value}"
+ assert original_value != cloned_value, (
+ f"Field {field.name} should not match, {original_value} !="
+ f" {cloned_value}"
+ )
if field.name not in fields["copied"] + fields["not_copied"]:
- assert False, f"Unidentified field '{field.name}', please take this "
- "field into account when renaming, removing, or adding fields"
+ raise AssertionError(
+ f"Unidentified field '{field.name}', please take this "
+ "field into account when renaming, removing, or adding fields"
+ )
def _check_application_fields(application, cloned_application):
@@ -322,9 +326,9 @@ def _check_pay_subsidies(application, cloned_application):
original_pay_subsidies = list(application.pay_subsidies.all())
cloned_pay_subsidies = list(cloned_application.pay_subsidies.all())
- assert len(original_pay_subsidies) == len(
- cloned_pay_subsidies
- ), "Number of pay subsidies should match"
+ assert len(original_pay_subsidies) == len(cloned_pay_subsidies), (
+ "Number of pay subsidies should match"
+ )
for original_pay_subsidy in original_pay_subsidies:
matched_subsidy = next(
@@ -340,9 +344,9 @@ def _check_pay_subsidies(application, cloned_application):
),
None,
)
- assert (
- matched_subsidy is not None
- ), "Matching pay subsidy not found in cloned subsidies"
+ assert matched_subsidy is not None, (
+ "Matching pay subsidy not found in cloned subsidies"
+ )
_check_fields(original_pay_subsidy, matched_subsidy, pay_subsidy_fields)
@@ -352,9 +356,9 @@ def _check_training_compensations(application, cloned_application):
cloned_application.training_compensations.all()
)
- assert len(cloned_training_compensations) == len(
- original_training_compensations
- ), "Number of training compensations should match"
+ assert len(cloned_training_compensations) == len(original_training_compensations), (
+ "Number of training compensations should match"
+ )
for original_compensation in original_training_compensations:
matched_compensation = next(
@@ -369,9 +373,9 @@ def _check_training_compensations(application, cloned_application):
),
None,
)
- assert (
- matched_compensation is not None
- ), "Matching compensation not found in cloned compensations"
+ assert matched_compensation is not None, (
+ "Matching compensation not found in cloned compensations"
+ )
_check_fields(
original_compensation, matched_compensation, training_compensation_fields
)
@@ -381,9 +385,9 @@ def _check_de_minimis_aids(application, cloned_application):
original_de_minimis_aids = list(application.de_minimis_aid_set.all())
cloned_de_minimis_aids = list(cloned_application.de_minimis_aid_set.all())
- assert len(cloned_de_minimis_aids) == len(
- original_de_minimis_aids
- ), "Number of de minimis aids should match"
+ assert len(cloned_de_minimis_aids) == len(original_de_minimis_aids), (
+ "Number of de minimis aids should match"
+ )
for original_aid in original_de_minimis_aids:
matched_aid = next(
diff --git a/backend/benefit/applications/tests/test_application_tasks.py b/backend/benefit/applications/tests/test_application_tasks.py
index 72834c4fe0..6d7a97d714 100755
--- a/backend/benefit/applications/tests/test_application_tasks.py
+++ b/backend/benefit/applications/tests/test_application_tasks.py
@@ -12,9 +12,11 @@
from applications.enums import (
AhjoDecision,
AhjoRequestType,
- AhjoStatus as AhjoStatusEnum,
ApplicationStatus,
)
+from applications.enums import (
+ AhjoStatus as AhjoStatusEnum,
+)
from applications.models import AhjoSetting, AhjoStatus, Application, Attachment
from applications.services.ahjo.response_handler import (
AhjoDecisionDetailsResponseHandler,
@@ -90,8 +92,8 @@ def test_delete_cancelled_applications_older_than_30_days(cancelled_to_delete):
# Assert that the correct number of applications were deleted
assert (
- f"Deleted {total_applications - remaining_applications.count()} applications with status {[status]}"
- in out.getvalue()
+ f"Deleted {total_applications - remaining_applications.count()} applications"
+ f" with status {[status]}" in out.getvalue()
)
@@ -135,8 +137,8 @@ def test_delete_draft_applications_older_than_180_days(
# Assert that the correct number of applications were deleted
assert (
- f"Deleted {total_applications - remaining_applications.count()} applications with status {[status]}"
- in out.getvalue()
+ f"Deleted {total_applications - remaining_applications.count()} applications"
+ f" with status {[status]}" in out.getvalue()
)
@@ -150,8 +152,8 @@ def test_user_is_notified_of_upcoming_application_deletion(drafts_about_to_be_de
)
assert (
- f"Notified users of {drafts_about_to_be_deleted.count()} applications about upcoming application deletion"
- in out.getvalue()
+ f"Notified users of {drafts_about_to_be_deleted.count()} applications about"
+ " upcoming application deletion" in out.getvalue()
)
@@ -210,9 +212,10 @@ def test_send_ahjo_requests(
application_with_ahjo_decision,
):
AhjoSetting.objects.create(name="ahjo_code", data={"code": "12345"})
- with patch(patch_db_function) as mock_get_applications, patch(
- patch_request
- ) as mock_send_request:
+ with (
+ patch(patch_db_function) as mock_get_applications,
+ patch(patch_request) as mock_send_request,
+ ):
mock_get_token.return_value = MagicMock(AhjoToken)
number_to_send = 5
@@ -221,7 +224,8 @@ def test_send_ahjo_requests(
if request_type == AhjoRequestType.GET_DECISION_DETAILS:
mock_response = ahjo_decision_detail_response
- # Set the decision date to the current date in the same format as in the response
+ # Set the decision date to the current date in the same format as in the
+ # response
date_str = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
mock_response[0]["DateDecision"] = date_str
application.batch_id = batch_for_decision_details.id
@@ -256,7 +260,7 @@ def test_send_ahjo_requests(
stdout=out,
)
- print(out.getvalue())
+ print(out.getvalue()) # noqa: T201
assert (
f"Sending {request_type} request to Ahjo for {number_to_send} applications"
@@ -264,8 +268,8 @@ def test_send_ahjo_requests(
)
assert (
- f"Sent {request_type} requests for {number_to_send} application(s): {app_numbers} to Ahjo"
- in out.getvalue()
+ f"Sent {request_type} requests for {number_to_send} application(s):"
+ f" {app_numbers} to Ahjo" in out.getvalue()
)
if request_type == AhjoRequestType.GET_DECISION_DETAILS:
diff --git a/backend/benefit/applications/tests/test_applications_api.py b/backend/benefit/applications/tests/test_applications_api.py
index 684003d676..01f5ce9ede 100755
--- a/backend/benefit/applications/tests/test_applications_api.py
+++ b/backend/benefit/applications/tests/test_applications_api.py
@@ -293,13 +293,15 @@ def test_applications_filter_archived_for_applicant(
DecidedApplicationFactory(application_number=123450),
# Batch processed and decided 15 days ago, should appear on archive page
DecidedApplicationFactory(application_number=123451, batch=old_batch),
- # Batch processed and decided 15 days ago and archived for handlers, should still appear on archive page
+ # Batch processed and decided 15 days ago and archived for handlers, should
+ # still appear on archive page
DecidedApplicationFactory(
application_number=123452, batch=old_batch, archived=True
),
# Batch processed and decided two days ago, should appear on main page
DecidedApplicationFactory(application_number=123453, batch=recent_batch),
- # Batch decided 15 days ago but not yet fully processed, should appear on main page
+ # Batch decided 15 days ago but not yet fully processed, should appear on main
+ # page
DecidedApplicationFactory(application_number=123454, batch=pending_batch),
# Fresh application not yet decided, should appear on main page
ReceivedApplicationFactory(application_number=123455),
@@ -609,9 +611,9 @@ def test_application_post_invalid_data(
data["applicant_language"] = None # non-null required
data["company_bank_account_number"] = "FI91 4008 0282 0002 02" # invalid number
- data[
- "company_contact_person_phone_number"
- ] = "+359505658789" # Invalid country code
+ data["company_contact_person_phone_number"] = (
+ "+359505658789" # Invalid country code
+ )
api_client.defaults["HTTP_ACCEPT_LANGUAGE"] = language
response = api_client.post(
@@ -776,9 +778,9 @@ def test_application_put_read_only_fields(api_client, application):
def test_application_put_invalid_data(api_client, application):
data = ApplicantApplicationSerializer(application).data
data["de_minimis_aid_set"][0]["amount"] = "300001.00" # value too high
- data[
- "status"
- ] = ApplicationStatus.ACCEPTED # invalid value when transitioning from draft
+ data["status"] = (
+ ApplicationStatus.ACCEPTED
+ ) # invalid value when transitioning from draft
data["bases"] = ["something_completely_different"] # invalid value
data["applicant_language"] = None # non-null required
response = api_client.put(
@@ -1723,7 +1725,8 @@ def _upload_pdf(
def _add_pdf_attachment(
request, application, attachment_type=AttachmentType.EMPLOYMENT_CONTRACT
):
- # add attachment, bypassing validation, so attachment can be added even if application
+ # add attachment, bypassing validation, so attachment can be added even if
+ # application
# state does not allow it
with open(_pdf_file_path(request), "rb") as valid_pdf_file:
file_upload = SimpleUploadedFile(VALID_PDF_FILE, valid_pdf_file.read())
@@ -2137,7 +2140,8 @@ def test_application_number(api_client, application):
new_application.delete()
assert Application.objects.count() == 1
- # Next application should not have old application_number if the previous one was deleted
+ # Next application should not have old application_number if the previous one was
+ # deleted
next_application = ApplicationFactory()
assert Application.objects.count() == 2
assert next_application.application_number == application.application_number + 2
@@ -2435,7 +2439,7 @@ def test_require_additional_information(handler_api_client, application, mailout
{"status": ApplicationStatus.ADDITIONAL_INFORMATION_NEEDED},
)
assert response.status_code == 200
- print(response.__dict__)
+ print(response.__dict__) # noqa: T201
assert application.messages.count() == 1
assert (
diff --git a/backend/benefit/applications/tests/test_applications_report.py b/backend/benefit/applications/tests/test_applications_report.py
index e6a8440f70..4cbf4a7366 100644
--- a/backend/benefit/applications/tests/test_applications_report.py
+++ b/backend/benefit/applications/tests/test_applications_report.py
@@ -140,7 +140,10 @@ def _create_applications_for_export():
@pytest.mark.skip(
- reason="This test fails in deploy pipeline - DETAIL: Key (username)=(masonzachary_a45eb8) already exists."
+ reason=(
+ "This test fails in deploy pipeline - DETAIL: Key"
+ " (username)=(masonzachary_a45eb8) already exists."
+ )
)
def test_applications_csv_export_new_applications(handler_api_client):
(
@@ -181,11 +184,13 @@ def test_applications_csv_export_new_applications(handler_api_client):
assert set(
[
a.pk
- for a in ApplicationBatch.objects.filter(
- proposal_for_decision=AhjoDecision.DECIDED_ACCEPTED
+ for a in (
+ ApplicationBatch.objects.filter(
+ proposal_for_decision=AhjoDecision.DECIDED_ACCEPTED
+ )
+ .first()
+ .applications.all()
)
- .first()
- .applications.all()
]
) == {application1.pk, application2.pk}
@@ -409,9 +414,9 @@ def test_power_bi_report_csv_output(application_powerbi_csv_service):
# Assert that each column header matches
for index, header in enumerate(expected_headers):
- assert (
- csv_lines[0][index] == header
- ), f"Expected {header} but got {csv_lines[0][index]}"
+ assert csv_lines[0][index] == header, (
+ f"Expected {header} but got {csv_lines[0][index]}"
+ )
applications = application_powerbi_csv_service.get_applications()
@@ -592,7 +597,7 @@ def test_write_application_alterations_csv_file(
application_alteration_csv_service.write_csv_file(output_file)
with open(output_file, encoding="utf-8") as f:
contents = f.read()
- print(contents)
+ print(contents) # noqa: T201
assert str(alteration.recovery_amount) in contents
@@ -692,7 +697,7 @@ def test_applications_csv_output(applications_csv_service): # noqa: C901
assert application.ahjo_rows[0].start_date == application.calculation.start_date
assert application.ahjo_rows[0].end_date == application.calculation.end_date
- csv_columns = iter(applications_csv_service.CSV_COLUMNS)
+ csv_columns = iter(applications_csv_service.csv_columns)
next(csv_columns, None) # Skip the first element
for idx, col in enumerate(csv_columns, start=1):
@@ -832,7 +837,8 @@ def test_applications_csv_two_ahjo_rows(
assert csv_lines[2][1] == f'"{format_datetime(application.submitted_at)}"'
assert int(csv_lines[2][2]) == 2
- # the content of columns "Siirrettävä Ahjo-rivi / xxx" and "Hakemusrivi" change, rest of the lines are equal
+ # the content of columns "Siirrettävä Ahjo-rivi / xxx" and "Hakemusrivi" change,
+ # rest of the lines are equal
current_ahjo_row_start = csv_lines[0].index('"Siirrettävä Ahjo-rivi / tyyppi"')
current_ahjo_row_end = csv_lines[0].index(
'"Siirrettävä Ahjo-rivi / päättymispäivä"'
diff --git a/backend/benefit/applications/tests/test_benefit_aggregation.py b/backend/benefit/applications/tests/test_benefit_aggregation.py
index ad328faac2..5d74f97dea 100644
--- a/backend/benefit/applications/tests/test_benefit_aggregation.py
+++ b/backend/benefit/applications/tests/test_benefit_aggregation.py
@@ -25,7 +25,8 @@
@pytest.mark.parametrize(
- "previous_benefits, benefit_type, apprenticeship_program, expected_warning, months_used, months_remaining",
+ "previous_benefits, benefit_type, apprenticeship_program, expected_warning,"
+ " months_used, months_remaining",
[
(
[
@@ -268,7 +269,8 @@
6,
6,
),
- # 24-month gap in past benefits so the benefit from 2017-2018 is not included and application is valid
+ # 24-month gap in past benefits so the benefit from 2017-2018 is not included
+ # and application is valid
(
[
(
@@ -320,10 +322,12 @@ def test_application_with_previously_accepted_applications_and_previous_benefits
months_remaining,
expected_warning,
):
- # the type of the previous benefit and the apprenticeship_program value do not matter when
+ # the type of the previous benefit and the apprenticeship_program value do not
+ # matter when
# calculating the remaining available benefit time (Teams discussion)
past_benefit_type_iterator = itertools.cycle([True, False])
- # also, the apprenticeship_program setting in _past_ benefits does not matter to calculation, so
+ # also, the apprenticeship_program setting in _past_ benefits does not matter to
+ # calculation, so
# alternate it to produce more testable combinations
past_apprenticeship_iterator = itertools.cycle([True, False])
for class_name, previous_start_date, previous_end_date in previous_benefits:
@@ -353,7 +357,7 @@ def test_application_with_previously_accepted_applications_and_previous_benefits
end_date=date.fromisoformat(previous_end_date),
)
else:
- assert False, "unexpected"
+ raise AssertionError("unexpected")
handling_application.apprenticeship_program = apprenticeship_program
handling_application.pay_subsidy_granted = PaySubsidyGranted.GRANTED
diff --git a/backend/benefit/applications/tests/test_models.py b/backend/benefit/applications/tests/test_models.py
index 29e069316c..b829d0da36 100755
--- a/backend/benefit/applications/tests/test_models.py
+++ b/backend/benefit/applications/tests/test_models.py
@@ -85,7 +85,8 @@ def test_application_batch_ahjo_decision(application_batch, status, expected_res
ApplicationBatchStatus.DECIDED_ACCEPTED,
ApplicationBatchStatus.DECIDED_REJECTED,
]:
- # need to create a new batch because factory has already created valid fields using ApplicationBatchFactory
+ # need to create a new batch because factory has already created valid fields
+ # using ApplicationBatchFactory
application_batch.delete()
application_batch = BaseApplicationBatchFactory(
status=ApplicationBatchStatus.DRAFT,
@@ -125,7 +126,8 @@ def test_application_batch_modified(application_batch, status, expected_result):
ApplicationBatchStatus.DECIDED_ACCEPTED,
ApplicationBatchStatus.DECIDED_REJECTED,
]:
- # need to create a new batch because factory has already created valid fields using ApplicationBatchFactory
+ # need to create a new batch because factory has already created valid fields
+ # using ApplicationBatchFactory
application_batch.delete()
application_batch = BaseApplicationBatchFactory(
status=ApplicationBatchStatus.DRAFT,
diff --git a/backend/benefit/applications/tests/test_talpa_integration.py b/backend/benefit/applications/tests/test_talpa_integration.py
index 975e76b2f4..93a00fbdd1 100644
--- a/backend/benefit/applications/tests/test_talpa_integration.py
+++ b/backend/benefit/applications/tests/test_talpa_integration.py
@@ -89,7 +89,7 @@ def test_talpa_csv_output(
)
# BOM at the beginning of the file
assert csv_lines[0][0] == '\ufeff"Hakemusnumero"'
- csv_columns = iter(talpa_applications_csv_service_with_one_application.CSV_COLUMNS)
+ csv_columns = iter(talpa_applications_csv_service_with_one_application.csv_columns)
next(csv_columns, None) # Skip the first element
for idx, col in enumerate(csv_columns, start=1):
diff --git a/backend/benefit/applications/tests/test_view_sets.py b/backend/benefit/applications/tests/test_view_sets.py
index d635e91b39..581722bace 100644
--- a/backend/benefit/applications/tests/test_view_sets.py
+++ b/backend/benefit/applications/tests/test_view_sets.py
@@ -26,7 +26,7 @@ class MockRequestWithAnonymousUser:
assert len(Application.objects.all()) == 7
view_set: ApplicantApplicationViewSet = ApplicantApplicationViewSet()
- setattr(view_set, "request", MockRequestWithAnonymousUser())
+ view_set.request = MockRequestWithAnonymousUser()
queryset: QuerySet[Application] = view_set.get_queryset()
if next_public_mock_flag:
diff --git a/backend/benefit/calculator/api/v1/serializers.py b/backend/benefit/calculator/api/v1/serializers.py
index 879facc1be..0f6a13c076 100644
--- a/backend/benefit/calculator/api/v1/serializers.py
+++ b/backend/benefit/calculator/api/v1/serializers.py
@@ -9,12 +9,12 @@
from calculator.api.v1.validators import InstalmentStatusValidator
from calculator.enums import InstalmentStatus
from calculator.models import (
+ STATE_AID_MAX_PERCENTAGE_CHOICES,
Calculation,
CalculationRow,
Instalment,
PaySubsidy,
PreviousBenefit,
- STATE_AID_MAX_PERCENTAGE_CHOICES,
TrainingCompensation,
)
from users.api.v1.serializers import UserSerializer
@@ -81,13 +81,6 @@ def validate_status(self, status):
return status
- amount_after_recoveries = serializers.SerializerMethodField(
- "get_amount_after_recoveries",
- )
-
- def amount_after_recoveries(self, obj):
- return getattr(obj, "amount_after_recoveries", None)
-
status = serializers.ChoiceField(
validators=[InstalmentStatusValidator()],
choices=InstalmentStatus.choices,
@@ -131,7 +124,8 @@ class CalculationSerializer(serializers.ModelSerializer):
def _validate_date_range(self, start_date, end_date):
# Only validate date range if both of them are set
if start_date is not None and end_date is not None:
- # validation is more relaxed as it's assumed that the handlers know what they're doing
+ # validation is more relaxed as it's assumed that the handlers know what
+ # they're doing
if (
start_date + relativedelta(months=self.CALCULATION_MAX_MONTHS)
<= end_date
@@ -257,7 +251,8 @@ def update(self, instance, validated_data):
ret.append(self.child.create(data))
else:
ret.append(self.child.update(obj, data))
- # ordering field is not exposed in API, it is added in ApplicantApplicationSerializer
+ # ordering field is not exposed in API, it is added in
+ # ApplicantApplicationSerializer
if ordering := data.get("ordering"):
ret[-1].ordering = ordering
ret[-1].save()
diff --git a/backend/benefit/calculator/api/v1/views.py b/backend/benefit/calculator/api/v1/views.py
index 2ea4863f4b..9a58300f58 100644
--- a/backend/benefit/calculator/api/v1/views.py
+++ b/backend/benefit/calculator/api/v1/views.py
@@ -1,7 +1,8 @@
from django.shortcuts import get_object_or_404
from django_filters import rest_framework as filters
from drf_spectacular.utils import extend_schema
-from rest_framework import filters as drf_filters, status
+from rest_framework import filters as drf_filters
+from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
@@ -28,7 +29,9 @@ class Meta:
@extend_schema(
- description="API for create/read/update/delete operations on PreviousBenefit objects"
+ description=(
+ "API for create/read/update/delete operations on PreviousBenefit objects"
+ )
)
class PreviousBenefitViewSet(AuditLoggingModelViewSet):
queryset = PreviousBenefit.objects.all()
diff --git a/backend/benefit/calculator/enums.py b/backend/benefit/calculator/enums.py
index a9aca112fa..2d35cb4490 100644
--- a/backend/benefit/calculator/enums.py
+++ b/backend/benefit/calculator/enums.py
@@ -7,20 +7,25 @@ class RowType(models.TextChoices):
SALARY_COSTS_EUR = "salary_costs", _("Salary costs") # Palkkauskustannukset
STATE_AID_MAX_MONTHLY_EUR = "state_aid_max_monthly_eur", _("State aid maximum %")
PAY_SUBSIDY_MONTHLY_EUR = "pay_subsidy_monthly_eur", _("Pay subsidy/month")
- HELSINKI_BENEFIT_MONTHLY_EUR = "helsinki_benefit_monthly_eur", _(
- "Helsinki benefit amount monthly"
+ HELSINKI_BENEFIT_MONTHLY_EUR = (
+ "helsinki_benefit_monthly_eur",
+ _("Helsinki benefit amount monthly"),
)
- HELSINKI_BENEFIT_SUB_TOTAL_EUR = "helsinki_benefit_sub_total_eur", _(
- "Helsinki benefit amount for a date range"
+ HELSINKI_BENEFIT_SUB_TOTAL_EUR = (
+ "helsinki_benefit_sub_total_eur",
+ _("Helsinki benefit amount for a date range"),
)
- HELSINKI_BENEFIT_TOTAL_EUR = "helsinki_benefit_total_eur", _(
- "Helsinki benefit total amount"
+ HELSINKI_BENEFIT_TOTAL_EUR = (
+ "helsinki_benefit_total_eur",
+ _("Helsinki benefit total amount"),
)
- TRAINING_COMPENSATION_MONTHLY_EUR = "training_compensation_monthly_eur", _(
- "Training compensation amount monthly"
+ TRAINING_COMPENSATION_MONTHLY_EUR = (
+ "training_compensation_monthly_eur",
+ _("Training compensation amount monthly"),
)
- DEDUCTIONS_TOTAL_EUR = "deductions_total_eur", _(
- "Total amount of deductions monthly"
+ DEDUCTIONS_TOTAL_EUR = (
+ "deductions_total_eur",
+ _("Total amount of deductions monthly"),
)
diff --git a/backend/benefit/calculator/migrations/0001_initial.py b/backend/benefit/calculator/migrations/0001_initial.py
index 94ea2f1c6a..7075fe3cae 100644
--- a/backend/benefit/calculator/migrations/0001_initial.py
+++ b/backend/benefit/calculator/migrations/0001_initial.py
@@ -1,15 +1,15 @@
# Generated by Django 3.2.4 on 2021-10-07 11:11
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import encrypted_fields.fields
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
-
initial = True
dependencies = [
@@ -78,7 +78,9 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=7,
null=True,
- verbose_name="amount of the benefit granted, calculated by the system",
+ verbose_name=(
+ "amount of the benefit granted, calculated by the system"
+ ),
),
),
(
@@ -88,14 +90,19 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=7,
null=True,
- verbose_name="amount of the benefit manually entered by the application handler",
+ verbose_name=(
+ "amount of the benefit manually entered by the application"
+ " handler"
+ ),
),
),
(
"override_benefit_amount_comment",
models.CharField(
max_length=256,
- verbose_name="reason for overriding the calculated benefit amount",
+ verbose_name=(
+ "reason for overriding the calculated benefit amount"
+ ),
),
),
(
@@ -556,7 +563,9 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=7,
null=True,
- verbose_name="amount of the benefit granted, calculated by the system",
+ verbose_name=(
+ "amount of the benefit granted, calculated by the system"
+ ),
),
),
(
@@ -566,14 +575,19 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=7,
null=True,
- verbose_name="amount of the benefit manually entered by the application handler",
+ verbose_name=(
+ "amount of the benefit manually entered by the application"
+ " handler"
+ ),
),
),
(
"override_benefit_amount_comment",
models.CharField(
max_length=256,
- verbose_name="reason for overriding the calculated benefit amount",
+ verbose_name=(
+ "reason for overriding the calculated benefit amount"
+ ),
),
),
("history_id", models.AutoField(primary_key=True, serialize=False)),
diff --git a/backend/benefit/calculator/migrations/0002_simple_benefit_calculation.py b/backend/benefit/calculator/migrations/0002_simple_benefit_calculation.py
index 286aa7081a..22ca156905 100644
--- a/backend/benefit/calculator/migrations/0002_simple_benefit_calculation.py
+++ b/backend/benefit/calculator/migrations/0002_simple_benefit_calculation.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0001_initial"),
]
diff --git a/backend/benefit/calculator/migrations/0003_changes_for_calculator_api.py b/backend/benefit/calculator/migrations/0003_changes_for_calculator_api.py
index 7034b3098e..44407c813f 100644
--- a/backend/benefit/calculator/migrations/0003_changes_for_calculator_api.py
+++ b/backend/benefit/calculator/migrations/0003_changes_for_calculator_api.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0002_simple_benefit_calculation"),
]
diff --git a/backend/benefit/calculator/migrations/0004_add_handler.py b/backend/benefit/calculator/migrations/0004_add_handler.py
index 267ae09c73..1821d8fc6b 100644
--- a/backend/benefit/calculator/migrations/0004_add_handler.py
+++ b/backend/benefit/calculator/migrations/0004_add_handler.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2021-11-04 05:06
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("calculator", "0003_changes_for_calculator_api"),
diff --git a/backend/benefit/calculator/migrations/0005_pay_subsidy_percent_not_null.py b/backend/benefit/calculator/migrations/0005_pay_subsidy_percent_not_null.py
index 5fce150008..899e607e00 100644
--- a/backend/benefit/calculator/migrations/0005_pay_subsidy_percent_not_null.py
+++ b/backend/benefit/calculator/migrations/0005_pay_subsidy_percent_not_null.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0004_add_handler"),
]
diff --git a/backend/benefit/calculator/migrations/0006_employeebenefitmonthlyrow_employeebenefittotalrow.py b/backend/benefit/calculator/migrations/0006_employeebenefitmonthlyrow_employeebenefittotalrow.py
index 1b86765e8f..7270295418 100644
--- a/backend/benefit/calculator/migrations/0006_employeebenefitmonthlyrow_employeebenefittotalrow.py
+++ b/backend/benefit/calculator/migrations/0006_employeebenefitmonthlyrow_employeebenefittotalrow.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0005_pay_subsidy_percent_not_null"),
]
diff --git a/backend/benefit/calculator/migrations/0007_apprenticeship_calculation.py b/backend/benefit/calculator/migrations/0007_apprenticeship_calculation.py
index ff472f88f8..5d099d4eec 100644
--- a/backend/benefit/calculator/migrations/0007_apprenticeship_calculation.py
+++ b/backend/benefit/calculator/migrations/0007_apprenticeship_calculation.py
@@ -1,14 +1,14 @@
# Generated by Django 3.2.4 on 2021-11-30 07:34
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0026_alter_applicationbatch_status"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
diff --git a/backend/benefit/calculator/migrations/0008_add_start_end_time_to_calc_row.py b/backend/benefit/calculator/migrations/0008_add_start_end_time_to_calc_row.py
index cf8ce8362d..c21182fb7f 100644
--- a/backend/benefit/calculator/migrations/0008_add_start_end_time_to_calc_row.py
+++ b/backend/benefit/calculator/migrations/0008_add_start_end_time_to_calc_row.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0007_apprenticeship_calculation"),
]
diff --git a/backend/benefit/calculator/migrations/0009_work_time_percent_to_decimal.py b/backend/benefit/calculator/migrations/0009_work_time_percent_to_decimal.py
index cbf39aefd0..e84a362a55 100644
--- a/backend/benefit/calculator/migrations/0009_work_time_percent_to_decimal.py
+++ b/backend/benefit/calculator/migrations/0009_work_time_percent_to_decimal.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0008_add_start_end_time_to_calc_row"),
]
diff --git a/backend/benefit/calculator/migrations/0010_override_monthly_benefit_amount.py b/backend/benefit/calculator/migrations/0010_override_monthly_benefit_amount.py
index 18484a1437..a000ad83e0 100644
--- a/backend/benefit/calculator/migrations/0010_override_monthly_benefit_amount.py
+++ b/backend/benefit/calculator/migrations/0010_override_monthly_benefit_amount.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0009_work_time_percent_to_decimal"),
]
@@ -46,7 +45,10 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=7,
null=True,
- verbose_name="monthly amount of the benefit manually entered by the application handler",
+ verbose_name=(
+ "monthly amount of the benefit manually entered by the application"
+ " handler"
+ ),
),
),
migrations.AddField(
@@ -57,7 +59,10 @@ class Migration(migrations.Migration):
decimal_places=2,
max_digits=7,
null=True,
- verbose_name="monthly amount of the benefit manually entered by the application handler",
+ verbose_name=(
+ "monthly amount of the benefit manually entered by the application"
+ " handler"
+ ),
),
),
]
diff --git a/backend/benefit/calculator/migrations/0011_make_calculation_fields_nullable.py b/backend/benefit/calculator/migrations/0011_make_calculation_fields_nullable.py
index c19c183ca2..42faa20ce3 100644
--- a/backend/benefit/calculator/migrations/0011_make_calculation_fields_nullable.py
+++ b/backend/benefit/calculator/migrations/0011_make_calculation_fields_nullable.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0010_override_monthly_benefit_amount"),
]
diff --git a/backend/benefit/calculator/migrations/0013_alter_paysubsidy_percentages.py b/backend/benefit/calculator/migrations/0013_alter_paysubsidy_percentages.py
index 60a3da5799..8303830202 100644
--- a/backend/benefit/calculator/migrations/0013_alter_paysubsidy_percentages.py
+++ b/backend/benefit/calculator/migrations/0013_alter_paysubsidy_percentages.py
@@ -4,30 +4,47 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('calculator', '0012_history_date_format_changes'),
+ ("calculator", "0012_history_date_format_changes"),
]
operations = [
migrations.AlterField(
- model_name='calculation',
- name='state_aid_max_percentage',
- field=models.IntegerField(blank=True, choices=[(50, '50%'), (70, '70%'), (100, '100%')], default=None, null=True, verbose_name='State aid maximum %'),
+ model_name="calculation",
+ name="state_aid_max_percentage",
+ field=models.IntegerField(
+ blank=True,
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ default=None,
+ null=True,
+ verbose_name="State aid maximum %",
+ ),
),
migrations.AlterField(
- model_name='historicalcalculation',
- name='state_aid_max_percentage',
- field=models.IntegerField(blank=True, choices=[(50, '50%'), (70, '70%'), (100, '100%')], default=None, null=True, verbose_name='State aid maximum %'),
+ model_name="historicalcalculation",
+ name="state_aid_max_percentage",
+ field=models.IntegerField(
+ blank=True,
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ default=None,
+ null=True,
+ verbose_name="State aid maximum %",
+ ),
),
migrations.AlterField(
- model_name='historicalpaysubsidy',
- name='pay_subsidy_percent',
- field=models.IntegerField(choices=[(50, '50%'), (70, '70%'), (100, '100%')], verbose_name='Pay subsidy percent'),
+ model_name="historicalpaysubsidy",
+ name="pay_subsidy_percent",
+ field=models.IntegerField(
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ verbose_name="Pay subsidy percent",
+ ),
),
migrations.AlterField(
- model_name='paysubsidy',
- name='pay_subsidy_percent',
- field=models.IntegerField(choices=[(50, '50%'), (70, '70%'), (100, '100%')], verbose_name='Pay subsidy percent'),
+ model_name="paysubsidy",
+ name="pay_subsidy_percent",
+ field=models.IntegerField(
+ choices=[(50, "50%"), (70, "70%"), (100, "100%")],
+ verbose_name="Pay subsidy percent",
+ ),
),
]
diff --git a/backend/benefit/calculator/migrations/0014_add_description_type_to_row.py b/backend/benefit/calculator/migrations/0014_add_description_type_to_row.py
index 71cac0cb99..76ecf34613 100644
--- a/backend/benefit/calculator/migrations/0014_add_description_type_to_row.py
+++ b/backend/benefit/calculator/migrations/0014_add_description_type_to_row.py
@@ -4,20 +4,37 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('calculator', '0013_alter_paysubsidy_percentages'),
+ ("calculator", "0013_alter_paysubsidy_percentages"),
]
operations = [
migrations.AddField(
- model_name='calculationrow',
- name='description_type',
- field=models.CharField(blank=True, choices=[('date', 'Basic date range description'), ('date_total', 'Date range description for total row'), ('deduction', 'Deduction description')], max_length=64, null=True),
+ model_name="calculationrow",
+ name="description_type",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("date", "Basic date range description"),
+ ("date_total", "Date range description for total row"),
+ ("deduction", "Deduction description"),
+ ],
+ max_length=64,
+ null=True,
+ ),
),
migrations.AddField(
- model_name='historicalcalculationrow',
- name='description_type',
- field=models.CharField(blank=True, choices=[('date', 'Basic date range description'), ('date_total', 'Date range description for total row'), ('deduction', 'Deduction description')], max_length=64, null=True),
+ model_name="historicalcalculationrow",
+ name="description_type",
+ field=models.CharField(
+ blank=True,
+ choices=[
+ ("date", "Basic date range description"),
+ ("date_total", "Date range description for total row"),
+ ("deduction", "Deduction description"),
+ ],
+ max_length=64,
+ null=True,
+ ),
),
]
diff --git a/backend/benefit/calculator/migrations/0015_desc_type_for_old_calc_rows.py b/backend/benefit/calculator/migrations/0015_desc_type_for_old_calc_rows.py
index 221a7fe60e..94d268b9f3 100644
--- a/backend/benefit/calculator/migrations/0015_desc_type_for_old_calc_rows.py
+++ b/backend/benefit/calculator/migrations/0015_desc_type_for_old_calc_rows.py
@@ -1,7 +1,8 @@
# Generated by Django 3.2.18 on 2023-11-20 17:28
from django.db import migrations
-from calculator.enums import RowType, DescriptionType
+
+from calculator.enums import DescriptionType, RowType
def add_description_type(apps, _):
diff --git a/backend/benefit/calculator/migrations/0016_change_pay_subsidy_work_time_default.py b/backend/benefit/calculator/migrations/0016_change_pay_subsidy_work_time_default.py
index 8c26ff657c..7d196b7181 100644
--- a/backend/benefit/calculator/migrations/0016_change_pay_subsidy_work_time_default.py
+++ b/backend/benefit/calculator/migrations/0016_change_pay_subsidy_work_time_default.py
@@ -1,24 +1,38 @@
# Generated by Django 3.2.23 on 2024-04-02 07:14
from decimal import Decimal
+
from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
- ('calculator', '0015_desc_type_for_old_calc_rows'),
+ ("calculator", "0015_desc_type_for_old_calc_rows"),
]
operations = [
migrations.AlterField(
- model_name='historicalpaysubsidy',
- name='work_time_percent',
- field=models.DecimalField(blank=True, decimal_places=2, default=Decimal('65'), max_digits=5, null=True, verbose_name='Work time percent'),
+ model_name="historicalpaysubsidy",
+ name="work_time_percent",
+ field=models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ default=Decimal("65"),
+ max_digits=5,
+ null=True,
+ verbose_name="Work time percent",
+ ),
),
migrations.AlterField(
- model_name='paysubsidy',
- name='work_time_percent',
- field=models.DecimalField(blank=True, decimal_places=2, default=Decimal('65'), max_digits=5, null=True, verbose_name='Work time percent'),
+ model_name="paysubsidy",
+ name="work_time_percent",
+ field=models.DecimalField(
+ blank=True,
+ decimal_places=2,
+ default=Decimal("65"),
+ max_digits=5,
+ null=True,
+ verbose_name="Work time percent",
+ ),
),
]
diff --git a/backend/benefit/calculator/migrations/0017_instalment.py b/backend/benefit/calculator/migrations/0017_instalment.py
index c0611fbd36..b10169273b 100644
--- a/backend/benefit/calculator/migrations/0017_instalment.py
+++ b/backend/benefit/calculator/migrations/0017_instalment.py
@@ -1,9 +1,10 @@
# Generated by Django 4.2.11 on 2024-10-23 15:15
-from django.db import migrations, models
-import django.db.models.deletion
import uuid
+import django.db.models.deletion
+from django.db import migrations, models
+
class Migration(migrations.Migration):
dependencies = [
diff --git a/backend/benefit/calculator/migrations/0018_instalment_amount_paid.py b/backend/benefit/calculator/migrations/0018_instalment_amount_paid.py
index c2eb4bea58..be6b65c9df 100644
--- a/backend/benefit/calculator/migrations/0018_instalment_amount_paid.py
+++ b/backend/benefit/calculator/migrations/0018_instalment_amount_paid.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("calculator", "0017_instalment"),
]
@@ -19,7 +18,12 @@ class Migration(migrations.Migration):
editable=False,
max_digits=7,
null=True,
- verbose_name="To be set only ONCE when final amount is sent to Talpa. The set value should be defined by 'amount' field that is reduced by handled ApplicationAlteration recoveries at the time of Talpa robot visit.",
+ verbose_name=(
+ "To be set only ONCE when final amount is sent to Talpa. The set"
+ " value should be defined by 'amount' field that is reduced by"
+ " handled ApplicationAlteration recoveries at the time of Talpa"
+ " robot visit."
+ ),
),
),
]
diff --git a/backend/benefit/calculator/models.py b/backend/benefit/calculator/models.py
index 3bb080029d..0166a95789 100644
--- a/backend/benefit/calculator/models.py
+++ b/backend/benefit/calculator/models.py
@@ -10,13 +10,13 @@
from simple_history.models import HistoricalRecords
from applications.enums import ApplicationAlterationState
-from applications.models import Application, PAY_SUBSIDY_PERCENT_CHOICES
+from applications.models import PAY_SUBSIDY_PERCENT_CHOICES, Application
from calculator.enums import DescriptionType, InstalmentStatus, RowType
from common.exceptions import BenefitAPIException
from common.utils import (
+ DurationMixin,
date_range_overlap,
duration_in_months,
- DurationMixin,
nested_getattr,
to_decimal,
)
@@ -58,7 +58,7 @@ class Calculation(UUIDModel, TimeStampedModel, DurationMixin):
The fields in Calculation is editable by handler. The value entered by applicant is stored in Application
For additional descriptions of the fields, see the API documentation (serializers.py)
- """
+ """ # noqa: E501
handler = models.ForeignKey(
settings.AUTH_USER_MODEL,
@@ -170,8 +170,8 @@ def reset_values(self):
# 1. Fill the fields of this Calculation based on the data that the applicant
# entered in the Application. The handlers are supposed to edit the values
# in Calculation, so the data entered by applicant stays intact.
- # 2. reset pay subsidy objects according to the applicant's input. One exception,
- # default value for start_time and end_time will be null
+ # 2. reset pay subsidy objects according to the applicant's input. One
+ # exception, default value for start_time and end_time will be null
for (
source_field_name,
@@ -193,7 +193,7 @@ def init_calculator(self):
and possibly other attributes, such as date of the application.
The calculator object should not be changed while calculation is ongoing.
- """
+ """ # noqa: E501
from calculator.rules import HelsinkiBenefitCalculator
if self.calculator is None:
@@ -201,7 +201,7 @@ def init_calculator(self):
return self.calculator
def calculate(self, override_status=False):
- """Do the calculation again. Override status is used to force the calculation when cloning an application"""
+ """Do the calculation again. Override status is used to force the calculation when cloning an application""" # noqa: E501
try:
return self.init_calculator().calculate(override_status=override_status)
@@ -273,7 +273,7 @@ def merge_compatible_subsidies(pay_subsidies):
* they have the equal values in these fields: application, pay_subsidy_percent, work_time_percent,
disability_or_illness
* the date ranges either overlap or are adjacent to each other
- """
+ """ # noqa: E501
if len(pay_subsidies) == 0:
return []
pay_subsidies.sort(key=operator.attrgetter("start_date"))
@@ -303,9 +303,9 @@ def merge_compatible_subsidies(pay_subsidies):
)
)
else:
- assert (
- ret[-1].application == subsidy.application
- ), "Should only process PaySubsidies with the same application"
+ assert ret[-1].application == subsidy.application, (
+ "Should only process PaySubsidies with the same application"
+ )
# it's a compatible PaySubsidy, just merge it with the previous one
ret[-1].start_date = min(ret[-1].start_date, subsidy.start_date)
ret[-1].end_date = max(ret[-1].end_date, subsidy.end_date)
@@ -518,8 +518,8 @@ def __init__(self, *args, **kwargs):
if start_date and end_date and prefix_text:
self.description_fi_template = (
- f'{prefix_text} {format_date(start_date, locale="fi_FI")} - '
- f'{format_date(end_date, locale="fi_FI")} '
+ f"{prefix_text} {format_date(start_date, locale='fi_FI')} - "
+ f"{format_date(end_date, locale='fi_FI')} "
f"({to_decimal(duration_in_months(start_date, end_date), 2)} kk)"
)
super().__init__(*args, **kwargs)
@@ -578,7 +578,7 @@ class PaySubsidyMonthlyRow(CalculationRow):
* 100% pay subsidy has been granted for 6 months
* Pay subsidy is calcuated using formula:
min(2020, (monthly_pay / work_time_fraction * 0.65) * 1.23
- """
+ """ # noqa: E501
MAX_WORK_TIME_FRACTION_FOR_FULL_PAY_SUBSIDY = decimal.Decimal("0.65")
GROSS_WAGE_COEFFICIENT_FOR_FULL_PAY_SUBSIDY = decimal.Decimal("1.23")
@@ -590,11 +590,12 @@ def __init__(self, *args, **kwargs):
def calculate_amount(self):
"""
1.7.2023 voimaantulevan lain mukaan lomarahaa ja sivukuluja ei oteta enää huomioon palkkatuen määrää laskiessa
- """
+ """ # noqa: E501
assert self.max_subsidy is not None
assert self.pay_subsidy is not None
- # for calculations, use a fraction in [0,1] range instead of a percent in [0,100] range
+ # for calculations, use a fraction in [0,1] range instead of a percent in
+ # [0,100] range
work_time_fraction = self.pay_subsidy.get_work_time_percent() * decimal.Decimal(
"0.01"
)
@@ -710,9 +711,9 @@ def monthly_amount(self):
.order_by("-ordering")
.first()
)
- assert (
- row is not None
- ), "Application logic error - misconstructed application rows"
+ assert row is not None, (
+ "Application logic error - misconstructed application rows"
+ )
return row.amount
@@ -837,7 +838,7 @@ class Meta:
class Instalment(UUIDModel, TimeStampedModel):
"""
Instalment model for Helsinki benefit grantend benefits that are paid in (two )instalments
- """
+ """ # noqa: E501
calculation = models.ForeignKey(
Calculation,
@@ -860,8 +861,9 @@ class Instalment(UUIDModel, TimeStampedModel):
decimal_places=2,
editable=False,
verbose_name=_(
- "To be set only ONCE when final amount is sent to Talpa. The set value should be defined by 'amount' "
- "field that is reduced by handled ApplicationAlteration recoveries at the time of Talpa robot visit."
+ "To be set only ONCE when final amount is sent to Talpa. The set value"
+ " should be defined by 'amount' field that is reduced by handled"
+ " ApplicationAlteration recoveries at the time of Talpa robot visit."
),
blank=True,
null=True,
@@ -904,10 +906,12 @@ def amount_after_recoveries(self):
)
def __str__(self):
- return f"Instalment of {self.amount}€, \
-number {self.instalment_number}/{self.calculation.instalments.count()} \
-for application {self.calculation.application.application_number}, \
-due in {self.due_date}, status: {self.status}."
+ return (
+ f"Instalment of {self.amount}€, number"
+ f" {self.instalment_number}/{self.calculation.instalments.count()} for"
+ f" application {self.calculation.application.application_number}, due in"
+ f" {self.due_date}, status: {self.status}."
+ )
class Meta:
db_table = "bf_calculator_instalment"
diff --git a/backend/benefit/calculator/rules.py b/backend/benefit/calculator/rules.py
index a0f278ebb6..5d0a7e2ee1 100644
--- a/backend/benefit/calculator/rules.py
+++ b/backend/benefit/calculator/rules.py
@@ -62,7 +62,7 @@ def _get_item_in_effect(
) -> Union[PaySubsidy, None]:
"""Return the first item in the list whose start date is less than or equal to the given day,
and whose end date is greater than or equal to the given day.
- If no such item is found, it returns None."""
+ If no such item is found, it returns None.""" # noqa: E501
for item in items:
if (
item.start_date is not None
@@ -74,7 +74,8 @@ def _get_item_in_effect(
@staticmethod
def get_calculator(calculation: Calculation):
- # in future, one might use e.g. application date to determine the correct calculator
+ # in future, one might use e.g. application date to determine the correct
+ # calculator
if calculation.override_monthly_benefit_amount is not None:
return ManualOverrideCalculator(calculation)
elif calculation.application.benefit_type == BenefitType.SALARY_BENEFIT:
@@ -87,7 +88,7 @@ def get_calculator(calculation: Calculation):
def get_sub_total_ranges(self):
"""return a list of BenefitSubRange(start_date, end_date, pay_subsidy, training_compensation)
that require a separate calculation.
- date range are inclusive"""
+ date range are inclusive""" # noqa: E501
if self.calculation.start_date is None or self.calculation.end_date is None:
raise ValueError(
@@ -131,7 +132,8 @@ def get_sub_total_ranges(self):
return ranges
def get_amount(self, row_type: RowType, default=None):
- # This function is used by the various CalculationRow to retrieve a previously calculated value
+ # This function is used by the various CalculationRow to retrieve a previously
+ # calculated value
row = (
self.calculation.rows.order_by("-ordering")
.filter(row_type=row_type)
@@ -177,7 +179,7 @@ def _calculate_instalment_amounts(
If not, two instalments are created, with the amount of
the first instalment being equal to the FIRST_INSTALMENT_LIMIT,
and the second being equal to the rest of the total.
- """
+ """ # noqa: E501
if total_benefit_amount <= self.instalment_threshold:
return [
(
@@ -232,7 +234,8 @@ def calculate(self, override_status=False):
self.calculation.instalments.all().delete()
if self.can_calculate():
self.create_rows()
- # the total benefit amount is stored in Calculation model, for easier processing.
+ # the total benefit amount is stored in Calculation model, for easier
+ # processing.
total_benefit_amount = self.get_amount(
RowType.HELSINKI_BENEFIT_TOTAL_EUR
)
@@ -283,7 +286,8 @@ class SalaryBenefitCalculator2023(HelsinkiBenefitCalculator):
Calculation of salary benefit, according to rules in effect starting from 1.7.2023
"""
- # The maximum amount of pay subsidy depends on the pay subsidy percent in the pay subsidy decision.
+ # The maximum amount of pay subsidy depends on the pay subsidy percent in the pay
+ # subsidy decision.
PAY_SUBSIDY_MAX_FOR_100_PERCENT = settings.PAY_SUBSIDY_MAX_FOR_100_PERCENT
PAY_SUBSIDY_MAX_FOR_70_PERCENT = settings.PAY_SUBSIDY_MAX_FOR_70_PERCENT
PAY_SUBSIDY_MAX_FOR_50_PERCENT = settings.PAY_SUBSIDY_MAX_FOR_50_PERCENT
@@ -372,7 +376,8 @@ def create_deduction_rows(self, benefit_sub_range):
and benefit_sub_range.training_compensation
and benefit_sub_range.training_compensation.monthly_amount > 0
):
- # as per UI design, create the totals row even if the amount of training compensation
+ # as per UI design, create the totals row even if the amount of training
+ # compensation
# is zero, if the TrainingCompensation has been created
self._create_row(
TotalDeductionsMonthlyRow, monthly_deductions=monthly_deductions
@@ -433,7 +438,7 @@ def create_rows(self):
class EmployeeBenefitCalculator2021(HelsinkiBenefitCalculator):
"""
Calculation of employee benefit, according to rules in effect 2021 (and possibly onwards)
- """
+ """ # noqa: E501
EMPLOYEE_BENEFIT_AMOUNT_PER_MONTH = 500
diff --git a/backend/benefit/calculator/tests/factories.py b/backend/benefit/calculator/tests/factories.py
index 376cf0f1a7..384aa7531d 100644
--- a/backend/benefit/calculator/tests/factories.py
+++ b/backend/benefit/calculator/tests/factories.py
@@ -7,12 +7,12 @@
from applications.tests.factories import ApplicationFactory
from calculator.enums import RowType
from calculator.models import (
+ STATE_AID_MAX_PERCENTAGE_CHOICES,
Calculation,
CalculationRow,
Instalment,
PaySubsidy,
PreviousBenefit,
- STATE_AID_MAX_PERCENTAGE_CHOICES,
TrainingCompensation,
)
from common.utils import duration_in_months
diff --git a/backend/benefit/calculator/tests/test_calculator_api.py b/backend/benefit/calculator/tests/test_calculator_api.py
index e0916934b2..bd9366e0c1 100644
--- a/backend/benefit/calculator/tests/test_calculator_api.py
+++ b/backend/benefit/calculator/tests/test_calculator_api.py
@@ -178,7 +178,8 @@ def test_modify_calculation(handler_api_client, handling_application):
assert handling_application.calculation
handling_application.pay_subsidies.all().delete()
data["calculation"]["monthly_pay"] = "1234.56"
- # also modify pay_subsidies. Although multiple objects are modified, calculate() should only
+ # also modify pay_subsidies. Although multiple objects are modified, calculate()
+ # should only
# be called once.
data["pay_subsidies"] = [
{
@@ -573,9 +574,9 @@ def test_ignore_pay_subsidy_dates_when_on_manual_calculator(
data["calculation"]["start_date"] = str(handling_application.start_date)
data["calculation"]["end_date"] = str(handling_application.end_date)
data["calculation"]["override_monthly_benefit_amount"] = "100.00"
- data["calculation"][
- "override_monthly_benefit_amount_comment"
- ] = "This is a comment."
+ data["calculation"]["override_monthly_benefit_amount_comment"] = (
+ "This is a comment."
+ )
_set_two_pay_subsidies_with_empty_dates(data)
diff --git a/backend/benefit/calculator/tests/test_handler_excel_examples.py b/backend/benefit/calculator/tests/test_handler_excel_examples.py
index 4bcdb7f96c..df73834d8a 100644
--- a/backend/benefit/calculator/tests/test_handler_excel_examples.py
+++ b/backend/benefit/calculator/tests/test_handler_excel_examples.py
@@ -6,13 +6,13 @@
from applications.enums import ApplicationStatus, BenefitType
from applications.tests.factories import ApplicationFactory
-from calculator.models import Calculation, STATE_AID_MAX_PERCENTAGE_CHOICES
+from calculator.models import STATE_AID_MAX_PERCENTAGE_CHOICES, Calculation
from calculator.tests.factories import PaySubsidyFactory, TrainingCompensationFactory
from common.utils import nested_setattr, to_decimal
from helsinkibenefit.tests.conftest import * # noqa
-class CaseNotFound(Exception):
+class CaseNotFoundError(Exception):
pass
@@ -55,7 +55,7 @@ def _setup(self):
self._setup_db_objects()
self._load_values_from_excel()
if self.expected_results.calculated_benefit_amount is None:
- raise CaseNotFound
+ raise CaseNotFoundError
self._save_initial_state()
def _setup_expected_results(self):
@@ -135,14 +135,14 @@ def _load_values_from_excel(self):
value = self.value_conversion_table[value]
elif target.endswith("_date"):
value = self.convert_date(value)
- elif target.endswith("percent") or target.endswith("percentage"):
+ elif target.endswith(("percent", "percentage")):
if value is not None:
value = to_decimal(value * 100, decimal_places=2)
elif isinstance(target, float):
if value is not None:
value = to_decimal(value, decimal_places=2)
- print(
+ print( # noqa: T201
f"{get_column_letter(self.column_idx)} {target}={value} ({type(value)}"
)
nested_setattr(self, target, value)
@@ -208,7 +208,7 @@ def run_test(self):
def _verify_results(self):
for row in self.application.calculation.rows.all():
- print(row)
+ print(row) # noqa: T201
assert (
self.application.calculation.calculated_benefit_amount
== self.expected_results.calculated_benefit_amount
@@ -265,7 +265,7 @@ def run_test(self):
def _verify_results(self):
for row in self.application.calculation.rows.all():
- print(row)
+ print(row) # noqa: T201
assert (
self.application.calculation.calculated_benefit_amount
== self.expected_results.calculated_benefit_amount
@@ -291,7 +291,7 @@ def test_cases_from_excel(request, api_client):
):
continue
test_sheet = wb[sheet_name]
- print(f"sheet {sheet_name}")
+ print(f"sheet {sheet_name}") # noqa: T201
run_sheet(test_handler_class, test_sheet)
@@ -313,5 +313,5 @@ def run_sheet(test_handler_class, test_sheet):
pdb.post_mortem()
else:
test.run_test()
- except CaseNotFound: # no tests
+ except CaseNotFoundError: # no tests
assert col_idx > 4 # all sheets should have at least some tests
diff --git a/backend/benefit/calculator/tests/test_models.py b/backend/benefit/calculator/tests/test_models.py
index 6d85eaf90a..b5408714ef 100644
--- a/backend/benefit/calculator/tests/test_models.py
+++ b/backend/benefit/calculator/tests/test_models.py
@@ -94,10 +94,8 @@ def test_pay_subsidy_maximum(handling_application, pay_subsidy_percent, max_subs
@pytest.mark.parametrize(
- (
- "benefit_type,start_date,end_date,state_aid_max_percentage,"
- "pay_subsidy_start_date,pay_subsidy_end_date,can_calculate"
- ),
+ "benefit_type,start_date,end_date,state_aid_max_percentage,"
+ "pay_subsidy_start_date,pay_subsidy_end_date,can_calculate",
[
(
BenefitType.SALARY_BENEFIT,
diff --git a/backend/benefit/common/debug_util.py b/backend/benefit/common/debug_util.py
index ed58588d28..8bc434e78e 100644
--- a/backend/benefit/common/debug_util.py
+++ b/backend/benefit/common/debug_util.py
@@ -55,5 +55,6 @@ def rest_framework_debug_exception_handler(exc, context):
}
"""
pdb.post_mortem()
- # Call REST framework's default exception handler to get the standard error response.
+ # Call REST framework's default exception handler to get the standard error
+ # response.
return exception_handler(exc, context)
diff --git a/backend/benefit/common/delay_call.py b/backend/benefit/common/delay_call.py
index 351075dad9..d62ba609b9 100644
--- a/backend/benefit/common/delay_call.py
+++ b/backend/benefit/common/delay_call.py
@@ -33,7 +33,7 @@ def call_now_or_later(func, duplicate_check=None):
def _call_all_pending():
if _get_pending_calls() is None:
raise Exception("This function must be used only with update_at_end")
- for k, func in list(_get_pending_calls().items()):
+ for func in list(_get_pending_calls().values()):
func()
_get_pending_calls().clear()
@@ -46,7 +46,8 @@ def do_delayed_calls_at_end():
# ...
if _get_pending_calls() is not None:
raise Exception(
- "Nested update_at_end not supported - need to use contextlib.ContextDecorator"
+ "Nested update_at_end not supported - need to use"
+ " contextlib.ContextDecorator"
)
_local.pending_calls = collections.OrderedDict()
try:
diff --git a/backend/benefit/common/localized_iban_field.py b/backend/benefit/common/localized_iban_field.py
index ac5d11aee6..42c69624bb 100644
--- a/backend/benefit/common/localized_iban_field.py
+++ b/backend/benefit/common/localized_iban_field.py
@@ -21,8 +21,10 @@ class LocalizedIBANField(IBANField):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# switch the validator.
- # self.validators is a read-only property so it can't be assigned to. The property value is a list that
- # is mutable so we can replace the contents of the list with the slice assignment.
+ # self.validators is a read-only property so it can't be assigned to. The
+ # property value is a list that
+ # is mutable so we can replace the contents of the list with the slice
+ # assignment.
# Also, avoid list modification while iterating over it.
self.validators[:] = [
v for v in self.validators if not isinstance(v, IBANValidator)
diff --git a/backend/benefit/common/permissions.py b/backend/benefit/common/permissions.py
index 9ef0c7dbad..48653c0538 100644
--- a/backend/benefit/common/permissions.py
+++ b/backend/benefit/common/permissions.py
@@ -19,8 +19,8 @@ def has_permission(self, request, view):
if settings.NEXT_PUBLIC_MOCK_FLAG:
return True
if request.user and request.user.is_staff:
- # Handlers are never applicants. This restriction is needed in order to limit
- # handler's access to draft applications.
+ # Handlers are never applicants. This restriction is needed in order to
+ # limit handler's access to draft applications.
return False
return super().has_permission(request, view)
diff --git a/backend/benefit/common/tests/test_utils.py b/backend/benefit/common/tests/test_utils.py
index 4eec16a15d..5a22e60c96 100644
--- a/backend/benefit/common/tests/test_utils.py
+++ b/backend/benefit/common/tests/test_utils.py
@@ -98,10 +98,10 @@ def test_get_date_range_end_with_days360_combinations():
if os.getenv("DAYS_360_FULL_TEST") == "1":
# The nested loops test a huge number of combinations. Takes a long time to run,
# only run this while debugging.
- day_offsets = range(0, 100) # offset from 2022-01-01
- months_range = range(0, 1200)
+ day_offsets = range(100) # offset from 2022-01-01
+ months_range = range(1200)
else:
- print(
+ print( # noqa: T201
"DAYS_360_FULL_TEST not set, test only a few combinations to make sure the"
" test code doesn't rot"
)
@@ -109,7 +109,7 @@ def test_get_date_range_end_with_days360_combinations():
months_range = range(0, 1200, 100)
for initial_day_offset in day_offsets:
- print(f"initial_day_offset={initial_day_offset}")
+ print(f"initial_day_offset={initial_day_offset}") # noqa: T201
for months in [decimal.Decimal(m) / 100 for m in months_range]:
start_date = date(2022, 1, 1) + relativedelta(days=initial_day_offset)
end_date = get_date_range_end_with_days360(start_date, months)
@@ -138,7 +138,10 @@ def test_get_date_range_end_with_days360_combinations():
@pytest.mark.django_db
def test_hash_file():
# Create a dummy file with known content
- dummy_file_content = b"Ea ullamco aliqua amet ut deserunt. Excepteur aliqua non excepteur pariatur exercitation."
+ dummy_file_content = (
+ b"Ea ullamco aliqua amet ut deserunt. Excepteur aliqua non excepteur pariatur"
+ b" exercitation."
+ )
dummy_file = SimpleUploadedFile("dummy.txt", dummy_file_content)
expected_hash = hashlib.sha256(dummy_file_content).hexdigest()
diff --git a/backend/benefit/common/utils.py b/backend/benefit/common/utils.py
index c63b51e87c..8b2bc17aff 100644
--- a/backend/benefit/common/utils.py
+++ b/backend/benefit/common/utils.py
@@ -33,7 +33,7 @@ def update_object(obj: object, data: dict, limit_to_fields=None):
In the example above, the update_object function is used to update the 'name' and 'age' fields of a User object.
The function takes the User object, a data dictionary with field-value pairs, and updates the object accordingly.
The updated object is then saved.
- """
+ """ # noqa: E501
if not data:
return
for k, v in data.items():
@@ -71,7 +71,7 @@ def xgroup(iter, n=2, check_length=False) -> Iterator[Tuple]:
In the example above, the xgroup function is used to group elements from a list into tuples of size 3.
Each tuple is then printed, demonstrating how the function can be used to iterate over groups of elements.
- """
+ """ # noqa: E501
"""
adapted from: comp.lang.python Thu Jun 5 22:58:05 CEST 2003
@@ -113,10 +113,10 @@ def pairwise(iterable):
In the example above, the pairwise function takes a list of numbers and returns an iterator that generates pairs
of consecutive numbers. The resulting pairs are then printed one by one.
- """
+ """ # noqa: E501
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
- for unused in b:
+ for _ in b:
break
return zip(a, b)
@@ -141,7 +141,7 @@ def nested_setattr(obj: object, attr, val):
In the example above, the nested_setattr function is used to set the 'name' and 'age' attributes of the 'profile'
nested object within a User object. The function takes the User object, the attribute name or dotted path, and the
corresponding value, and sets the attributes accordingly.
- """
+ """ # noqa: E501
pre, _, post = attr.rpartition(".")
return setattr(nested_getattr(obj, pre) if pre else obj, post, val)
@@ -165,7 +165,7 @@ def __init__(self, name):
person = Person("John")
print(nested_getattr(person, "name")) # Output: "John"
- """
+ """ # noqa: E501
def _getattr(obj, attr):
return getattr(obj, attr, *args)
@@ -195,7 +195,7 @@ def to_decimal(numeric_value, decimal_places: Union[int, None] = None, allow_nul
In the example above, the to_decimal function converts the numeric value 3.14159 to a decimal with 2 decimal places
and assigns it to the variable dec. The resulting decimal value is then printed.
- """
+ """ # noqa: E501
if numeric_value is None and allow_null:
return None
value = decimal.Decimal(numeric_value)
@@ -240,7 +240,7 @@ def date_range_overlap(start_1: date, end_1: date, start_2: date, end_2: date):
In the example above, the date_range_overlap function calculates the overlap between two date ranges.
The first date range spans from January 1st to January 15th, and the second date range spans from
January 10th to January 20th. The function returns the number of overlapping days, which is 6.
- """
+ """ # noqa: E501
"""
Based on: https://stackoverflow.com/questions/9044084/efficient-date-range-overlap-calculation-in-python
"""
@@ -282,8 +282,8 @@ def days360(start_date: date, end_date: date):
Changes:
* Added unit tests
* forced method_eu to always be True.
- """
- METHOD_EU = True
+ """ # noqa: E501
+ method_eu = True
if not isinstance(start_date, date) or not isinstance(end_date, date):
raise ValueError("date object needed")
@@ -296,14 +296,14 @@ def days360(start_date: date, end_date: date):
end_year = end_date.year
if start_day == 31 or (
- METHOD_EU is False
+ method_eu is False
and start_month == 2
and (start_day == 29 or (start_day == 28 and start_date.is_leap_year is False))
):
start_day = 30
if end_day == 31:
- if METHOD_EU is False and start_day != 30:
+ if method_eu is False and start_day != 30:
end_day = 1
if end_month == 12:
@@ -340,7 +340,7 @@ class DurationMixin:
Depends on having start_date and end_date fields available in the object.
The duration is calculated according to the DAYS360 Excel function, as that
function was used by the application handlers in the application calculation Excel file.
- """
+ """ # noqa: E501
@property
def duration_in_months(self):
@@ -393,10 +393,11 @@ def get_date_range_end_with_days360(start_date: date, n_months: int):
In case 4, when two date ranges have the same duration_in_months, we want to return the
longest possible duration. This will resolve the ambiguity in the applicant's favor, as
this function is used to calculate the last valid end_date for the benefit.
- """
+ """ # noqa: E501
assert n_months >= 0
- # Using the usual calendar definition of months, so initially the start_date might be off by a few days
+ # Using the usual calendar definition of months, so initially the start_date might
+ # be off by a few days
full_months = int(n_months)
# Make the initial guess work for February cases, too
fractional_days = int(to_decimal((n_months - full_months) * 28, decimal_places=0))
@@ -406,25 +407,27 @@ def get_date_range_end_with_days360(start_date: date, n_months: int):
+ relativedelta(days=fractional_days - 3)
)
for _ in range(DATE_RANGE_MAX_ITERATIONS):
- # calculate how much we are off from the duration that was requested, and see if the
- # next day would be closer to the goal
+ # calculate how much we are off from the duration that was requested, and see if
+ # the next day would be closer to the goal
difference = abs(duration_in_months(start_date, end_date) - n_months)
next_day_difference = abs(
duration_in_months(start_date, end_date + relativedelta(days=1)) - n_months
)
if difference < next_day_difference:
- # [end_date, start_date] is the date range that most closely matches n_months.
- # in case difference == next_day_difference, we'll advance to the next day, in order to
- # make the resulting date range as long as possible.
+ # [end_date, start_date] is the date range that most closely matches
+ # n_months.
+ # in case difference == next_day_difference, we'll advance to the next day,
+ # in order to make the resulting date range as long as possible.
break
else:
end_date += relativedelta(days=1)
else:
- assert False, "This should be unreachable"
+ raise AssertionError("This should be unreachable")
if end_date < start_date:
- # We can't have date ranges where duration is less than one day, as the range is inclusive
- # (for benefit calculation this is OK, as a benefit with a zero duration doesn't exist)
+ # We can't have date ranges where duration is less than one day, as the range is
+ # inclusive (for benefit calculation this is OK, as a benefit with a zero
+ # duration doesn't exist)
return None
return end_date
diff --git a/backend/benefit/companies/api/v1/views.py b/backend/benefit/companies/api/v1/views.py
index b2321313a3..59e9e6f2d5 100644
--- a/backend/benefit/companies/api/v1/views.py
+++ b/backend/benefit/companies/api/v1/views.py
@@ -5,7 +5,7 @@
from django.http import HttpRequest
from django.utils.translation import gettext_lazy as __
from drf_spectacular.types import OpenApiTypes
-from drf_spectacular.utils import extend_schema, OpenApiParameter
+from drf_spectacular.utils import OpenApiParameter, extend_schema
from requests.exceptions import HTTPError
from rest_framework import status
from rest_framework.response import Response
@@ -35,7 +35,8 @@ class GetUsersOrganizationView(APIView):
def ytj_api_error(self):
return Response(
__(
- "YTJ API is under heavy load or no company found with the given business id"
+ "YTJ API is under heavy load or no company found with the given"
+ " business id"
),
status.HTTP_404_NOT_FOUND,
)
@@ -107,9 +108,8 @@ def get(self, request: HttpRequest, format: str = "") -> Response:
return self.ytj_api_error
except (ValueError, KeyError) as err:
LOGGER.debug(
- "Could not handle the response from Palveluväylä and YRTTI API, error: {}".format(
- err
- )
+ "Could not handle the response from Palveluväylä and YRTTI API,"
+ " error: {}".format(err)
)
return Response(
__("Could not handle the response from Palveluväylä and YRTTI API"),
diff --git a/backend/benefit/companies/migrations/0001_initial.py b/backend/benefit/companies/migrations/0001_initial.py
index 9743352ff1..d088c7b0ba 100644
--- a/backend/benefit/companies/migrations/0001_initial.py
+++ b/backend/benefit/companies/migrations/0001_initial.py
@@ -7,7 +7,6 @@
class Migration(migrations.Migration):
-
initial = True
dependencies = []
diff --git a/backend/benefit/companies/migrations/0002_unique_company_business_id.py b/backend/benefit/companies/migrations/0002_unique_company_business_id.py
index f4966e0d0c..a149c6bcf2 100644
--- a/backend/benefit/companies/migrations/0002_unique_company_business_id.py
+++ b/backend/benefit/companies/migrations/0002_unique_company_business_id.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0001_initial"),
]
diff --git a/backend/benefit/companies/migrations/0003_company_form_code.py b/backend/benefit/companies/migrations/0003_company_form_code.py
index 8bef851593..3cf8130332 100644
--- a/backend/benefit/companies/migrations/0003_company_form_code.py
+++ b/backend/benefit/companies/migrations/0003_company_form_code.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0002_unique_company_business_id"),
]
diff --git a/backend/benefit/companies/migrations/0004_localized_iban_field.py b/backend/benefit/companies/migrations/0004_localized_iban_field.py
index 424e5c1cc6..60d470a893 100644
--- a/backend/benefit/companies/migrations/0004_localized_iban_field.py
+++ b/backend/benefit/companies/migrations/0004_localized_iban_field.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2.4 on 2022-03-21 07:43
-import common.localized_iban_field
from django.db import migrations
+import common.localized_iban_field
+
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0003_company_form_code"),
]
diff --git a/backend/benefit/companies/migrations/0005_alter_company_bank_account_number.py b/backend/benefit/companies/migrations/0005_alter_company_bank_account_number.py
index 021604b66d..bcb9ea22b4 100644
--- a/backend/benefit/companies/migrations/0005_alter_company_bank_account_number.py
+++ b/backend/benefit/companies/migrations/0005_alter_company_bank_account_number.py
@@ -1,19 +1,25 @@
# Generated by Django 4.2.11 on 2024-09-26 12:09
-import common.localized_iban_field
from django.db import migrations
+import common.localized_iban_field
+
class Migration(migrations.Migration):
-
dependencies = [
- ('companies', '0004_localized_iban_field'),
+ ("companies", "0004_localized_iban_field"),
]
operations = [
migrations.AlterField(
- model_name='company',
- name='bank_account_number',
- field=common.localized_iban_field.LocalizedIBANField(blank=True, include_countries=('FI',), max_length=34, use_nordea_extensions=False, verbose_name='bank account number'),
+ model_name="company",
+ name="bank_account_number",
+ field=common.localized_iban_field.LocalizedIBANField(
+ blank=True,
+ include_countries=("FI",),
+ max_length=34,
+ use_nordea_extensions=False,
+ verbose_name="bank account number",
+ ),
),
]
diff --git a/backend/benefit/companies/tests/data/company_data.py b/backend/benefit/companies/tests/data/company_data.py
index a38881b655..c45bc74ad7 100644
--- a/backend/benefit/companies/tests/data/company_data.py
+++ b/backend/benefit/companies/tests/data/company_data.py
@@ -74,63 +74,81 @@ def get_dummy_company_data():
"registrationDate": "2021-01-01",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/55730X",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/55730X"
+ ),
},
{
"recordNumber": "2020/290401",
"registrationDate": "2020-06-15",
"typeOfRegistration": "M",
"entryCodes": [""],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/290401",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/290401"
+ ),
},
{
"recordNumber": "2019/53986T",
"registrationDate": "2019-12-05",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/53986T",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/53986T"
+ ),
},
{
"recordNumber": "2019/250695",
"registrationDate": "2019-07-09",
"typeOfRegistration": "M",
"entryCodes": ["HAL"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/250695",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/250695"
+ ),
},
{
"recordNumber": "2018/50210V",
"registrationDate": "2018-10-19",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2018/50210V",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2018/50210V"
+ ),
},
{
"recordNumber": "2017/46683V",
"registrationDate": "2017-10-21",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2017/46683V",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2017/46683V"
+ ),
},
{
"recordNumber": "2016/86280V",
"registrationDate": "2016-11-03",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2016/86280V",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2016/86280V"
+ ),
},
{
"recordNumber": "2015/739492",
"registrationDate": "2015-11-04",
"typeOfRegistration": "M",
"entryCodes": ["TILTAR"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/739492",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/739492"
+ ),
},
{
"recordNumber": "2015/84509U",
"registrationDate": "2015-10-08",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/84509U",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/84509U"
+ ),
},
],
"registeredOffices": [
@@ -636,7 +654,9 @@ def get_dummy_company_data():
"endDate": None,
"statusDate": "2008-07-21",
"language": "SE",
- "description": "För överlåtelse av nyttjanderätten till en fastighet",
+ "description": (
+ "För överlåtelse av nyttjanderätten till en fastighet"
+ ),
},
{
"authority": 1,
@@ -646,7 +666,10 @@ def get_dummy_company_data():
"endDate": None,
"statusDate": "2008-07-21",
"language": "EN",
- "description": "VAT-obliged for the transfer of rights to use immovable property",
+ "description": (
+ "VAT-obliged for the transfer of rights to use immovable"
+ " property"
+ ),
},
{
"authority": 1,
@@ -754,9 +777,17 @@ def get_dummy_company_data():
"Address": [
{
"AddressTypeCode": "YRPO",
- "FormattedAddressFI": "Lamberg Matti Olavi\nKatajakalliontie 16\n01120 Västerskog\nSuomi",
- "FormattedAddressEN": "Lamberg Matti Olavi\nKatajakalliontie 16\n01120 Västerskog\nFinland",
- "FormattedAddressSE": "Lamberg Matti Olavi\nKatajakalliontie 16\n01120 Västerskog\nFinland",
+ "FormattedAddressFI": (
+ "Lamberg Matti Olavi\nKatajakalliontie 16\n01120 Västerskog\nSuomi"
+ ),
+ "FormattedAddressEN": (
+ "Lamberg Matti Olavi\nKatajakalliontie 16\n01120"
+ " Västerskog\nFinland"
+ ),
+ "FormattedAddressSE": (
+ "Lamberg Matti Olavi\nKatajakalliontie 16\n01120"
+ " Västerskog\nFinland"
+ ),
"CoAddress": None,
"StreetName": "Lamberg Matti Olavi\nKatajakalliontie 16",
"HouseNumber": None,
@@ -997,7 +1028,9 @@ def get_dummy_company_data():
{
"Language": "sv",
"Type": "Default",
- "Description": "Specialiserad butikshandel med hushållsartiklar",
+ "Description": (
+ "Specialiserad butikshandel med hushållsartiklar"
+ ),
},
{
"Language": "en",
@@ -1339,18 +1372,25 @@ def get_dummy_company_data():
{
"Language": "fi",
"Type": "Default",
- "Description": "Kiinteistön käyttöoikeuden luovuttamisesta",
+ "Description": (
+ "Kiinteistön käyttöoikeuden luovuttamisesta"
+ ),
},
{
"Language": "sv",
"Type": "Default",
- "Description": "För överlåtelse av nyttjanderätten till en fastighet",
+ "Description": (
+ "För överlåtelse av nyttjanderätten till en"
+ " fastighet"
+ ),
},
{
"Language": "en",
"Type": "Default",
- "Description": "VAT-obliged for the transfer of rights to"
- " use immovable property",
+ "Description": (
+ "VAT-obliged for the transfer of rights to"
+ " use immovable property"
+ ),
},
]
},
@@ -1416,17 +1456,23 @@ def get_dummy_company_data():
{
"Language": "fi",
"Type": "Default",
- "Description": "Liiketoiminnasta arvonlisäverovelvollinen",
+ "Description": (
+ "Liiketoiminnasta arvonlisäverovelvollinen"
+ ),
},
{
"Language": "sv",
"Type": "Default",
- "Description": "Momsskyldig för rörelseverksamhet",
+ "Description": (
+ "Momsskyldig för rörelseverksamhet"
+ ),
},
{
"Language": "en",
"Type": "Default",
- "Description": "VAT-liable for business activity",
+ "Description": (
+ "VAT-liable for business activity"
+ ),
},
]
},
@@ -1601,7 +1647,9 @@ def get_dummy_company_data():
{
"Language": "en",
"Type": "Default",
- "Description": "Finnish Patent and Registration Office",
+ "Description": (
+ "Finnish Patent and Registration Office"
+ ),
},
]
},
@@ -1702,7 +1750,9 @@ def get_dummy_company_data():
{
"Language": "sv",
"Type": "Default",
- "Description": "Skatteförvaltningens basuppgifter",
+ "Description": (
+ "Skatteförvaltningens basuppgifter"
+ ),
},
{
"Language": "en",
@@ -1800,18 +1850,25 @@ def get_dummy_company_data():
{
"Language": "fi",
"Type": "Default",
- "Description": "Kiinteistön käyttöoikeuden luovuttamisesta",
+ "Description": (
+ "Kiinteistön käyttöoikeuden luovuttamisesta"
+ ),
},
{
"Language": "sv",
"Type": "Default",
- "Description": "För överlåtelse av nyttjanderätten till en fastighet",
+ "Description": (
+ "För överlåtelse av nyttjanderätten till en"
+ " fastighet"
+ ),
},
{
"Language": "en",
"Type": "Default",
- "Description": "VAT-obliged for the transfer of rights to use"
- " immovable property",
+ "Description": (
+ "VAT-obliged for the transfer of rights to"
+ " use immovable property"
+ ),
},
]
},
@@ -1877,17 +1934,23 @@ def get_dummy_company_data():
{
"Language": "fi",
"Type": "Default",
- "Description": "Liiketoiminnasta arvonlisäverovelvollinen",
+ "Description": (
+ "Liiketoiminnasta arvonlisäverovelvollinen"
+ ),
},
{
"Language": "sv",
"Type": "Default",
- "Description": "Momsskyldig för rörelseverksamhet",
+ "Description": (
+ "Momsskyldig för rörelseverksamhet"
+ ),
},
{
"Language": "en",
"Type": "Default",
- "Description": "VAT-liable for business activity",
+ "Description": (
+ "VAT-liable for business activity"
+ ),
},
]
},
@@ -2062,7 +2125,9 @@ def get_dummy_company_data():
{
"Language": "en",
"Type": "Default",
- "Description": "Finnish Patent and Registration Office",
+ "Description": (
+ "Finnish Patent and Registration Office"
+ ),
},
]
},
@@ -2163,7 +2228,9 @@ def get_dummy_company_data():
{
"Language": "sv",
"Type": "Default",
- "Description": "Skatteförvaltningens basuppgifter",
+ "Description": (
+ "Skatteförvaltningens basuppgifter"
+ ),
},
{
"Language": "en",
diff --git a/backend/benefit/docker-entrypoint.sh b/backend/benefit/docker-entrypoint.sh
index e00dfbffca..d74786f588 100755
--- a/backend/benefit/docker-entrypoint.sh
+++ b/backend/benefit/docker-entrypoint.sh
@@ -3,7 +3,7 @@
set -e
# Wait for the database
-if [ -z "$SKIP_DATABASE_CHECK" -o "$SKIP_DATABASE_CHECK" = "0" ]; then
+if [ -z "$SKIP_DATABASE_CHECK" ] || [ "$SKIP_DATABASE_CHECK" = "0" ]; then
until nc -z -v -w30 "${DATABASE_HOST}" "${DATABASE_PORT-5432}"
do
echo "Waiting for postgres database connection..."
@@ -54,7 +54,7 @@ if [[ "$CREATE_SUPERUSER" = "1" ]]; then
fi
# Start server
-if [[ ! -z "$@" ]]; then
+if [ "$#" -gt 0 ]; then
"$@"
elif [[ "$DEV_SERVER" = "1" ]]; then
python -Wd ./manage.py runserver 0.0.0.0:8000
diff --git a/backend/benefit/helsinkibenefit/settings.py b/backend/benefit/helsinkibenefit/settings.py
index 5192edf905..e5e1d46b8d 100644
--- a/backend/benefit/helsinkibenefit/settings.py
+++ b/backend/benefit/helsinkibenefit/settings.py
@@ -53,14 +53,16 @@
CSRF_COOKIE_NAME=(str, "yjdhcsrftoken"),
YTJ_BASE_URL=(str, "https://avoindata.prh.fi"),
YTJ_TIMEOUT=(int, 30),
- # Source: YTJ-rajapinnan koodiston kuvaus, available at https://liityntakatalogi.suomi.fi/dataset/xroadytj-services
+ # Source: YTJ-rajapinnan koodiston kuvaus, available at
+ # https://liityntakatalogi.suomi.fi/dataset/xroadytj-services
# file: suomi_fi_palveluvayla_ytj_rajapinta_koodistot_v1_4.xlsx
ASSOCIATION_FORM_CODES=(
str,
"18,21,25,29,31,32,35,38,39,4,44,45,46,47,50,58,6,71,9,90,94999",
),
NEXT_PUBLIC_MOCK_FLAG=(bool, False),
- # Random 32 bytes AES key, for testing purpose only, DO NOT use the same value in staging/production
+ # Random 32 bytes AES key, for testing purpose only, DO NOT use the same value in
+ # staging/production
# Always override this value from env variables
ENCRYPTION_KEY=(
str,
@@ -243,7 +245,8 @@
("sv", _("Swedish")),
)
-# Call gettext on languages so that "makemessages" command can find them when used dynamically in templates
+# Call gettext on languages so that "makemessages" command can find them when used
+# dynamically in templates
_("fi")
_("en")
_("sv")
@@ -379,11 +382,13 @@
"ENUM_NAME_OVERRIDES": {
"AvailableBenefitTypesEnum": "applications.enums.BenefitType",
},
- "DESCRIPTION": """REST API for Helsinki Benefit application management
+ "DESCRIPTION": (
+ """REST API for Helsinki Benefit application management
# Authentication methods
-""",
+"""
+ ),
"VERSION": "0.0.1",
"EXTERNAL_DOCS": {
"description": "Helsinki benefit / YJDH repository in GitHub",
@@ -457,7 +462,8 @@
# Language selection is done with accept-language header in this project
# UPDATE: 2023-08-07
-# Didn't seem to be working correctly with EAUTH forwards and landing back to callback url
+# Didn't seem to be working correctly with EAUTH forwards and landing back to callback
+# url
# Changing this to False as nextjs's language autodetect seems to be at set to false too
OIDC_DISABLE_LANGUAGE_COOKIE = False
diff --git a/backend/benefit/manage.py b/backend/benefit/manage.py
index 101a1cef90..07185637d0 100755
--- a/backend/benefit/manage.py
+++ b/backend/benefit/manage.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
+
import os
import sys
diff --git a/backend/benefit/messages/automatic_messages.py b/backend/benefit/messages/automatic_messages.py
index 7ac318529e..fb4b128d83 100644
--- a/backend/benefit/messages/automatic_messages.py
+++ b/backend/benefit/messages/automatic_messages.py
@@ -16,13 +16,15 @@
LOGGER = logging.getLogger(__name__)
APPLICATION_REOPENED_MESSAGE = _(
- "Your application has been opened for editing. Please make the corrections and send application again by "
- "{additional_information_needed_by}, otherwise the application cannot be processed."
+ "Your application has been opened for editing. Please make the corrections and send"
+ " application again by {additional_information_needed_by}, otherwise the"
+ " application cannot be processed."
)
def get_default_email_notification_subject():
- # force evaluation of lazy string so that the messages in local memory queue remain translated
+ # force evaluation of lazy string so that the messages in local memory queue remain
+ # translated
# correctly during unit tests
return str(
_("You have received a new message regarding your Helsinki benefit application")
@@ -37,8 +39,10 @@ def _message_notification_email_body(application):
if submitted_at := application.submitted_at:
submitted_at_fmt = submitted_at.strftime("%d.%m.%Y")
else:
- # this should never happen in practice, as the applicants are not allowed to send messages
- # while application remains draft, and the handlers don't see non-submitted applications
+ # this should never happen in practice, as the applicants are not allowed to
+ # send messages
+ # while application remains draft, and the handlers don't see non-submitted
+ # applications
# at all.
submitted_at_fmt = "n/a"
return str(
@@ -88,19 +92,22 @@ def send_email_to_applicant(
if not application.company_contact_person_email:
# company_contact_person_email is a required field for submitted applications
LOGGER.warning(
- f"Application {application} does not have company_contact_person_email - unexpected"
+ f"Application {application} does not have company_contact_person_email -"
+ " unexpected"
)
return 0
with translation.override(application.applicant_language):
try:
return send_mail(
- subject=subject
- if subject
- else get_default_email_notification_subject(),
- message=text_message
- if text_message
- else _message_notification_email_body(application),
+ subject=(
+ subject if subject else get_default_email_notification_subject()
+ ),
+ message=(
+ text_message
+ if text_message
+ else _message_notification_email_body(application)
+ ),
html_message=html_message or None,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[application.company_contact_person_email],
@@ -111,10 +118,8 @@ def send_email_to_applicant(
if "@" in application.company_contact_person_email:
email_domain = application.company_contact_person_email.split("@")[1]
capture_message(
- (
- f"SMTPException while sending email to xxx@{email_domain}, "
- f"application number {application.application_number}"
- ),
+ f"SMTPException while sending email to xxx@{email_domain}, "
+ f"application number {application.application_number}",
"error",
)
return 0
@@ -127,7 +132,7 @@ def send_application_reopened_message(
:param user: The handler who is setting the application to ADDITIONAL_INFORMATION_REQUESTED status
:param application: The application being reopened
:param additional_information_needed_by: The date by which the applicant must provide the additional information
- """
+ """ # noqa: E501
formatted_info_needed_by = additional_information_needed_by.strftime("%d.%m.%Y")
diff --git a/backend/benefit/messages/migrations/0001_initial.py b/backend/benefit/messages/migrations/0001_initial.py
index 6df4731085..0062a7f6a0 100644
--- a/backend/benefit/messages/migrations/0001_initial.py
+++ b/backend/benefit/messages/migrations/0001_initial.py
@@ -8,7 +8,6 @@
class Migration(migrations.Migration):
-
initial = True
dependencies = [
diff --git a/backend/benefit/messages/migrations/0002_alter_message_options.py b/backend/benefit/messages/migrations/0002_alter_message_options.py
index 736b6da12a..77911d3dd6 100644
--- a/backend/benefit/messages/migrations/0002_alter_message_options.py
+++ b/backend/benefit/messages/migrations/0002_alter_message_options.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("bf_messages", "0001_initial"),
]
diff --git a/backend/benefit/messages/migrations/0003_add_seen_flag.py b/backend/benefit/messages/migrations/0003_add_seen_flag.py
index 3c5786998f..be607144a8 100644
--- a/backend/benefit/messages/migrations/0003_add_seen_flag.py
+++ b/backend/benefit/messages/migrations/0003_add_seen_flag.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("bf_messages", "0002_alter_message_options"),
]
diff --git a/backend/benefit/messages/serializers.py b/backend/benefit/messages/serializers.py
index 469096e17b..ef3f23806b 100644
--- a/backend/benefit/messages/serializers.py
+++ b/backend/benefit/messages/serializers.py
@@ -26,7 +26,8 @@ class Meta:
"seen_by_applicant",
]
- # An applicant is only allowed to send a message if application is in one of these statuses
+ # An applicant is only allowed to send a message if application is in one of these
+ # statuses
APPLICANT_MESSAGE_ALLOWED_STATUSES = [
ApplicationStatus.RECEIVED,
ApplicationStatus.HANDLING,
diff --git a/backend/benefit/messages/tests/test_api.py b/backend/benefit/messages/tests/test_api.py
index 5c0a95f429..adf78bc03c 100644
--- a/backend/benefit/messages/tests/test_api.py
+++ b/backend/benefit/messages/tests/test_api.py
@@ -329,14 +329,15 @@ def test_create_message(
assert mailoutbox[0].from_email == settings.DEFAULT_FROM_EMAIL
assert "Olet saanut uuden viestin" in mailoutbox[0].subject
- # Parse email to an object and assert that it contains the correct text content
+ # Parse email to an object and assert that it contains the correct text
+ # content
email_parts = email.message_from_string(mailoutbox[0].body)
for part in email_parts.walk():
if part.get_content_type() == "text/plain":
- print(part.get_payload())
+ print(part.get_payload()) # noqa: T201
assert (
- "Olet saanut uuden viestin Helsinki-lisä -hakemukseen liittyen. Voit lukea viestin"
- in part.get_payload()
+ "Olet saanut uuden viestin Helsinki-lisä -hakemukseen"
+ " liittyen. Voit lukea viestin" in part.get_payload()
)
assert result.status_code == 201
@@ -462,8 +463,8 @@ def test_delete_message_unauthenticated(
@pytest.mark.parametrize(
"view_name",
[
- ("applicant-message-detail"),
- ("handler-message-detail"),
+ "applicant-message-detail",
+ "handler-message-detail",
],
)
def test_delete_message_unauthorized(
diff --git a/backend/benefit/pyproject.toml b/backend/benefit/pyproject.toml
index 319ad03f1d..e9faee147f 100644
--- a/backend/benefit/pyproject.toml
+++ b/backend/benefit/pyproject.toml
@@ -1,8 +1,25 @@
-[tool.black]
-extend-exclude = '''
-(
- .pytest_cache
- | var/media
- | migrations
-)
-'''
+[tool.ruff]
+target-version = "py39"
+
+[tool.ruff.lint]
+select = [
+ # Pyflakes
+ "F",
+ # pycodestyle
+ "E",
+ "W",
+ # isort
+ "I",
+ # pep8-naming
+ "N",
+ # flake8-bugbear without opinionated rules
+ "B0",
+ # flake8-pie
+ "PIE",
+ # flake8-print
+ "T20",
+]
+extend-per-file-ignores = { "*/migrations/*" = ["E501"], "*/tests/*" = ["E501"] }
+
+[tool.ruff.lint.isort]
+known-first-party = ["shared"]
diff --git a/backend/benefit/requirements-dev.in b/backend/benefit/requirements-dev.in
index b6e894a517..5cb45665b8 100644
--- a/backend/benefit/requirements-dev.in
+++ b/backend/benefit/requirements-dev.in
@@ -1,7 +1,4 @@
-black
-flake8
ipython
-isort
langdetect
pip-tools==7.4.1
pytest
@@ -10,4 +7,3 @@ pytest-django
pytest-freezegun
requests-mock
werkzeug
-pre-commit
diff --git a/backend/benefit/requirements-dev.txt b/backend/benefit/requirements-dev.txt
index 19d2de4888..c980394c91 100644
--- a/backend/benefit/requirements-dev.txt
+++ b/backend/benefit/requirements-dev.txt
@@ -10,38 +10,24 @@ attrs==22.2.0
# via pytest
backcall==0.2.0
# via ipython
-black==23.1.0
- # via -r requirements-dev.in
build==1.2.1
# via pip-tools
certifi==2022.12.7
# via requests
-cfgv==3.3.1
- # via pre-commit
charset-normalizer==3.0.1
# via requests
click==8.1.3
- # via
- # black
- # pip-tools
+ # via pip-tools
coverage[toml]==7.2.0
# via pytest-cov
decorator==5.1.1
# via ipython
-distlib==0.3.6
- # via virtualenv
exceptiongroup==1.1.0
# via pytest
executing==1.2.0
# via stack-data
-filelock==3.9.0
- # via virtualenv
-flake8==6.0.0
- # via -r requirements-dev.in
freezegun==1.2.2
# via pytest-freezegun
-identify==2.5.18
- # via pre-commit
idna==3.4
# via requests
importlib-metadata==8.0.0
@@ -50,8 +36,6 @@ iniconfig==2.0.0
# via pytest
ipython==8.10.0
# via -r requirements-dev.in
-isort==5.12.0
- # via -r requirements-dev.in
jedi==0.18.2
# via ipython
langdetect==1.0.9
@@ -60,45 +44,26 @@ markupsafe==2.1.2
# via werkzeug
matplotlib-inline==0.1.6
# via ipython
-mccabe==0.7.0
- # via flake8
-mypy-extensions==1.0.0
- # via black
-nodeenv==1.7.0
- # via pre-commit
packaging==23.0
# via
- # black
# build
# pytest
parso==0.8.3
# via jedi
-pathspec==0.11.0
- # via black
pexpect==4.8.0
# via ipython
pickleshare==0.7.5
# via ipython
pip-tools==7.4.1
# via -r requirements-dev.in
-platformdirs==3.0.0
- # via
- # black
- # virtualenv
pluggy==1.0.0
# via pytest
-pre-commit==3.1.0
- # via -r requirements-dev.in
prompt-toolkit==3.0.37
# via ipython
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.2
# via stack-data
-pycodestyle==2.10.0
- # via flake8
-pyflakes==3.0.1
- # via flake8
pygments==2.14.0
# via ipython
pyproject-hooks==1.0.0
@@ -119,8 +84,6 @@ pytest-freezegun==0.4.2
# via -r requirements-dev.in
python-dateutil==2.8.2
# via freezegun
-pyyaml==6.0
- # via pre-commit
requests==2.28.2
# via requests-mock
requests-mock==1.10.0
@@ -135,7 +98,6 @@ stack-data==0.6.2
# via ipython
tomli==2.0.1
# via
- # black
# build
# coverage
# pip-tools
@@ -145,12 +107,8 @@ traitlets==5.9.0
# via
# ipython
# matplotlib-inline
-typing-extensions==4.5.0
- # via black
urllib3==1.26.14
# via requests
-virtualenv==20.19.0
- # via pre-commit
wcwidth==0.2.6
# via prompt-toolkit
werkzeug==2.2.3
diff --git a/backend/benefit/setup.cfg b/backend/benefit/setup.cfg
index 00fb1f2e7b..1a438a55de 100644
--- a/backend/benefit/setup.cfg
+++ b/backend/benefit/setup.cfg
@@ -1,23 +1,3 @@
-[pep8]
-max-line-length = 120
-exclude =
- *migrations*
- .pytest_cache
- var/media
- .eggs
- *.egg-info
-ignore = E309
-
-[flake8]
-exclude = migrations,snapshots,.pytest_cache,var/media,.eggs,*.egg-info
-max-line-length = 120
-max-complexity = 10
-# E203 and W503 are disabled and W504 enabled for compatibility with Black.
-# For details see "Why are Flake8's E203 and W503 violated?" in Black FAQ at
-# https://black.readthedocs.io/en/stable/faq.html
-ignore = E203, W503
-extend-select = W504
-
[tool:pytest]
DJANGO_SETTINGS_MODULE = helsinkibenefit.settings
norecursedirs = node_modules .git venv* .pytest_cache var/media .eggs *.egg-info
@@ -26,19 +6,3 @@ doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ALLOW_UNICODE
[coverage:run]
branch = True
omit = *migrations*,*site-packages*,*venv*,*tests*
-
-[isort]
-profile=black
-default_section = THIRDPARTY
-atomic=true
-combine_as_imports=true
-indent=4
-length_sort=false
-multi_line_output=3
-order_by_type=false
-skip=migrations,venv,.pytest_cache,var/media,.eggs,*.egg-info
-include_trailing_comma = True
-force_grid_wrap = 0
-use_parentheses = True
-line_length = 88
-known_first_party = shared
diff --git a/backend/benefit/terms/api/v1/serializers.py b/backend/benefit/terms/api/v1/serializers.py
index 74adcbfc52..45d9de1591 100644
--- a/backend/benefit/terms/api/v1/serializers.py
+++ b/backend/benefit/terms/api/v1/serializers.py
@@ -74,7 +74,7 @@ class ApproveTermsSerializer(serializers.ModelSerializer):
The Terms ID and ApplicantConsent IDs are explicitly sent in the request as an extra
precaution, to ensure that the effective terms were shown and thta the user clicked all the required checkboxes.
- """
+ """ # noqa: E501
selected_applicant_consents = serializers.PrimaryKeyRelatedField(
many=True, queryset=ApplicantConsent.objects.all()
@@ -83,10 +83,10 @@ class ApproveTermsSerializer(serializers.ModelSerializer):
def validate(self, data):
"""
Currently, all the applicant consents must be selected, none of them are optional.
- """
+ """ # noqa: E501
if data["terms"] != Terms.objects.get_terms_in_effect(data["terms"].terms_type):
- # Extra validation step to ensure that the terms that have been shown to the user are actually the
- # terms that are currently in effect.
+ # Extra validation step to ensure that the terms that have been shown to the
+ # user are actually the terms that are currently in effect.
raise serializers.ValidationError(
{"terms": _("Only the terms currently in effect can be approved")}
)
@@ -97,7 +97,8 @@ def validate(self, data):
raise serializers.ValidationError(
{
"selected_applicant_consents": _(
- "User must explicitly select all the applicant consents required by the terms"
+ "User must explicitly select all the applicant consents"
+ " required by the terms"
)
}
)
diff --git a/backend/benefit/terms/enums.py b/backend/benefit/terms/enums.py
index 8a4b44fc85..fbcfa41a75 100644
--- a/backend/benefit/terms/enums.py
+++ b/backend/benefit/terms/enums.py
@@ -4,9 +4,11 @@
class TermsType(models.TextChoices):
TERMS_OF_SERVICE = "terms_of_service", _("Terms of service - shown at login")
- APPLICANT_TERMS = "applicant_terms", _(
- "Terms of application - show at application submit"
+ APPLICANT_TERMS = (
+ "applicant_terms",
+ _("Terms of application - show at application submit"),
)
- HANDLER_TERMS = "handler_terms", _(
- "Terms of application for handler - show at application submit for handler"
+ HANDLER_TERMS = (
+ "handler_terms",
+ _("Terms of application for handler - show at application submit for handler"),
)
diff --git a/backend/benefit/terms/migrations/0001_initial.py b/backend/benefit/terms/migrations/0001_initial.py
index 82d852aefc..ea6890dab3 100644
--- a/backend/benefit/terms/migrations/0001_initial.py
+++ b/backend/benefit/terms/migrations/0001_initial.py
@@ -1,13 +1,13 @@
# Generated by Django 3.2.4 on 2021-09-14 04:28
+import uuid
+
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
-import uuid
class Migration(migrations.Migration):
-
initial = True
dependencies = [
diff --git a/backend/benefit/terms/migrations/0002_termsofserviceapproval.py b/backend/benefit/terms/migrations/0002_termsofserviceapproval.py
index 35f9c168df..c11d09b7e5 100644
--- a/backend/benefit/terms/migrations/0002_termsofserviceapproval.py
+++ b/backend/benefit/terms/migrations/0002_termsofserviceapproval.py
@@ -1,13 +1,13 @@
# Generated by Django 3.2.4 on 2021-09-17 11:12
+import uuid
+
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
-import uuid
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("companies", "0001_initial"),
diff --git a/backend/benefit/terms/migrations/0003_add_applicantconsent_ordering.py b/backend/benefit/terms/migrations/0003_add_applicantconsent_ordering.py
index 4a30874f1b..4ff0f90c35 100644
--- a/backend/benefit/terms/migrations/0003_add_applicantconsent_ordering.py
+++ b/backend/benefit/terms/migrations/0003_add_applicantconsent_ordering.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("terms", "0002_termsofserviceapproval"),
]
diff --git a/backend/benefit/terms/migrations/0004_alter_terms_terms_type.py b/backend/benefit/terms/migrations/0004_alter_terms_terms_type.py
index 1b1012f4dd..2f73a0147a 100644
--- a/backend/benefit/terms/migrations/0004_alter_terms_terms_type.py
+++ b/backend/benefit/terms/migrations/0004_alter_terms_terms_type.py
@@ -4,15 +4,32 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('terms', '0003_add_applicantconsent_ordering'),
+ ("terms", "0003_add_applicantconsent_ordering"),
]
operations = [
migrations.AlterField(
- model_name='terms',
- name='terms_type',
- field=models.CharField(choices=[('terms_of_service', 'Terms of service - shown at login'), ('applicant_terms', 'Terms of application - show at application submit'), ('handler_terms', 'Terms of application for handler - show at application submit for handler')], default='applicant_terms', max_length=64, verbose_name='type of terms'),
+ model_name="terms",
+ name="terms_type",
+ field=models.CharField(
+ choices=[
+ ("terms_of_service", "Terms of service - shown at login"),
+ (
+ "applicant_terms",
+ "Terms of application - show at application submit",
+ ),
+ (
+ "handler_terms",
+ (
+ "Terms of application for handler - show at application"
+ " submit for handler"
+ ),
+ ),
+ ],
+ default="applicant_terms",
+ max_length=64,
+ verbose_name="type of terms",
+ ),
),
]
diff --git a/backend/benefit/terms/migrations/0006_alter_pdf_terms_not_required.py b/backend/benefit/terms/migrations/0006_alter_pdf_terms_not_required.py
index 766e98c503..50973509b5 100644
--- a/backend/benefit/terms/migrations/0006_alter_pdf_terms_not_required.py
+++ b/backend/benefit/terms/migrations/0006_alter_pdf_terms_not_required.py
@@ -4,25 +4,30 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('terms', '0005_add_support_for_md_terms'),
+ ("terms", "0005_add_support_for_md_terms"),
]
operations = [
migrations.AlterField(
- model_name='terms',
- name='terms_pdf_en',
- field=models.FileField(blank=True, upload_to='', verbose_name='english terms (pdf file)'),
+ model_name="terms",
+ name="terms_pdf_en",
+ field=models.FileField(
+ blank=True, upload_to="", verbose_name="english terms (pdf file)"
+ ),
),
migrations.AlterField(
- model_name='terms',
- name='terms_pdf_fi',
- field=models.FileField(blank=True, upload_to='', verbose_name='finnish terms (pdf file)'),
+ model_name="terms",
+ name="terms_pdf_fi",
+ field=models.FileField(
+ blank=True, upload_to="", verbose_name="finnish terms (pdf file)"
+ ),
),
migrations.AlterField(
- model_name='terms',
- name='terms_pdf_sv',
- field=models.FileField(blank=True, upload_to='', verbose_name='swedish terms (pdf file)'),
+ model_name="terms",
+ name="terms_pdf_sv",
+ field=models.FileField(
+ blank=True, upload_to="", verbose_name="swedish terms (pdf file)"
+ ),
),
]
diff --git a/backend/benefit/terms/migrations/0007_alter_change_terms_md_defaults_20231201_1049.py b/backend/benefit/terms/migrations/0007_alter_change_terms_md_defaults_20231201_1049.py
index d6d3473480..8ef0386b75 100644
--- a/backend/benefit/terms/migrations/0007_alter_change_terms_md_defaults_20231201_1049.py
+++ b/backend/benefit/terms/migrations/0007_alter_change_terms_md_defaults_20231201_1049.py
@@ -4,25 +4,30 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('terms', '0006_alter_pdf_terms_not_required'),
+ ("terms", "0006_alter_pdf_terms_not_required"),
]
operations = [
migrations.AlterField(
- model_name='terms',
- name='terms_md_en',
- field=models.TextField(blank=True, default='', verbose_name='English terms (md)'),
+ model_name="terms",
+ name="terms_md_en",
+ field=models.TextField(
+ blank=True, default="", verbose_name="English terms (md)"
+ ),
),
migrations.AlterField(
- model_name='terms',
- name='terms_md_fi',
- field=models.TextField(blank=True, default='', verbose_name='Finnish terms (md)'),
+ model_name="terms",
+ name="terms_md_fi",
+ field=models.TextField(
+ blank=True, default="", verbose_name="Finnish terms (md)"
+ ),
),
migrations.AlterField(
- model_name='terms',
- name='terms_md_sv',
- field=models.TextField(blank=True, default='', verbose_name='Swedish terms (md)'),
+ model_name="terms",
+ name="terms_md_sv",
+ field=models.TextField(
+ blank=True, default="", verbose_name="Swedish terms (md)"
+ ),
),
]
diff --git a/backend/benefit/terms/models.py b/backend/benefit/terms/models.py
index 2f457409bb..36f04c0f17 100644
--- a/backend/benefit/terms/models.py
+++ b/backend/benefit/terms/models.py
@@ -47,7 +47,7 @@ class Terms(UUIDModel, TimeStampedModel):
"""
If effective_from is set to null, that means the terms are not to be displayed to the applicant.
- """
+ """ # noqa: E501
effective_from = models.DateField(
verbose_name=_("first day these terms are in effect"), null=True, blank=True
)
@@ -155,7 +155,7 @@ class AbstractTermsApproval(UUIDModel, TimeStampedModel):
(this is actually redundant data, but I guess it helps us meet some auditing requirements). If we
didn't have that requirement, the data model would work fine with just a ForeignKey to Terms object,
as the applicant_consents can be accessed through it.
- """
+ """ # noqa: E501
approved_at = models.DateTimeField(verbose_name=_("timestamp of approval"))
approved_by = models.ForeignKey(
@@ -170,7 +170,7 @@ class AbstractTermsApproval(UUIDModel, TimeStampedModel):
)
"""
API validates that the selected_applicant_consents must belong to the terms of this approval
- """
+ """ # noqa: E501
selected_applicant_consents = models.ManyToManyField(
ApplicantConsent,
verbose_name=_("selected applicant consents"),
@@ -189,12 +189,15 @@ class ApplicantTermsApproval(AbstractTermsApproval):
)
def __str__(self):
- return f"{self.approved_by.email} approved terms {self.terms} at {self.approved_at}"
+ return (
+ f"{self.approved_by.email} approved terms {self.terms} at"
+ f" {self.approved_at}"
+ )
@staticmethod
def terms_approval_needed(application):
try:
- application.applicant_terms_approval
+ _ = application.applicant_terms_approval
except ObjectDoesNotExist:
return True
else:
diff --git a/backend/benefit/terms/tests/test_api.py b/backend/benefit/terms/tests/test_api.py
index f49adcba25..005c35bf06 100644
--- a/backend/benefit/terms/tests/test_api.py
+++ b/backend/benefit/terms/tests/test_api.py
@@ -77,7 +77,8 @@ def test_approve_terms_success(
application.status = from_status
application.save()
if previously_approved:
- # Handle case where user has previously approved terms, but new terms are now in effect.
+ # Handle case where user has previously approved terms, but new terms are now in
+ # effect.
previous_terms = TermsFactory(
effective_from=applicant_terms.effective_from - timedelta(days=10)
)
diff --git a/backend/benefit/terms/tests/test_terms_of_service_api.py b/backend/benefit/terms/tests/test_terms_of_service_api.py
index d1300068b6..26624676c5 100644
--- a/backend/benefit/terms/tests/test_terms_of_service_api.py
+++ b/backend/benefit/terms/tests/test_terms_of_service_api.py
@@ -120,7 +120,8 @@ def test_approve_terms_success(
mock_get_organisation_roles_and_create_company,
):
if previously_approved:
- # Handle case where user has previously approved terms, but new terms are now in effect.
+ # Handle case where user has previously approved terms, but new terms are now in
+ # effect.
previous_terms = TermsFactory(
effective_from=terms_of_service.effective_from - timedelta(days=10)
)
diff --git a/backend/benefit/users/api/v1/serializers.py b/backend/benefit/users/api/v1/serializers.py
index 2b8588ed7c..144cbb3fd7 100644
--- a/backend/benefit/users/api/v1/serializers.py
+++ b/backend/benefit/users/api/v1/serializers.py
@@ -14,7 +14,10 @@ class UserSerializer(serializers.ModelSerializer):
terms_of_service_approvals = TermsOfServiceApprovalSerializer(
read_only=True,
many=True,
- help_text="Terms of service approvals by this user. There could be many, if user has access to many companies.",
+ help_text=(
+ "Terms of service approvals by this user. There could be many, if user has"
+ " access to many companies."
+ ),
)
class Meta:
@@ -41,8 +44,8 @@ class Meta:
terms_of_service_in_effect = serializers.SerializerMethodField(
"get_terms_of_service_in_effect",
help_text=(
- "does the current user need to approve the terms of service currently in effect"
- "for the current company"
+ "does the current user need to approve the terms of service currently in"
+ " effectfor the current company"
),
)
@@ -70,8 +73,8 @@ def _current_user(self):
terms_of_service_approval_needed = serializers.SerializerMethodField(
"is_terms_of_service_approval_needed",
help_text=(
- "does the current user need to approve the terms of service currently in effect"
- "for the current company"
+ "does the current user need to approve the terms of service currently in"
+ " effectfor the current company"
),
)
diff --git a/backend/benefit/users/api/v1/views.py b/backend/benefit/users/api/v1/views.py
index 4c8cfe43ff..ea3d187591 100644
--- a/backend/benefit/users/api/v1/views.py
+++ b/backend/benefit/users/api/v1/views.py
@@ -57,7 +57,7 @@ def get(self, request):
class UserUuidGDPRAPIView(GDPRAPIView):
- """GDPR API view that is used from Helsinki profile to query and delete user data."""
+ """GDPR API view that is used from Helsinki profile to query and delete user data.""" # noqa: E501
permission_classes = [BFGDPRScopesPermission]
authentication_classes = [HelsinkiProfileApiTokenAuthentication]
diff --git a/backend/benefit/users/management/commands/set_group_permissions.py b/backend/benefit/users/management/commands/set_group_permissions.py
index d04a3181ee..131091525b 100644
--- a/backend/benefit/users/management/commands/set_group_permissions.py
+++ b/backend/benefit/users/management/commands/set_group_permissions.py
@@ -18,7 +18,8 @@ def handle(self, *args, **options):
handler_group = Group.objects.get(name=settings.HANDLERS_GROUP_NAME)
except Group.DoesNotExist:
raise Exception(
- f"Create group {settings.HANDLERS_GROUP_NAME} by loading groups.json fixture first"
+ f"Create group {settings.HANDLERS_GROUP_NAME} by loading groups.json"
+ " fixture first"
)
group_permissions = []
for app_label, model in self.HANDLER_PERMISSIONS:
diff --git a/backend/benefit/users/migrations/0001_initial.py b/backend/benefit/users/migrations/0001_initial.py
index ac7935e2d8..defbe347d0 100644
--- a/backend/benefit/users/migrations/0001_initial.py
+++ b/backend/benefit/users/migrations/0001_initial.py
@@ -1,14 +1,14 @@
# Generated by Django 3.2 on 2021-06-08 04:07
+import uuid
+
import django.contrib.auth.models
import django.contrib.auth.validators
-from django.db import migrations, models
import django.utils.timezone
-import uuid
+from django.db import migrations, models
class Migration(migrations.Migration):
-
initial = True
dependencies = [
@@ -30,7 +30,10 @@ class Migration(migrations.Migration):
"is_superuser",
models.BooleanField(
default=False,
- help_text="Designates that this user has all permissions without explicitly assigning them.",
+ help_text=(
+ "Designates that this user has all permissions without"
+ " explicitly assigning them."
+ ),
verbose_name="superuser status",
),
),
@@ -40,7 +43,10 @@ class Migration(migrations.Migration):
error_messages={
"unique": "A user with that username already exists."
},
- help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
+ help_text=(
+ "Required. 150 characters or fewer. Letters, digits and"
+ " @/./+/-/_ only."
+ ),
max_length=150,
unique=True,
validators=[
@@ -71,7 +77,9 @@ class Migration(migrations.Migration):
"is_staff",
models.BooleanField(
default=False,
- help_text="Designates whether the user can log into this admin site.",
+ help_text=(
+ "Designates whether the user can log into this admin site."
+ ),
verbose_name="staff status",
),
),
@@ -79,7 +87,10 @@ class Migration(migrations.Migration):
"is_active",
models.BooleanField(
default=True,
- help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
+ help_text=(
+ "Designates whether this user should be treated as active."
+ " Unselect this instead of deleting accounts."
+ ),
verbose_name="active",
),
),
@@ -102,7 +113,10 @@ class Migration(migrations.Migration):
"groups",
models.ManyToManyField(
blank=True,
- help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
+ help_text=(
+ "The groups this user belongs to. A user will get all"
+ " permissions granted to each of their groups."
+ ),
related_name="user_set",
related_query_name="user",
to="auth.Group",
diff --git a/backend/benefit/users/migrations/0002_user_ad_username.py b/backend/benefit/users/migrations/0002_user_ad_username.py
index d174725f2a..e5ddae518c 100644
--- a/backend/benefit/users/migrations/0002_user_ad_username.py
+++ b/backend/benefit/users/migrations/0002_user_ad_username.py
@@ -4,15 +4,14 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('users', '0001_initial'),
+ ("users", "0001_initial"),
]
operations = [
migrations.AddField(
- model_name='user',
- name='ad_username',
+ model_name="user",
+ name="ad_username",
field=models.CharField(blank=True, max_length=255, null=True),
),
]
diff --git a/backend/benefit/users/tests/factories.py b/backend/benefit/users/tests/factories.py
index a25d2f178e..1cec67ed0c 100644
--- a/backend/benefit/users/tests/factories.py
+++ b/backend/benefit/users/tests/factories.py
@@ -6,5 +6,3 @@ class BFHandlerUserFactory(StaffUserFactory):
Handlers are users with `is_staff=True`.
Overrided just for clear naming.
"""
-
- pass
diff --git a/backend/benefit/users/utils.py b/backend/benefit/users/utils.py
index 76692f58b1..a7dc9fcd9f 100644
--- a/backend/benefit/users/utils.py
+++ b/backend/benefit/users/utils.py
@@ -29,9 +29,10 @@ def get_company_from_request(request):
business_id=business_id
) # unique constraint ensures at most one is returned
except Company.DoesNotExist:
- # In case we cannot find the Company in DB, try to query it from 3rd party source
- # This should cover the case when first applicant of company log in because their company
- # hasn't been created yet
+ # In case we cannot find the Company in DB, try to query it from 3rd party
+ # source
+ # This should cover the case when first applicant of company log in because
+ # their company hasn't been created yet
return get_or_create_organisation_with_business_id(business_id)
else:
return None
diff --git a/backend/kesaseteli/README.md b/backend/kesaseteli/README.md
index 4f94250461..955c97cc06 100644
--- a/backend/kesaseteli/README.md
+++ b/backend/kesaseteli/README.md
@@ -65,17 +65,18 @@ In `backend/kesaseteli/`:
## Code format
-This project uses
-[`black`](https://github.com/psf/black),
-[`flake8`](https://gitlab.com/pycqa/flake8) and
-[`isort`](https://github.com/PyCQA/isort)
-for code formatting and quality checking. Project follows the basic
-black config, without any modifications.
+This project uses [](https://docs.astral.sh/ruff/) for code formatting and quality checking.
+
+Basic `ruff` commands:
-Basic `black` commands:
+* lint: `ruff check`
+* apply safe lint fixes: `ruff check --fix`
+* check formatting: `ruff format --check`
+* format: `ruff format`
-* To let `black` do its magic: `black .`
-* To see which files `black` would change: `black --check .`
+[`pre-commit`](https://pre-commit.com/) can be used to install and
+run all the formatting tools as git hooks automatically before a
+commit.
## Storages
diff --git a/backend/kesaseteli/applications/api/v1/permissions.py b/backend/kesaseteli/applications/api/v1/permissions.py
index 4ee12e5f57..90abe0b04a 100644
--- a/backend/kesaseteli/applications/api/v1/permissions.py
+++ b/backend/kesaseteli/applications/api/v1/permissions.py
@@ -28,7 +28,8 @@ def has_employer_application_permission(
request: HttpRequest, employer_application: EmployerApplication
) -> bool:
"""
- Allow access only for DRAFT status employer applications of the user & company.
+ Allow access only for DRAFT status employer applications of the user &
+ company.
"""
user = request.user
diff --git a/backend/kesaseteli/applications/api/v1/serializers.py b/backend/kesaseteli/applications/api/v1/serializers.py
index b64d1bd802..3f49e8db43 100644
--- a/backend/kesaseteli/applications/api/v1/serializers.py
+++ b/backend/kesaseteli/applications/api/v1/serializers.py
@@ -59,7 +59,8 @@ class EmployerApplicationStatusValidator:
def __call__(self, value, serializer_field):
if application := serializer_field.parent.instance:
- # In case it's an update operation, validate with the current status in database
+ # In case it's an update operation, validate with the current status in
+ # database
if (
value != application.status
and value not in self.APPLICATION_STATUS_TRANSITIONS[application.status]
@@ -67,7 +68,8 @@ def __call__(self, value, serializer_field):
raise serializers.ValidationError(
format_lazy(
_(
- "EmployerApplication state transition not allowed: {status} to {value}"
+ "EmployerApplication state transition not allowed: {status}"
+ " to {value}"
),
status=application.status,
value=value,
@@ -113,8 +115,8 @@ def get_attachment_file_name(self, obj):
def validate(self, data):
"""
- Perform rudimentary validation of file content to guard against accidentally uploading
- invalid files.
+ Perform rudimentary validation of file content to guard against
+ accidentally uploading invalid files.
"""
if (
@@ -145,7 +147,8 @@ def validate(self, data):
if not self._is_valid_pdf(data["attachment_file"]):
raise serializers.ValidationError(_("Not a valid pdf file"))
elif not self._is_valid_image(data["attachment_file"]):
- # only pdf and image files are listed in ATTACHMENT_CONTENT_TYPE_CHOICES, so if we get here,
+ # only pdf and image files are listed in ATTACHMENT_CONTENT_TYPE_CHOICES, so
+ # if we get here,
# the content type is an image file
raise serializers.ValidationError(_("Not a valid image file"))
return data
@@ -358,9 +361,9 @@ def _update_summer_vouchers(
for idx, summer_voucher_item in enumerate(serializer.validated_data):
summer_voucher_item["application_id"] = application.pk
- summer_voucher_item[
- "ordering"
- ] = idx # use the ordering defined in the JSON sent by the client
+ summer_voucher_item["ordering"] = (
+ idx # use the ordering defined in the JSON sent by the client
+ )
serializer.save()
def validate(self, data):
@@ -409,8 +412,8 @@ def _validate_non_draft_required_fields(self, data):
def _validate_attachments(self):
"""
The requirements for attachments are the minimum requirements.
- * Sometimes, a multi-page document might be uploaded as a set of jpg files, and the backend
- would not know that it's meant to be a single document.
+ * Sometimes, a multi-page document might be uploaded as a set of jpg files, and
+ the backend would not know that it's meant to be a single document.
* This validator makes sure that there is at least one of each attachment type.
"""
for summer_voucher in self.instance.summer_vouchers.all():
@@ -546,7 +549,8 @@ def create(self, validated_data):
def get_encrypted_char_field_as_json(self, obj, field_name):
"""
- Return EncryptedCharField as JSON object, converting None & empty string to {}.
+ Return EncryptedCharField as JSON object, converting None & empty
+ string to {}.
"""
if not hasattr(obj, field_name):
raise ValueError(f"Invalid field name {field_name}")
diff --git a/backend/kesaseteli/applications/api/v1/validators.py b/backend/kesaseteli/applications/api/v1/validators.py
index 82b2ec189d..bab52876ff 100644
--- a/backend/kesaseteli/applications/api/v1/validators.py
+++ b/backend/kesaseteli/applications/api/v1/validators.py
@@ -8,12 +8,13 @@ def validate_additional_info_user_reasons(
input_reasons_list, allow_empty_list=True
) -> None:
"""
- Validate input_reasons_list as a list of unique values from AdditionalInfoUserReason.
- The list may be empty only if allow_empty_list is True.
+ Validate input_reasons_list as a list of unique values from
+ AdditionalInfoUserReason. The list may be empty only if allow_empty_list is
+ True.
- :raises ValidationError: If input_reasons_list is not a list of unique values from
- AdditionalInfoUserReason, or if allow_empty_list is False
- and input_reasons_list is an empty list.
+ :raises ValidationError: If input_reasons_list is not a list of unique
+ values from AdditionalInfoUserReason, or if allow_empty_list is False
+ and input_reasons_list is an empty list.
"""
if not isinstance(input_reasons_list, list):
raise ValidationError(
@@ -46,5 +47,6 @@ def validate_additional_info_user_reasons(
if len(input_reasons_list) != len(input_reasons_set):
raise ValidationError(
- "additional_info_user_reasons must contain unique values, contained duplicates"
+ "additional_info_user_reasons must contain unique values, contained"
+ " duplicates"
)
diff --git a/backend/kesaseteli/applications/api/v1/views.py b/backend/kesaseteli/applications/api/v1/views.py
index f9d1c13b0b..e7f398bcf2 100644
--- a/backend/kesaseteli/applications/api/v1/views.py
+++ b/backend/kesaseteli/applications/api/v1/views.py
@@ -173,8 +173,10 @@ def additional_info(self, request, *args, **kwargs) -> HttpResponse:
if not youth_application.can_set_additional_info:
return Response(
data={
- "detail": _("Invalid status %(status)s for setting additional info")
- % {"status": youth_application.status}
+ "detail": (
+ _("Invalid status %(status)s for setting additional info")
+ % {"status": youth_application.status}
+ )
},
status=status.HTTP_400_BAD_REQUEST,
)
@@ -207,7 +209,7 @@ def additional_info(self, request, *args, **kwargs) -> HttpResponse:
)
except ValidationError as e:
LOGGER.error(
- f"Youth application additional info rejected because of "
+ "Youth application additional info rejected because of "
f"validation error. Validation error codes: {str(e.get_codes())}"
)
raise
@@ -217,8 +219,9 @@ def additional_info(self, request, *args, **kwargs) -> HttpResponse:
@action(methods=["post"], detail=False)
def fetch_employee_data(self, request, *args, **kwargs) -> HttpResponse:
"""
- Fetch employee data to a particular EmployerSummerVoucher using the employee's
- name and their YouthSummerVoucher's summer_voucher_serial_number
+ Fetch employee data to a particular EmployerSummerVoucher using the
+ employee's name and their YouthSummerVoucher's
+ summer_voucher_serial_number.
"""
if not request.user.is_authenticated:
return Response(status=status.HTTP_403_FORBIDDEN)
@@ -324,7 +327,7 @@ def accept(self, request, *args, **kwargs) -> HttpResponse:
serializer.is_valid(raise_exception=True)
except ValidationError as e:
LOGGER.error(
- f"Youth application was not changed to accepted state because of "
+ "Youth application was not changed to accepted state because of "
f"validation error. Validation error codes: {str(e.get_codes())}"
)
raise
@@ -372,7 +375,7 @@ def reject(self, request, *args, **kwargs) -> HttpResponse:
serializer.is_valid(raise_exception=True)
except ValidationError as e:
LOGGER.error(
- f"Youth application was not changed to rejected state because of "
+ "Youth application was not changed to rejected state because of "
f"validation error. Validation error codes: {str(e.get_codes())}"
)
raise
@@ -425,7 +428,7 @@ def activate(self, request, *args, **kwargs) -> HttpResponse: # noqa: C901
f"Activated youth application {youth_application.pk}: "
"Youth application was accepted automatically using data from VTJ"
)
- was_email_sent = youth_application.youth_summer_voucher.send_youth_summer_voucher_email(
+ was_email_sent = youth_application.youth_summer_voucher.send_youth_summer_voucher_email( # noqa: E501
language=youth_application.language
)
if not was_email_sent:
@@ -469,7 +472,7 @@ def error_response_with_logging(
response_status = status.HTTP_400_BAD_REQUEST
response_data = reason.json()
LOGGER.info(
- f"Youth application submission rejected. "
+ "Youth application submission rejected. "
f"Return HTTP status code: {response_status}. "
f"YouthApplicationRejectedReason: {response_data.get('code')}."
)
@@ -486,7 +489,7 @@ def create(self, request, *args, **kwargs): # noqa: C901
email = serializer.validated_data["email"]
social_security_number = serializer.validated_data["social_security_number"]
- if YouthApplication.objects.is_email_or_social_security_number_active_this_year(
+ if YouthApplication.objects.is_email_or_social_security_number_active_this_year( # noqa: E501
email, social_security_number
):
return self.error_response_with_logging(
@@ -538,7 +541,7 @@ def create(self, request, *args, **kwargs): # noqa: C901
if not request_additional_info:
if (
- not youth_application.is_social_security_number_valid_according_to_vtj
+ not youth_application.is_social_security_number_valid_according_to_vtj # noqa: E501
or youth_application.is_applicant_dead_according_to_vtj
):
transaction.set_rollback(True)
@@ -579,7 +582,7 @@ def create(self, request, *args, **kwargs): # noqa: C901
)
except ValidationError as e:
LOGGER.error(
- f"Youth application submission rejected because of validation error. "
+ "Youth application submission rejected because of validation error. "
f"Validation error codes: {str(e.get_codes())}"
)
raise
@@ -645,8 +648,9 @@ class EmployerApplicationViewSet(AuditLoggingModelViewSet):
def get_queryset(self):
"""
Fetch all DRAFT status applications of the user & company.
- Should inlcude only 1 application since we don't allow creation of multiple
- DRAFT applications per user & company.
+
+ Should inlcude only 1 application since we don't allow creation of
+ multiple DRAFT applications per user & company.
"""
queryset = (
super()
@@ -698,7 +702,8 @@ class EmployerSummerVoucherViewSet(AuditLoggingModelViewSet):
def get_queryset(self):
"""
- Fetch summer vouchers of DRAFT status applications of the user & company.
+ Fetch summer vouchers of DRAFT status applications of the user &
+ company.
"""
queryset = (
super()
@@ -744,7 +749,7 @@ def destroy(self, request, *args, **kwargs):
)
def post_attachment(self, request, *args, **kwargs):
"""
- Upload a single file as attachment
+ Upload a single file as attachment.
"""
obj = self.get_object()
@@ -779,7 +784,7 @@ def handle_attachment(self, request, attachment_pk, *args, **kwargs):
if request.method == "GET":
"""
- Read a single attachment as file
+ Read a single attachment as file.
"""
attachment = obj.attachments.filter(pk=attachment_pk).first()
if not attachment or not attachment.attachment_file:
@@ -795,7 +800,7 @@ def handle_attachment(self, request, attachment_pk, *args, **kwargs):
elif request.method == "DELETE":
"""
- Delete a single attachment as file
+ Delete a single attachment as file.
"""
if obj.application.status not in ALLOWED_APPLICATION_UPDATE_STATUSES:
raise ValidationError(
diff --git a/backend/kesaseteli/applications/enums.py b/backend/kesaseteli/applications/enums.py
index e389d29b7d..b08a22a1f8 100644
--- a/backend/kesaseteli/applications/enums.py
+++ b/backend/kesaseteli/applications/enums.py
@@ -19,7 +19,7 @@
def get_supported_languages() -> Tuple[str]:
"""
- Get tuple of supported languages
+ Get tuple of supported languages.
:return: Tuple of the supported languages' codes, e.g. ('fi', 'sv', 'en')
"""
@@ -28,7 +28,7 @@ def get_supported_languages() -> Tuple[str]:
class ExcelColumns(models.TextChoices):
"""
- Excel export output column set choices
+ Excel export output column set choices.
"""
REPORTING = "reporting", _("Reporting")
@@ -38,11 +38,13 @@ class ExcelColumns(models.TextChoices):
class EmployerApplicationStatus(models.TextChoices):
DRAFT = "draft", _("Draft")
SUBMITTED = "submitted", _("Submitted")
- ADDITIONAL_INFORMATION_REQUESTED = "additional_information_requested", _(
- "Additional information requested"
+ ADDITIONAL_INFORMATION_REQUESTED = (
+ "additional_information_requested",
+ _("Additional information requested"),
)
- ADDITIONAL_INFORMATION_PROVIDED = "additional_information_provided", _(
- "Additional information provided"
+ ADDITIONAL_INFORMATION_PROVIDED = (
+ "additional_information_provided",
+ _("Additional information provided"),
)
ACCEPTED = "accepted", _("Accepted")
REJECTED = "rejected", _("Rejected")
@@ -51,14 +53,17 @@ class EmployerApplicationStatus(models.TextChoices):
class YouthApplicationStatus(models.TextChoices):
SUBMITTED = "submitted", _("Submitted")
- AWAITING_MANUAL_PROCESSING = "awaiting_manual_processing", _(
- "Awaiting manual processing"
+ AWAITING_MANUAL_PROCESSING = (
+ "awaiting_manual_processing",
+ _("Awaiting manual processing"),
)
- ADDITIONAL_INFORMATION_REQUESTED = "additional_information_requested", _(
- "Additional information requested"
+ ADDITIONAL_INFORMATION_REQUESTED = (
+ "additional_information_requested",
+ _("Additional information requested"),
)
- ADDITIONAL_INFORMATION_PROVIDED = "additional_information_provided", _(
- "Additional information provided"
+ ADDITIONAL_INFORMATION_PROVIDED = (
+ "additional_information_provided",
+ _("Additional information provided"),
)
ACCEPTED = "accepted", _("Accepted")
REJECTED = "rejected", _("Rejected")
@@ -66,7 +71,8 @@ class YouthApplicationStatus(models.TextChoices):
@staticmethod
def active_values():
"""
- Youth application statuses for youth application that have been activated.
+ Youth application statuses for youth application that have been
+ activated.
"""
return [
YouthApplicationStatus.AWAITING_MANUAL_PROCESSING.value,
@@ -79,7 +85,8 @@ def active_values():
@staticmethod
def can_have_additional_info_values():
"""
- Youth application statuses in which additional info may have been provided.
+ Youth application statuses in which additional info may have been
+ provided.
"""
return [
YouthApplicationStatus.ADDITIONAL_INFORMATION_PROVIDED.value,
@@ -90,7 +97,8 @@ def can_have_additional_info_values():
@staticmethod
def must_have_additional_info_values():
"""
- Youth application statuses in which additional info must have been provided.
+ Youth application statuses in which additional info must have been
+ provided.
"""
return [
YouthApplicationStatus.ADDITIONAL_INFORMATION_PROVIDED.value,
@@ -99,7 +107,8 @@ def must_have_additional_info_values():
@staticmethod
def acceptable_values():
"""
- Youth application statuses from which the youth application can be accepted.
+ Youth application statuses from which the youth application can be
+ accepted.
"""
return [
YouthApplicationStatus.AWAITING_MANUAL_PROCESSING.value,
@@ -109,7 +118,8 @@ def acceptable_values():
@staticmethod
def rejectable_values():
"""
- Youth application statuses from which the youth application can be rejected.
+ Youth application statuses from which the youth application can be
+ rejected.
"""
return [
YouthApplicationStatus.AWAITING_MANUAL_PROCESSING.value,
@@ -120,7 +130,8 @@ def rejectable_values():
@staticmethod
def handled_values():
"""
- Youth application statuses which have been handled and require a handler.
+ Youth application statuses which have been handled and require a
+ handler.
"""
return [YouthApplicationStatus.ACCEPTED, YouthApplicationStatus.REJECTED]
@@ -146,13 +157,15 @@ def active_unhandled_values():
class AdditionalInfoUserReason(models.TextChoices):
- STUDENT_IN_HELSINKI_BUT_NOT_RESIDENT = "student_in_helsinki_but_not_resident", _(
- "Student in Helsinki but not resident"
+ STUDENT_IN_HELSINKI_BUT_NOT_RESIDENT = (
+ "student_in_helsinki_but_not_resident",
+ _("Student in Helsinki but not resident"),
)
MOVING_TO_HELSINKI = "moving_to_helsinki", _("Moving to Helsinki")
UNDERAGE_OR_OVERAGE = "underage_or_overage", _("Underage or overage")
- PERSONAL_INFO_DIFFERS_FROM_VTJ = "personal_info_differs_from_vtj", _(
- "Personal info differs from VTJ"
+ PERSONAL_INFO_DIFFERS_FROM_VTJ = (
+ "personal_info_differs_from_vtj",
+ _("Personal info differs from VTJ"),
)
UNLISTED_SCHOOL = "unlisted_school", _("Unlisted school")
OTHER = "other", _("Other")
@@ -164,8 +177,10 @@ class AttachmentType(models.TextChoices):
class SummerVoucherExceptionReason(models.TextChoices):
- # TODO: Replace this hard coded enum class with a model where the controllers can add the exceptions themselves.
- # These exceptions can change yearly and thus should be dynamically editable by the controllers.
+ # TODO: Replace this hard coded enum class with a model where the controllers can
+ # add the exceptions themselves.
+ # These exceptions can change yearly and thus should be dynamically editable by the
+ # controllers.
PRIMARY_TARGET_GROUP = "primary_target_group", _("primary target group")
SECONDARY_TARGET_GROUP = "secondary_target_group", _("secondary target group")
diff --git a/backend/kesaseteli/applications/exporters/excel_exporter.py b/backend/kesaseteli/applications/exporters/excel_exporter.py
index eb0c5ed384..8adb8c728d 100644
--- a/backend/kesaseteli/applications/exporters/excel_exporter.py
+++ b/backend/kesaseteli/applications/exporters/excel_exporter.py
@@ -95,7 +95,8 @@ class ExcelField(NamedTuple):
FIELDS = [
- # Field title, field value, field names in summer voucher model, column width, background color
+ # Field title, field value, field names in summer voucher model, column width,
+ # background color
ExcelField(ORDER_FIELD_TITLE, "", [], 15, "white"), # Specially handled
ExcelField(
RECEIVED_DATE_FIELD_TITLE, "%s", ["submitted_at"], 15, "white"
@@ -277,7 +278,9 @@ def get_exportable_fields(columns: ExcelColumns):
def get_xlsx_filename(columns: ExcelColumns) -> str:
"""
- Get the name of the excel file. Example filename:
+ Get the name of the excel file.
+
+ Example filename:
talpa-kesasetelihakemukset_2021-01-01_23-59-59.xlsx
"""
local_datetime_now_as_str = timezone.localtime(timezone.now()).strftime(
@@ -313,7 +316,8 @@ def get_attachment_uri(
elif attachment_type == "Palkkalaskelma":
attachment_type = "payslip"
- # Get attachment of type `attachment_type` and use the OFFSET and LIMIT to get only the n'th entry
+ # Get attachment of type `attachment_type` and use the OFFSET and LIMIT to get only
+ # the n'th entry
# where n is `attachment_number`.
attachment = (
value.filter(attachment_type=attachment_type)
@@ -355,7 +359,7 @@ def generate_data_row(
is_template: bool = False,
) -> list:
result = []
- for column_number, field in enumerate(fields):
+ for field in fields:
if field.title == ORDER_FIELD_TITLE:
cell_value = summer_voucher.row_number
elif field.title == RECEIVED_DATE_FIELD_TITLE:
@@ -419,8 +423,9 @@ def populate_workbook(
is_template: bool = False,
):
"""
- Fill the workbook with information from the summer vouchers queryset. Field names and values are
- fetched from the FIELDS tuple.
+ Fill the workbook with information from the summer vouchers queryset.
+
+ Field names and values are fetched from the FIELDS tuple.
"""
ws = wb.add_worksheet(name=str(_("Setelit")))
wrapped_cell_format = wb.add_format()
diff --git a/backend/kesaseteli/applications/jobs/daily/tests/test_clean_youth_applications.py b/backend/kesaseteli/applications/jobs/daily/tests/test_clean_youth_applications.py
index 3e4d954e1e..d510c61b5c 100644
--- a/backend/kesaseteli/applications/jobs/daily/tests/test_clean_youth_applications.py
+++ b/backend/kesaseteli/applications/jobs/daily/tests/test_clean_youth_applications.py
@@ -54,14 +54,14 @@ def test_clean_inactive_youth_applications_older_than_week():
).exists(), "Inactive applications should have been cleaned"
for application in inactive_applications_created_less_than_week_ago:
- assert YouthApplication.objects.filter(
- pk=application.id
- ).exists(), "Newer inactive applications should still exist"
+ assert YouthApplication.objects.filter(pk=application.id).exists(), (
+ "Newer inactive applications should still exist"
+ )
for application in active_applications_created_week_ago:
- assert YouthApplication.objects.filter(
- pk=application.id
- ).exists(), "Active applications should still exist"
+ assert YouthApplication.objects.filter(pk=application.id).exists(), (
+ "Active applications should still exist"
+ )
@pytest.mark.django_db
@@ -95,19 +95,19 @@ def test_clean_rejected_youth_applications_older_than_year():
).exists(), "Rejected application older than year should have been cleaned"
for application in rejected_applications_created_less_than_year_ago:
- assert YouthApplication.objects.filter(
- pk=application.id
- ).exists(), "Newer rejected applications should still exist"
+ assert YouthApplication.objects.filter(pk=application.id).exists(), (
+ "Newer rejected applications should still exist"
+ )
for application in unhandled_applications_created_year_ago:
- assert YouthApplication.objects.filter(
- pk=application.id
- ).exists(), "Unhandled applications should still exist"
+ assert YouthApplication.objects.filter(pk=application.id).exists(), (
+ "Unhandled applications should still exist"
+ )
for application in accepted_applications_created_year_ago:
- assert YouthApplication.objects.filter(
- pk=application.id
- ).exists(), "Accepted applications should still exist"
+ assert YouthApplication.objects.filter(pk=application.id).exists(), (
+ "Accepted applications should still exist"
+ )
@pytest.mark.django_db
@@ -160,11 +160,11 @@ def test_clean_all_youth_applications_older_than_five_years():
).exists(), "Old summer vouchers should have been cleaned"
for application in applications_created_less_than_five_years_ago:
- assert YouthApplication.objects.filter(
- pk=application.id
- ).exists(), "Newer applications should still exist"
+ assert YouthApplication.objects.filter(pk=application.id).exists(), (
+ "Newer applications should still exist"
+ )
for summer_voucher in summer_vouchers_created_less_than_five_years_ago:
- assert YouthSummerVoucher.objects.filter(
- pk=summer_voucher.id
- ).exists(), "Newer summer vouchers should still exist"
+ assert YouthSummerVoucher.objects.filter(pk=summer_voucher.id).exists(), (
+ "Newer summer vouchers should still exist"
+ )
diff --git a/backend/kesaseteli/applications/migrations/0001_initial.py b/backend/kesaseteli/applications/migrations/0001_initial.py
index fa0a090743..273bd26fbf 100644
--- a/backend/kesaseteli/applications/migrations/0001_initial.py
+++ b/backend/kesaseteli/applications/migrations/0001_initial.py
@@ -1,14 +1,14 @@
# Generated by Django 3.2 on 2021-05-05 08:32
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
class Migration(migrations.Migration):
-
initial = True
dependencies = [
diff --git a/backend/kesaseteli/applications/migrations/0002_summer_voucher_attachments.py b/backend/kesaseteli/applications/migrations/0002_summer_voucher_attachments.py
index 78e96cbe28..aac8083418 100644
--- a/backend/kesaseteli/applications/migrations/0002_summer_voucher_attachments.py
+++ b/backend/kesaseteli/applications/migrations/0002_summer_voucher_attachments.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0001_initial"),
]
diff --git a/backend/kesaseteli/applications/migrations/0003_application_contact_person.py b/backend/kesaseteli/applications/migrations/0003_application_contact_person.py
index 9231eb0104..51ace97674 100644
--- a/backend/kesaseteli/applications/migrations/0003_application_contact_person.py
+++ b/backend/kesaseteli/applications/migrations/0003_application_contact_person.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0002_summer_voucher_attachments"),
]
diff --git a/backend/kesaseteli/applications/migrations/0004_application_default_status.py b/backend/kesaseteli/applications/migrations/0004_application_default_status.py
index 4b50ca9501..0d58762ee8 100644
--- a/backend/kesaseteli/applications/migrations/0004_application_default_status.py
+++ b/backend/kesaseteli/applications/migrations/0004_application_default_status.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0003_application_contact_person"),
]
diff --git a/backend/kesaseteli/applications/migrations/0005_change_encryption_library.py b/backend/kesaseteli/applications/migrations/0005_change_encryption_library.py
index a71dba08e0..0180581907 100644
--- a/backend/kesaseteli/applications/migrations/0005_change_encryption_library.py
+++ b/backend/kesaseteli/applications/migrations/0005_change_encryption_library.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.4 on 2021-08-18 07:35
-from django.db import migrations, models
import encrypted_fields.fields
+from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0004_application_default_status"),
]
diff --git a/backend/kesaseteli/applications/migrations/0006_refactor_attachments.py b/backend/kesaseteli/applications/migrations/0006_refactor_attachments.py
index ab74ba653b..038294911a 100644
--- a/backend/kesaseteli/applications/migrations/0006_refactor_attachments.py
+++ b/backend/kesaseteli/applications/migrations/0006_refactor_attachments.py
@@ -1,12 +1,12 @@
# Generated by Django 3.2.4 on 2021-08-26 12:08
-from django.db import migrations, models
-import django.db.models.deletion
import uuid
+import django.db.models.deletion
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0005_change_encryption_library"),
]
diff --git a/backend/kesaseteli/applications/migrations/0007_model_timestamps_and_ordering.py b/backend/kesaseteli/applications/migrations/0007_model_timestamps_and_ordering.py
index 1622663091..3491eed5f8 100644
--- a/backend/kesaseteli/applications/migrations/0007_model_timestamps_and_ordering.py
+++ b/backend/kesaseteli/applications/migrations/0007_model_timestamps_and_ordering.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.4 on 2021-08-26 12:46
-from django.db import migrations, models
import django.utils.timezone
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0006_refactor_attachments"),
]
diff --git a/backend/kesaseteli/applications/migrations/0008_delete_applications.py b/backend/kesaseteli/applications/migrations/0008_delete_applications.py
index add58d3ad3..cbaac8ea51 100644
--- a/backend/kesaseteli/applications/migrations/0008_delete_applications.py
+++ b/backend/kesaseteli/applications/migrations/0008_delete_applications.py
@@ -10,9 +10,11 @@ def delete_applications(apps, schema_editor):
class Migration(migrations.Migration):
"""
- Delete applications since the next migration (0009_add_application_user) will add the user ForeignKey for
- the appilcations and it is not possible to set a reasonable default value for that. Delete all applications
- since there is no use form them without an user.
+ Delete applications since the next migration (0009_add_application_user)
+ will add the user ForeignKey for the appilcations and it is not possible to
+ set a reasonable default value for that.
+
+ Delete all applications since there is no use form them without an user.
"""
dependencies = [
diff --git a/backend/kesaseteli/applications/migrations/0009_add_application_user.py b/backend/kesaseteli/applications/migrations/0009_add_application_user.py
index 9f06faf1fc..7e263b70a9 100644
--- a/backend/kesaseteli/applications/migrations/0009_add_application_user.py
+++ b/backend/kesaseteli/applications/migrations/0009_add_application_user.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2021-08-30 09:43
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("applications", "0008_delete_applications"),
diff --git a/backend/kesaseteli/applications/migrations/0010_update_summer_voucher_fields.py b/backend/kesaseteli/applications/migrations/0010_update_summer_voucher_fields.py
index c87693d116..f6006ab636 100644
--- a/backend/kesaseteli/applications/migrations/0010_update_summer_voucher_fields.py
+++ b/backend/kesaseteli/applications/migrations/0010_update_summer_voucher_fields.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0009_add_application_user"),
]
@@ -146,7 +145,10 @@ class Migration(migrations.Migration):
field=models.CharField(
blank=True,
choices=[("yes", "yes"), ("no", "no"), ("maybe", "maybe")],
- help_text="Whether the employee would have been hired without a summer voucher.",
+ help_text=(
+ "Whether the employee would have been hired without a summer"
+ " voucher."
+ ),
max_length=32,
null=True,
verbose_name="hired without voucher assessment",
@@ -231,7 +233,10 @@ class Migration(migrations.Migration):
field=models.CharField(
blank=True,
choices=[("yes", "yes"), ("no", "no"), ("maybe", "maybe")],
- help_text="Whether the employee would have been hired without a summer voucher.",
+ help_text=(
+ "Whether the employee would have been hired without a summer"
+ " voucher."
+ ),
max_length=32,
null=True,
verbose_name="hired without voucher assessment",
diff --git a/backend/kesaseteli/applications/migrations/0011_add_is_exported.py b/backend/kesaseteli/applications/migrations/0011_add_is_exported.py
index d2ebe14ac6..c21279d94e 100644
--- a/backend/kesaseteli/applications/migrations/0011_add_is_exported.py
+++ b/backend/kesaseteli/applications/migrations/0011_add_is_exported.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0010_update_summer_voucher_fields"),
]
diff --git a/backend/kesaseteli/applications/migrations/0012_add_youthapplication_youthsummervoucher.py b/backend/kesaseteli/applications/migrations/0012_add_youthapplication_youthsummervoucher.py
index 14c98cfec2..cecda090ec 100644
--- a/backend/kesaseteli/applications/migrations/0012_add_youthapplication_youthsummervoucher.py
+++ b/backend/kesaseteli/applications/migrations/0012_add_youthapplication_youthsummervoucher.py
@@ -1,16 +1,17 @@
# Generated by Django 3.2.4 on 2021-12-02 11:12
-import common.utils
-from django.conf import settings
-from django.db import migrations, models
+import uuid
+
import django.db.models.deletion
import encrypted_fields.fields
import simple_history.models
-import uuid
+from django.conf import settings
+from django.db import migrations, models
+import common.utils
-class Migration(migrations.Migration):
+class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("applications", "0011_add_is_exported"),
diff --git a/backend/kesaseteli/applications/migrations/0013_school.py b/backend/kesaseteli/applications/migrations/0013_school.py
index f3f02ddadf..4c2f8a76d6 100644
--- a/backend/kesaseteli/applications/migrations/0013_school.py
+++ b/backend/kesaseteli/applications/migrations/0013_school.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2.4 on 2021-12-03 06:32
-from django.db import migrations, models
import uuid
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0012_add_youthapplication_youthsummervoucher"),
]
diff --git a/backend/kesaseteli/applications/migrations/0014_set_default_schools.py b/backend/kesaseteli/applications/migrations/0014_set_default_schools.py
index 11640246dc..07d906e372 100644
--- a/backend/kesaseteli/applications/migrations/0014_set_default_schools.py
+++ b/backend/kesaseteli/applications/migrations/0014_set_default_schools.py
@@ -1,6 +1,5 @@
from django.db import migrations, transaction
-
DEFAULT_SCHOOL_LIST = [
"Aleksis Kiven peruskoulu",
"Arabian peruskoulu",
@@ -122,7 +121,6 @@ def set_default_schools(apps, schema_editor):
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0013_school"),
]
diff --git a/backend/kesaseteli/applications/migrations/0015_set_real_schools.py b/backend/kesaseteli/applications/migrations/0015_set_real_schools.py
index a71867e953..6011acb1b7 100644
--- a/backend/kesaseteli/applications/migrations/0015_set_real_schools.py
+++ b/backend/kesaseteli/applications/migrations/0015_set_real_schools.py
@@ -1,6 +1,5 @@
from django.db import migrations, transaction
-
REAL_SCHOOL_LIST = [
"Aleksis Kiven peruskoulu",
"Apollon yhteiskoulu",
@@ -91,7 +90,6 @@ def set_real_schools(apps, schema_editor):
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0014_set_default_schools"),
]
diff --git a/backend/kesaseteli/applications/migrations/0016_add_youth_application_field_validation.py b/backend/kesaseteli/applications/migrations/0016_add_youth_application_field_validation.py
index 550c3f4c60..d29c81fe6e 100644
--- a/backend/kesaseteli/applications/migrations/0016_add_youth_application_field_validation.py
+++ b/backend/kesaseteli/applications/migrations/0016_add_youth_application_field_validation.py
@@ -1,14 +1,14 @@
# Generated by Django 3.2.4 on 2021-12-14 10:53
+import encrypted_fields.fields
+from django.db import migrations, models
+
import applications.models
import common.utils
import shared.common.validators
-from django.db import migrations, models
-import encrypted_fields.fields
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0015_set_real_schools"),
]
@@ -74,7 +74,9 @@ class Migration(migrations.Migration):
blank=True,
db_index=True,
encrypted_field_name="encrypted_social_security_number",
- hash_key="ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669",
+ hash_key=(
+ "ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669"
+ ),
max_length=66,
null=True,
validators=[common.utils.validate_finnish_social_security_number],
@@ -140,7 +142,9 @@ class Migration(migrations.Migration):
blank=True,
db_index=True,
encrypted_field_name="encrypted_social_security_number",
- hash_key="ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669",
+ hash_key=(
+ "ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669"
+ ),
max_length=66,
null=True,
validators=[common.utils.validate_finnish_social_security_number],
diff --git a/backend/kesaseteli/applications/migrations/0017_refactor_school.py b/backend/kesaseteli/applications/migrations/0017_refactor_school.py
index 2bf3700c88..45ccef5728 100644
--- a/backend/kesaseteli/applications/migrations/0017_refactor_school.py
+++ b/backend/kesaseteli/applications/migrations/0017_refactor_school.py
@@ -1,4 +1,5 @@
from django.db import migrations, models
+
import shared.common.validators
@@ -8,7 +9,6 @@ def remove_deleted_schools(apps, schema_editor):
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0016_add_youth_application_field_validation"),
]
diff --git a/backend/kesaseteli/applications/migrations/0018_rename_application_to_employer_application.py b/backend/kesaseteli/applications/migrations/0018_rename_application_to_employer_application.py
index 4274dbb3c6..1c62dad377 100644
--- a/backend/kesaseteli/applications/migrations/0018_rename_application_to_employer_application.py
+++ b/backend/kesaseteli/applications/migrations/0018_rename_application_to_employer_application.py
@@ -5,7 +5,6 @@
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("companies", "0005_remove_company_eauth_profile"),
diff --git a/backend/kesaseteli/applications/migrations/0019_use_employer_applications_related_name.py b/backend/kesaseteli/applications/migrations/0019_use_employer_applications_related_name.py
index a445658ef6..7e53ac3db6 100644
--- a/backend/kesaseteli/applications/migrations/0019_use_employer_applications_related_name.py
+++ b/backend/kesaseteli/applications/migrations/0019_use_employer_applications_related_name.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2021-12-30 09:30
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0005_remove_company_eauth_profile"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
diff --git a/backend/kesaseteli/applications/migrations/0020_rename_summer_voucher_to_employer_summer_voucher.py b/backend/kesaseteli/applications/migrations/0020_rename_summer_voucher_to_employer_summer_voucher.py
index 27dfaa3c40..ab405fb07e 100644
--- a/backend/kesaseteli/applications/migrations/0020_rename_summer_voucher_to_employer_summer_voucher.py
+++ b/backend/kesaseteli/applications/migrations/0020_rename_summer_voucher_to_employer_summer_voucher.py
@@ -5,7 +5,6 @@
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("applications", "0019_use_employer_applications_related_name"),
diff --git a/backend/kesaseteli/applications/migrations/0021_add_encrypted_vtj_json.py b/backend/kesaseteli/applications/migrations/0021_add_encrypted_vtj_json.py
index 8de2d6727f..4f7fc681ca 100644
--- a/backend/kesaseteli/applications/migrations/0021_add_encrypted_vtj_json.py
+++ b/backend/kesaseteli/applications/migrations/0021_add_encrypted_vtj_json.py
@@ -1,12 +1,12 @@
# Generated by Django 3.2.4 on 2022-01-14 09:32
-from django.db import migrations
import encrypted_fields.fields
+from django.db import migrations
+
import shared.common.validators
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0020_rename_summer_voucher_to_employer_summer_voucher"),
]
diff --git a/backend/kesaseteli/applications/migrations/0022_youthapplication_postcode.py b/backend/kesaseteli/applications/migrations/0022_youthapplication_postcode.py
index 61685fd94c..cb8ccf74ba 100644
--- a/backend/kesaseteli/applications/migrations/0022_youthapplication_postcode.py
+++ b/backend/kesaseteli/applications/migrations/0022_youthapplication_postcode.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2.4 on 2022-01-24 11:35
from django.db import migrations, models
+
import shared.common.validators
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0021_add_encrypted_vtj_json"),
]
diff --git a/backend/kesaseteli/applications/migrations/0023_index_youth_application_fields.py b/backend/kesaseteli/applications/migrations/0023_index_youth_application_fields.py
index 32331eb84a..fb4fc40274 100644
--- a/backend/kesaseteli/applications/migrations/0023_index_youth_application_fields.py
+++ b/backend/kesaseteli/applications/migrations/0023_index_youth_application_fields.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0022_youthapplication_postcode"),
]
diff --git a/backend/kesaseteli/applications/migrations/0024_youthapplication_status.py b/backend/kesaseteli/applications/migrations/0024_youthapplication_status.py
index 7607b0abb0..914af63ab9 100644
--- a/backend/kesaseteli/applications/migrations/0024_youthapplication_status.py
+++ b/backend/kesaseteli/applications/migrations/0024_youthapplication_status.py
@@ -1,4 +1,5 @@
from django.db import migrations, models
+
from applications.enums import YouthApplicationStatus
@@ -13,7 +14,6 @@ def set_youth_application_statuses(apps, schema_editor):
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0023_index_youth_application_fields"),
]
diff --git a/backend/kesaseteli/applications/migrations/0025_youthapplication_handler_and_handled_at.py b/backend/kesaseteli/applications/migrations/0025_youthapplication_handler_and_handled_at.py
index d393a12d8a..a50338b924 100644
--- a/backend/kesaseteli/applications/migrations/0025_youthapplication_handler_and_handled_at.py
+++ b/backend/kesaseteli/applications/migrations/0025_youthapplication_handler_and_handled_at.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2022-02-28 06:51
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("applications", "0024_youthapplication_status"),
diff --git a/backend/kesaseteli/applications/migrations/0026_youth_summer_voucher_serial_number.py b/backend/kesaseteli/applications/migrations/0026_youth_summer_voucher_serial_number.py
index 0878227a6f..4f40e74e2d 100644
--- a/backend/kesaseteli/applications/migrations/0026_youth_summer_voucher_serial_number.py
+++ b/backend/kesaseteli/applications/migrations/0026_youth_summer_voucher_serial_number.py
@@ -1,12 +1,11 @@
# Generated by Django 3.2.4 on 2022-03-01 14:28
import django.core.validators
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0025_youthapplication_handler_and_handled_at"),
]
diff --git a/backend/kesaseteli/applications/migrations/0027_add_additional_info.py b/backend/kesaseteli/applications/migrations/0027_add_additional_info.py
index 90802efce0..ca0e4c385a 100644
--- a/backend/kesaseteli/applications/migrations/0027_add_additional_info.py
+++ b/backend/kesaseteli/applications/migrations/0027_add_additional_info.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2.4 on 2022-03-22 09:30
-import applications.api.v1.validators
from django.db import migrations, models
+import applications.api.v1.validators
+
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0026_youth_summer_voucher_serial_number"),
]
diff --git a/backend/kesaseteli/applications/migrations/0028_add_encrypted_handler_and_original_vtj_json.py b/backend/kesaseteli/applications/migrations/0028_add_encrypted_handler_and_original_vtj_json.py
index 1b1d8d9d42..23635a5358 100644
--- a/backend/kesaseteli/applications/migrations/0028_add_encrypted_handler_and_original_vtj_json.py
+++ b/backend/kesaseteli/applications/migrations/0028_add_encrypted_handler_and_original_vtj_json.py
@@ -1,5 +1,6 @@
-from django.db import migrations, transaction
import encrypted_fields.fields
+from django.db import migrations, transaction
+
import shared.common.validators
@@ -35,7 +36,6 @@ def backward_migrate_encrypted_vtj_json_fields(apps, schema_editor):
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0027_add_additional_info"),
]
@@ -58,7 +58,9 @@ class Migration(migrations.Migration):
name="encrypted_original_vtj_json",
field=encrypted_fields.fields.EncryptedCharField(
blank=True,
- help_text="VTJ JSON used for automatic processing of new youth application",
+ help_text=(
+ "VTJ JSON used for automatic processing of new youth application"
+ ),
max_length=1048576,
null=True,
validators=[shared.common.validators.validate_optional_json],
diff --git a/backend/kesaseteli/applications/migrations/0029_remove_youthapplication_encrypted_vtj_json.py b/backend/kesaseteli/applications/migrations/0029_remove_youthapplication_encrypted_vtj_json.py
index 4ffccd9b53..a521e3ffde 100644
--- a/backend/kesaseteli/applications/migrations/0029_remove_youthapplication_encrypted_vtj_json.py
+++ b/backend/kesaseteli/applications/migrations/0029_remove_youthapplication_encrypted_vtj_json.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0028_add_encrypted_handler_and_original_vtj_json"),
]
diff --git a/backend/kesaseteli/applications/migrations/0030_add_bank_account_number.py b/backend/kesaseteli/applications/migrations/0030_add_bank_account_number.py
index 54e5701e3c..f29d6716c4 100644
--- a/backend/kesaseteli/applications/migrations/0030_add_bank_account_number.py
+++ b/backend/kesaseteli/applications/migrations/0030_add_bank_account_number.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.4 on 2022-05-13 07:07
-from django.db import migrations
import localflavor.generic.models
+from django.db import migrations
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0029_remove_youthapplication_encrypted_vtj_json"),
]
diff --git a/backend/kesaseteli/applications/migrations/0031_rename_summer_voucher_exception_reason_to_target_group.py b/backend/kesaseteli/applications/migrations/0031_rename_summer_voucher_exception_reason_to_target_group.py
index 467b67e17b..fe5d0eb7f4 100644
--- a/backend/kesaseteli/applications/migrations/0031_rename_summer_voucher_exception_reason_to_target_group.py
+++ b/backend/kesaseteli/applications/migrations/0031_rename_summer_voucher_exception_reason_to_target_group.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0030_add_bank_account_number"),
]
diff --git a/backend/kesaseteli/applications/migrations/0032_alter_employersummervoucher_target_group.py b/backend/kesaseteli/applications/migrations/0032_alter_employersummervoucher_target_group.py
index f17618771a..1f428f3da7 100644
--- a/backend/kesaseteli/applications/migrations/0032_alter_employersummervoucher_target_group.py
+++ b/backend/kesaseteli/applications/migrations/0032_alter_employersummervoucher_target_group.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0031_rename_summer_voucher_exception_reason_to_target_group"),
]
diff --git a/backend/kesaseteli/applications/migrations/0033_add_non_vtj_birthdate_and_home_municipality.py b/backend/kesaseteli/applications/migrations/0033_add_non_vtj_birthdate_and_home_municipality.py
index 7a0d2791aa..5f1f1ba696 100644
--- a/backend/kesaseteli/applications/migrations/0033_add_non_vtj_birthdate_and_home_municipality.py
+++ b/backend/kesaseteli/applications/migrations/0033_add_non_vtj_birthdate_and_home_municipality.py
@@ -4,20 +4,38 @@
class Migration(migrations.Migration):
-
dependencies = [
- ('applications', '0032_alter_employersummervoucher_target_group'),
+ ("applications", "0032_alter_employersummervoucher_target_group"),
]
operations = [
migrations.AddField(
- model_name='youthapplication',
- name='non_vtj_birthdate',
- field=models.DateField(blank=True, default=None, help_text='Birthdate of person who has no permanent Finnish personal identity code, and thus no data obtainable through the VTJ integration', null=True, verbose_name='non-vtj birthdate'),
+ model_name="youthapplication",
+ name="non_vtj_birthdate",
+ field=models.DateField(
+ blank=True,
+ default=None,
+ help_text=(
+ "Birthdate of person who has no permanent Finnish personal identity"
+ " code, and thus no data obtainable through the VTJ integration"
+ ),
+ null=True,
+ verbose_name="non-vtj birthdate",
+ ),
),
migrations.AddField(
- model_name='youthapplication',
- name='non_vtj_home_municipality',
- field=models.CharField(blank=True, default='', help_text='Home municipality of person who has no permanent Finnish personal identity code, and thus no data obtainable through the VTJ integration', max_length=64, verbose_name='non-vtj home municipality'),
+ model_name="youthapplication",
+ name="non_vtj_home_municipality",
+ field=models.CharField(
+ blank=True,
+ default="",
+ help_text=(
+ "Home municipality of person who has no permanent Finnish personal"
+ " identity code, and thus no data obtainable through the VTJ"
+ " integration"
+ ),
+ max_length=64,
+ verbose_name="non-vtj home municipality",
+ ),
),
]
diff --git a/backend/kesaseteli/applications/migrations/0034_make_social_security_number_optional.py b/backend/kesaseteli/applications/migrations/0034_make_social_security_number_optional.py
index 6cdf50566f..abbf736d11 100644
--- a/backend/kesaseteli/applications/migrations/0034_make_social_security_number_optional.py
+++ b/backend/kesaseteli/applications/migrations/0034_make_social_security_number_optional.py
@@ -1,20 +1,32 @@
# Generated by Django 3.2.23 on 2024-04-16 13:46
-import common.utils
-from django.db import migrations
import encrypted_fields.fields
+from django.db import migrations
+import common.utils
-class Migration(migrations.Migration):
+class Migration(migrations.Migration):
dependencies = [
- ('applications', '0033_add_non_vtj_birthdate_and_home_municipality'),
+ ("applications", "0033_add_non_vtj_birthdate_and_home_municipality"),
]
operations = [
migrations.AlterField(
- model_name='youthapplication',
- name='social_security_number',
- field=encrypted_fields.fields.SearchField(blank=True, db_index=True, encrypted_field_name='encrypted_social_security_number', hash_key='ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669', max_length=66, null=True, validators=[common.utils.validate_optional_finnish_social_security_number]),
+ model_name="youthapplication",
+ name="social_security_number",
+ field=encrypted_fields.fields.SearchField(
+ blank=True,
+ db_index=True,
+ encrypted_field_name="encrypted_social_security_number",
+ hash_key=(
+ "ee235e39ebc238035a6264c063dd829d4b6d2270604b57ee1f463e676ec44669"
+ ),
+ max_length=66,
+ null=True,
+ validators=[
+ common.utils.validate_optional_finnish_social_security_number
+ ],
+ ),
),
]
diff --git a/backend/kesaseteli/applications/migrations/0035_add_youth_application_creator.py b/backend/kesaseteli/applications/migrations/0035_add_youth_application_creator.py
index 88864e0429..95d6d9a5ad 100644
--- a/backend/kesaseteli/applications/migrations/0035_add_youth_application_creator.py
+++ b/backend/kesaseteli/applications/migrations/0035_add_youth_application_creator.py
@@ -1,26 +1,39 @@
# Generated by Django 3.2.23 on 2024-04-19 11:09
+import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
-import django.db.models.deletion
class Migration(migrations.Migration):
-
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('applications', '0034_make_social_security_number_optional'),
+ ("applications", "0034_make_social_security_number_optional"),
]
operations = [
migrations.AddField(
- model_name='youthapplication',
- name='creator',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_youth_applications', to=settings.AUTH_USER_MODEL, verbose_name='creator'),
+ model_name="youthapplication",
+ name="creator",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="created_youth_applications",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="creator",
+ ),
),
migrations.AlterField(
- model_name='youthapplication',
- name='handler',
- field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='handled_youth_applications', to=settings.AUTH_USER_MODEL, verbose_name='handler'),
+ model_name="youthapplication",
+ name="handler",
+ field=models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.SET_NULL,
+ related_name="handled_youth_applications",
+ to=settings.AUTH_USER_MODEL,
+ verbose_name="handler",
+ ),
),
]
diff --git a/backend/kesaseteli/applications/migrations/0036_alter_historicalemployerapplication_options_and_more.py b/backend/kesaseteli/applications/migrations/0036_alter_historicalemployerapplication_options_and_more.py
index 561bdc2865..f46646fb69 100644
--- a/backend/kesaseteli/applications/migrations/0036_alter_historicalemployerapplication_options_and_more.py
+++ b/backend/kesaseteli/applications/migrations/0036_alter_historicalemployerapplication_options_and_more.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("applications", "0035_add_youth_application_creator"),
]
diff --git a/backend/kesaseteli/applications/models.py b/backend/kesaseteli/applications/models.py
index f565e092a8..e8e5525d2e 100644
--- a/backend/kesaseteli/applications/models.py
+++ b/backend/kesaseteli/applications/models.py
@@ -15,7 +15,8 @@
from django.template.loader import get_template
from django.urls import reverse
from django.utils import timezone, translation
-from django.utils.translation import gettext, gettext_lazy as _, pgettext
+from django.utils.translation import gettext, pgettext
+from django.utils.translation import gettext_lazy as _
from encrypted_fields.fields import EncryptedCharField, SearchField
from localflavor.generic.models import IBANField
from requests.exceptions import ReadTimeout
@@ -78,7 +79,7 @@ class Meta:
class YouthApplicationQuerySet(MatchesAnyOfQuerySet, models.QuerySet):
def _active_q_filter(self) -> Q:
"""
- Return Q filter for active youth applications
+ Return Q filter for active youth applications.
"""
return Q(receipt_confirmed_at__isnull=False)
@@ -90,7 +91,8 @@ def _unexpired_q_filter(self) -> Q:
def matches_email_or_social_security_number(self, email, social_security_number):
"""
- Return youth applications that match given email or social security number
+ Return youth applications that match given email or social security
+ number.
"""
return self.matches_any_of(
email=email, social_security_number=social_security_number
@@ -98,43 +100,43 @@ def matches_email_or_social_security_number(self, email, social_security_number)
def expired(self):
"""
- Return youth applications that are expired
+ Return youth applications that are expired.
"""
return self.filter(~self._unexpired_q_filter())
def unexpired(self):
"""
- Return youth applications that are unexpired
+ Return youth applications that are unexpired.
"""
return self.filter(self._unexpired_q_filter())
def unexpired_or_active(self):
"""
- Return youth applications that are unexpired or active
+ Return youth applications that are unexpired or active.
"""
return self.filter(self._unexpired_q_filter() | self._active_q_filter())
def active(self):
"""
- Return active youth applications
+ Return active youth applications.
"""
return self.filter(self._active_q_filter())
def non_rejected(self):
"""
- Return non-rejected youth applications
+ Return non-rejected youth applications.
"""
return self.exclude(status=YouthApplicationStatus.REJECTED.value)
def accepted(self):
"""
- Return accepted youth applications
+ Return accepted youth applications.
"""
return self.filter(status=YouthApplicationStatus.ACCEPTED.value)
def created_this_year(self):
"""
- Return youth applications created this year
+ Return youth applications created this year.
"""
return self.filter(created_at__year=timezone.localdate().year)
@@ -142,12 +144,13 @@ def is_email_or_social_security_number_active_this_year(
self, email, social_security_number
) -> bool:
"""
- Is there an active non-rejected youth application created this year present in
- this queryset that uses the given email and/or social security number?
+ Is there an active non-rejected youth application created this year
+ present in this queryset that uses the given email and/or social
+ security number?
- :return: True if there is at least one active non-rejected youth application
- created this year present in this queryset that uses the given email
- and/or social security number, otherwise False.
+ :return: True if there is at least one active non-rejected youth
+ application created this year present in this queryset that uses
+ the given email and/or social security number, otherwise False.
"""
return (
self.matches_email_or_social_security_number(email, social_security_number)
@@ -159,12 +162,12 @@ def is_email_or_social_security_number_active_this_year(
def is_email_used_this_year(self, email) -> bool:
"""
- Is the given email used by an unexpired non-rejected or active non-rejected
- youth application created this year present in this queryset?
+ Is the given email used by an unexpired non-rejected or active non-
+ rejected youth application created this year present in this queryset?
- :return: True if the given email is used by an unexpired non-rejected or active
- non-rejected youth application created this year present in this
- queryset, otherwise False.
+ :return: True if the given email is used by an unexpired non-rejected
+ or active non-rejected youth application created this year present
+ in this queryset, otherwise False.
"""
return (
self.filter(email=email)
@@ -211,8 +214,8 @@ class YouthApplication(LockForUpdateMixin, TimeStampedModel, UUIDModel):
max_length=64,
verbose_name=_("non-vtj home municipality"),
help_text=_(
- "Home municipality of person who has no permanent Finnish personal identity code, "
- "and thus no data obtainable through the VTJ integration"
+ "Home municipality of person who has no permanent Finnish personal identity"
+ " code, and thus no data obtainable through the VTJ integration"
),
)
school = models.CharField(
@@ -310,7 +313,8 @@ def is_vtj_test_case(self) -> bool:
@property
def vtj_test_case(self) -> str:
"""
- If last name is found in VtjTestCase.values then return it, otherwise return "".
+ If last name is found in VtjTestCase.values then return it, otherwise
+ return "".
"""
for vtj_test_case in VtjTestCase.values:
if are_same_texts(self.last_name, vtj_test_case):
@@ -488,8 +492,8 @@ def _processing_email_message(self, processing_link):
def send_additional_info_request_email(self, request, language) -> bool:
"""
- Send youth application's additional info request email with given language to
- the applicant.
+ Send youth application's additional info request email with given
+ language to the applicant.
:param request: Request used for generating the activation link
:param language: The language to be used in the email
@@ -510,7 +514,8 @@ def send_additional_info_request_email(self, request, language) -> bool:
def send_activation_email(self, request, language) -> bool:
"""
- Send youth application's activation email with given language to the applicant.
+ Send youth application's activation email with given language to the
+ applicant.
:param request: Request used for generating the activation link
:param language: The activation email language to be used
@@ -582,12 +587,13 @@ def _handle(
automatic_handling,
):
"""
- Handle the youth application by setting the status, encrypted_handler_vtj_json,
- handler and handled_at.
+ Handle the youth application by setting the status,
+ encrypted_handler_vtj_json, handler and handled_at.
:param status: The target status
:type status: YouthApplicationStatus
- :param encrypted_handler_vtj_json: The VTJ JSON the handler used for handling
+ :param encrypted_handler_vtj_json: The VTJ JSON the handler used for
+ handling
:type encrypted_handler_vtj_json: str
:param handler: Handler user
:type handler: None | AnonymousUser | User
@@ -603,7 +609,7 @@ def _handle(
@property
def has_youth_summer_voucher(self) -> bool:
try:
- self.youth_summer_voucher
+ _ = self.youth_summer_voucher
except ObjectDoesNotExist:
return False
return True
@@ -642,8 +648,8 @@ def can_accept_manually(self, handler, encrypted_handler_vtj_json) -> bool:
@transaction.atomic
def accept_automatically(self) -> bool:
"""
- Accept this youth application automatically without handler if possible.
- Create related YouthSummerVoucher if changed to accepted.
+ Accept this youth application automatically without handler if
+ possible. Create related YouthSummerVoucher if changed to accepted.
:return: self.is_accepted
"""
@@ -669,8 +675,9 @@ def is_valid_encrypted_handler_vtj_json(cls, encrypted_handler_vtj_json):
@transaction.atomic
def accept_manually(self, handler, encrypted_handler_vtj_json) -> bool:
"""
- Accept this youth application manually using given handler user and handler VTJ
- JSON if possible. Create related YouthSummerVoucher if changed to accepted.
+ Accept this youth application manually using given handler user and
+ handler VTJ JSON if possible. Create related YouthSummerVoucher if
+ changed to accepted.
:return: self.is_accepted
"""
@@ -708,8 +715,8 @@ def can_reject(self, handler, encrypted_handler_vtj_json) -> bool:
@transaction.atomic
def reject(self, handler, encrypted_handler_vtj_json) -> bool:
"""
- Reject youth application using given handler user and handler VTJ JSON if
- possible.
+ Reject youth application using given handler user and handler VTJ JSON
+ if possible.
:return: self.is_rejected
"""
@@ -727,8 +734,8 @@ def reject(self, handler, encrypted_handler_vtj_json) -> bool:
@property
def birthdate(self) -> date:
"""
- Applicant's birthdate based on their social security number,
- or on their provided birthdate through other means as a fallback.
+ Applicant's birthdate based on their social security number, or on
+ their provided birthdate through other means as a fallback.
"""
return (
social_security_number_birthdate(self.social_security_number)
@@ -739,15 +746,17 @@ def birthdate(self) -> date:
@property
def is_9th_grader_age(self) -> bool:
"""
- If applicant's age correct for a ninth grader ("9. luokkalainen" in Finnish)?
+ If applicant's age correct for a ninth grader ("9.
+
+ luokkalainen" in Finnish)?
"""
return (self.created_at.year - self.birthdate.year) == 16 # e.g. 2022 - 2006
@property
def is_upper_secondary_education_1st_year_student_age(self) -> bool:
"""
- If applicant's age correct for an upper secondary education first year student
- ("Toisen asteen ensimmäisen vuoden opiskelija" in Finnish)?
+ If applicant's age correct for an upper secondary education first year
+ student ("Toisen asteen ensimmäisen vuoden opiskelija" in Finnish)?
"""
return (self.created_at.year - self.birthdate.year) == 17 # e.g. 2022 - 2005
@@ -817,11 +826,12 @@ def has_social_security_number(self) -> bool:
@property
def need_additional_info(self) -> bool:
"""
- Does the youth application initially need additional info to be processed?
+ Does the youth application initially need additional info to be
+ processed?
- :return: True if youth application initially needs additional info be processed,
- otherwise False. Note that this value does NOT change based on whether
- additional info has been provided or not.
+ :return: True if youth application initially needs additional info be
+ processed, otherwise False. Note that this value does NOT change
+ based on whether additional info has been provided or not.
"""
return (
settings.NEXT_PUBLIC_DISABLE_VTJ
@@ -856,9 +866,11 @@ def set_additional_info(
self, additional_info_user_reasons, additional_info_description
):
"""
- Sets additional_info_user_reasons and additional_info_description to given
- values, status to YouthApplicationStatus.ADDITIONAL_INFORMATION_PROVIDED,
- additional_info_provided_at to current time and saves the youth application.
+ Sets additional_info_user_reasons and additional_info_description to
+ given values, status to
+ YouthApplicationStatus.ADDITIONAL_INFORMATION_PROVIDED,
+ additional_info_provided_at to current time and saves the youth
+ application.
"""
self.additional_info_provided_at = timezone.now()
self.additional_info_user_reasons = additional_info_user_reasons
@@ -958,7 +970,7 @@ def helsinki_logo(self, language) -> MIMEImage:
@staticmethod
def _value_with_euro_sign(value_in_euros: int) -> str:
"""
- Given value with euro sign
+ Given value with euro sign.
Example:
_value_with_euro_sign(350) -> "350€" with Finnish translation active
@@ -971,28 +983,28 @@ def _value_with_euro_sign(value_in_euros: int) -> str:
@staticmethod
def voucher_value_in_euros_in_year(year: int) -> int:
"""
- Voucher value in euros in given year
+ Voucher value in euros in given year.
"""
return 325 if year < 2024 else 350
@property
def voucher_value_in_euros(self) -> int:
"""
- Voucher value in euros in youth summer voucher's year
+ Voucher value in euros in youth summer voucher's year.
"""
return YouthSummerVoucher.voucher_value_in_euros_in_year(self.year)
@property
def voucher_value_with_euro_sign(self) -> str:
"""
- Voucher value with euro sign in youth summer voucher's year
+ Voucher value with euro sign in youth summer voucher's year.
"""
return self._value_with_euro_sign(self.voucher_value_in_euros)
@property
def summer_job_period_localized_string(self) -> str:
"""
- Summer job period as a string
+ Summer job period as a string.
"""
return pgettext(
"Summer job period in youth summer voucher email (d.m.–d.m.y)",
@@ -1002,31 +1014,33 @@ def summer_job_period_localized_string(self) -> str:
@property
def employer_summer_voucher_application_end_date_localized_string(self) -> str:
"""
- Employer summer voucher application end date as a localized string
+ Employer summer voucher application end date as a localized string.
"""
return pgettext(
- "Employer summer voucher application end date in youth summer voucher email (d.m.y)",
+ "Employer summer voucher application end date in youth summer voucher email"
+ " (d.m.y)",
"30.11.%(year)d",
) % {"year": self.year}
@property
def min_work_hours(self) -> int:
"""
- Minimum work hours for summer job in youth summer voucher's year
+ Minimum work hours for summer job in youth summer voucher's year.
"""
return 60
@staticmethod
def min_work_compensation_in_euros_in_year(year: int) -> int:
"""
- Minimum work compensation for summer job in euros in given year
+ Minimum work compensation for summer job in euros in given year.
"""
return 400 if year < 2024 else 500
@property
def min_work_compensation_in_euros(self) -> int:
"""
- Minimum work compensation for summer job in euros in youth summer voucher's year
+ Minimum work compensation for summer job in euros in youth summer
+ voucher's year.
"""
return YouthSummerVoucher.min_work_compensation_in_euros_in_year(self.year)
@@ -1034,7 +1048,7 @@ def min_work_compensation_in_euros(self) -> int:
def min_work_compensation_with_euro_sign(self) -> str:
"""
Minimum work compensation for summer job with euro sign in youth summer
- voucher's year
+ voucher's year.
"""
return self._value_with_euro_sign(self.min_work_compensation_in_euros)
@@ -1066,12 +1080,16 @@ def send_youth_summer_voucher_email(
"email": self.youth_application.email,
"year": self.year,
"voucher_value_with_euro_sign": self.voucher_value_with_euro_sign,
- "summer_job_period_localized_string": self.summer_job_period_localized_string,
+ "summer_job_period_localized_string": (
+ self.summer_job_period_localized_string
+ ),
"employer_summer_voucher_application_end_date_localized_string": (
self.employer_summer_voucher_application_end_date_localized_string
),
"min_work_hours": self.min_work_hours,
- "min_work_compensation_with_euro_sign": self.min_work_compensation_with_euro_sign,
+ "min_work_compensation_with_euro_sign": (
+ self.min_work_compensation_with_euro_sign
+ ),
}
return send_mail_with_error_logging(
subject=self.email_subject(language),
@@ -1300,7 +1318,7 @@ class Meta:
class Attachment(UUIDModel, TimeStampedModel):
"""
- created_at field from TimeStampedModel provides the upload timestamp
+ created_at field from TimeStampedModel provides the upload timestamp.
"""
summer_voucher = models.ForeignKey(
diff --git a/backend/kesaseteli/applications/tests/data/mock_vtj.py b/backend/kesaseteli/applications/tests/data/mock_vtj.py
index 882c673c3e..a5529f3b1e 100644
--- a/backend/kesaseteli/applications/tests/data/mock_vtj.py
+++ b/backend/kesaseteli/applications/tests/data/mock_vtj.py
@@ -14,8 +14,8 @@
def mock_vtj_person_id_query_not_found_content(**kwargs) -> str:
"""
- Mock VTJ person's ID query's (i.e. henkilön tunnuskysely in Finnish) result content
- when no data is found.
+ Mock VTJ person's ID query's (i.e. henkilön tunnuskysely in Finnish) result
+ content when no data is found.
:param kwargs: Keyword arguments to add or override values in result
@@ -37,8 +37,8 @@ def mock_vtj_person_id_query_found_content(
is_home_municipality_helsinki: bool,
) -> str:
"""
- Mock VTJ person's ID query's (i.e. henkilön tunnuskysely in Finnish) result content
- when data is found.
+ Mock VTJ person's ID query's (i.e. henkilön tunnuskysely in Finnish) result
+ content when data is found.
Endpoint: /api/HenkilonTunnuskysely
"""
@@ -57,7 +57,9 @@ def mock_vtj_person_id_query_found_content(
"@sanomatunnus": "PERUSSANOMA 1",
"@tietojenPoimintaaika": "20220407090800",
"@versio": "1.0",
- "@xsi:schemaLocation": "http://xml.vrk.fi/schema/vtjkysely PERUSSANOMA 1.xsd",
+ "@xsi:schemaLocation": (
+ "http://xml.vrk.fi/schema/vtjkysely PERUSSANOMA 1.xsd"
+ ),
"Asiakasinfo": {
"InfoS": "07.04.2022 09:08",
"InfoR": "07.04.2022 09:08",
diff --git a/backend/kesaseteli/applications/tests/test_application_validation.py b/backend/kesaseteli/applications/tests/test_application_validation.py
index 840a5928e2..806eb23f30 100644
--- a/backend/kesaseteli/applications/tests/test_application_validation.py
+++ b/backend/kesaseteli/applications/tests/test_application_validation.py
@@ -96,12 +96,17 @@ def test_validate_name_with_invalid_unlisted_school(name):
# EmployerApplicationStatus.ADDITIONAL_INFORMATION_REQUESTED,
# 200,
# ),
- # (EmployerApplicationStatus.SUBMITTED, EmployerApplicationStatus.ACCEPTED, 200),
- # (EmployerApplicationStatus.SUBMITTED, EmployerApplicationStatus.REJECTED, 200),
- # (EmployerApplicationStatus.SUBMITTED, EmployerApplicationStatus.DELETED_BY_CUSTOMER, 200),
+ # (EmployerApplicationStatus.SUBMITTED, EmployerApplicationStatus.ACCEPTED,
+ # 200),
+ # (EmployerApplicationStatus.SUBMITTED, EmployerApplicationStatus.REJECTED,
+ # 200),
+ # (EmployerApplicationStatus.SUBMITTED,
+ # EmployerApplicationStatus.DELETED_BY_CUSTOMER, 200),
# (EmployerApplicationStatus.SUBMITTED, EmployerApplicationStatus.DRAFT, 400),
- # (EmployerApplicationStatus.ACCEPTED, EmployerApplicationStatus.SUBMITTED, 400),
- # (EmployerApplicationStatus.DELETED_BY_CUSTOMER, EmployerApplicationStatus.ACCEPTED, 400),
+ # (EmployerApplicationStatus.ACCEPTED, EmployerApplicationStatus.SUBMITTED,
+ # 400),
+ # (EmployerApplicationStatus.DELETED_BY_CUSTOMER,
+ # EmployerApplicationStatus.ACCEPTED, 400),
# (EmployerApplicationStatus.REJECTED, EmployerApplicationStatus.DRAFT, 400),
],
)
diff --git a/backend/kesaseteli/applications/tests/test_attachments_api.py b/backend/kesaseteli/applications/tests/test_attachments_api.py
index c3b5771579..9bdfef3708 100644
--- a/backend/kesaseteli/applications/tests/test_attachments_api.py
+++ b/backend/kesaseteli/applications/tests/test_attachments_api.py
@@ -136,7 +136,7 @@ def test_attachment_upload_invalid_status(
@pytest.mark.django_db
def test_too_many_attachments(request, api_client, summer_voucher):
- for idx, _ in enumerate(range(AttachmentSerializer.MAX_ATTACHMENTS_PER_TYPE)):
+ for _ in range(AttachmentSerializer.MAX_ATTACHMENTS_PER_TYPE):
response = _upload_file(
request,
api_client,
diff --git a/backend/kesaseteli/applications/tests/test_excel_export.py b/backend/kesaseteli/applications/tests/test_excel_export.py
index 783a782754..0c55d20f7e 100644
--- a/backend/kesaseteli/applications/tests/test_excel_export.py
+++ b/backend/kesaseteli/applications/tests/test_excel_export.py
@@ -192,7 +192,8 @@ def test_excel_download_writes_audit_log(
staff_client, download_url, expected_audit_log_additional_information
):
"""
- Test that audit log is written when downloading employer summer voucher Excel files.
+ Test that audit log is written when downloading employer summer voucher
+ Excel files.
NOTE:
Tested values MAY NEED UPDATING when audit logging is added to the endpoint!
@@ -350,9 +351,9 @@ def employer_summer_voucher_sorting_key(voucher: EmployerSummerVoucher):
else:
query = EmployerSummerVoucher.objects.filter(pk=voucher.pk)
values_tuple = query.values_list(*excel_field.model_fields)[0]
- assert (
- output_column.value == excel_field.value % values_tuple
- ), excel_field.title
+ assert output_column.value == excel_field.value % values_tuple, (
+ excel_field.title
+ )
@pytest.mark.django_db
diff --git a/backend/kesaseteli/applications/tests/test_mock_vtj.py b/backend/kesaseteli/applications/tests/test_mock_vtj.py
index 7c636115e4..f59b9723f6 100644
--- a/backend/kesaseteli/applications/tests/test_mock_vtj.py
+++ b/backend/kesaseteli/applications/tests/test_mock_vtj.py
@@ -12,7 +12,7 @@
def get_jsonpath_matches(jsonpath_expression, json_data) -> list:
"""
- Get matching values from JSON data using JSONPath expression
+ Get matching values from JSON data using JSONPath expression.
"""
return [
match.value for match in jsonpath_ng.parse(jsonpath_expression).find(json_data)
diff --git a/backend/kesaseteli/applications/tests/test_models.py b/backend/kesaseteli/applications/tests/test_models.py
index b7be0bb6d0..127bf4657c 100644
--- a/backend/kesaseteli/applications/tests/test_models.py
+++ b/backend/kesaseteli/applications/tests/test_models.py
@@ -33,7 +33,7 @@ def _get_email_template_image_file(image_name: str) -> bytes:
def create_test_employer_summer_vouchers(year) -> List[EmployerSummerVoucher]:
"""
- Create EmployerSummerVouchers for given year sorted by last_submitted_at
+ Create EmployerSummerVouchers for given year sorted by last_submitted_at.
"""
vouchers: List[EmployerSummerVoucher] = []
for created_at, last_submitted_at_list, attachment_count in [
@@ -84,7 +84,7 @@ def create_test_employer_summer_vouchers(year) -> List[EmployerSummerVoucher]:
@pytest.mark.parametrize("year", [2021, 2022])
def test_employer_summer_voucher_last_submitted_at(year):
"""
- Test EmployerSummerVoucher instances' last_submitted_at property
+ Test EmployerSummerVoucher instances' last_submitted_at property.
"""
vouchers = create_test_employer_summer_vouchers(year=year)
@@ -108,10 +108,8 @@ def test_employer_summer_voucher_last_submitted_at(year):
def test_youth_summer_voucher_get_last_used_serial_number():
assert YouthSummerVoucher.objects.count() == 0
assert YouthSummerVoucher.get_last_used_serial_number() is None
- for ordinal_number in range(1, 10):
- summer_voucher = (
- AwaitingManualProcessingYouthApplicationFactory().create_youth_summer_voucher()
- )
+ for _ in range(1, 10):
+ summer_voucher = AwaitingManualProcessingYouthApplicationFactory().create_youth_summer_voucher()
assert YouthSummerVoucher.get_last_used_serial_number() is not None
assert (
YouthSummerVoucher.get_last_used_serial_number()
@@ -135,9 +133,7 @@ def test_youth_summer_voucher_first_serial_number():
def test_youth_summer_voucher_sequentiality():
assert YouthSummerVoucher.objects.count() == 0
for ordinal_number in range(1, 10):
- summer_voucher = (
- AwaitingManualProcessingYouthApplicationFactory().create_youth_summer_voucher()
- )
+ summer_voucher = AwaitingManualProcessingYouthApplicationFactory().create_youth_summer_voucher()
assert YouthSummerVoucher.objects.count() == ordinal_number
assert YouthSummerVoucher.objects.last() == summer_voucher
assert summer_voucher.summer_voucher_serial_number == ordinal_number
@@ -259,7 +255,7 @@ def test_youth_summer_voucher_sequentiality_complex_transaction_nesting():
assert YouthSummerVoucher.objects.count() == 0
def create_youth_summer_vouchers(count: int):
- for i in range(count):
+ for _ in range(count):
AwaitingManualProcessingYouthApplicationFactory().create_youth_summer_voucher()
create_youth_summer_vouchers(count=1)
diff --git a/backend/kesaseteli/applications/tests/test_querying.py b/backend/kesaseteli/applications/tests/test_querying.py
index 0728d0e677..96a7d40761 100644
--- a/backend/kesaseteli/applications/tests/test_querying.py
+++ b/backend/kesaseteli/applications/tests/test_querying.py
@@ -162,18 +162,18 @@ def test_youth_application_query_set_unexpired_or_active(
YouthApplication.objects.unexpired_or_active().values_list("pk", flat=True)
)
- assert len(unexpired_or_active_pks) == len(
- set(unexpired_or_active_pks)
- ), "unexpired_or_active() gave duplicates"
+ assert len(unexpired_or_active_pks) == len(set(unexpired_or_active_pks)), (
+ "unexpired_or_active() gave duplicates"
+ )
for app, expected_unexpired_or_active in zip(
apps, expected_unexpired_or_active_list
):
unexpired_or_active = app.pk in unexpired_or_active_pks
- assert (
- unexpired_or_active == expected_unexpired_or_active
- ), unexpired_or_active_error_message(
- app, is_active, expected_unexpired_or_active
+ assert unexpired_or_active == expected_unexpired_or_active, (
+ unexpired_or_active_error_message(
+ app, is_active, expected_unexpired_or_active
+ )
)
@@ -203,9 +203,9 @@ def test_youth_application_query_set_matches_email_or_social_security_number(
email=email, social_security_number=ssn
).values_list("pk", flat=True)
- assert len(matched_pks) == len(
- set(matched_pks)
- ), "matches_email_or_social_security_number() gave duplicates"
+ assert len(matched_pks) == len(set(matched_pks)), (
+ "matches_email_or_social_security_number() gave duplicates"
+ )
for app in apps:
assert (app.pk in matched_pks) == (
diff --git a/backend/kesaseteli/applications/tests/test_security_with_anonymous_user.py b/backend/kesaseteli/applications/tests/test_security_with_anonymous_user.py
index 655b881607..6c89b429ab 100644
--- a/backend/kesaseteli/applications/tests/test_security_with_anonymous_user.py
+++ b/backend/kesaseteli/applications/tests/test_security_with_anonymous_user.py
@@ -57,9 +57,9 @@ def test_company_forbidden_to_anonymous_user(client, company):
@pytest.mark.django_db
def test_youth_application_status_openly_accessible_to_anonymous_user(client):
"""
- Test that youth application's status endpoint is openly accessible to anonymous
- users and returns only the single queried youth application's status and nothing
- else.
+ Test that youth application's status endpoint is openly accessible to
+ anonymous users and returns only the single queried youth application's
+ status and nothing else.
NOTE:
The youth application's status endpoint is open to everyone and can be used to
@@ -83,8 +83,8 @@ def test_youth_application_status_openly_accessible_to_anonymous_user(client):
@pytest.mark.django_db
def test_youth_applications_list_get_method_not_allowed_to_anonymous_user(client):
"""
- Test that using GET on youth applications' list endpoint returns method not allowed
- to anonymous users.
+ Test that using GET on youth applications' list endpoint returns method not
+ allowed to anonymous users.
"""
list_url = reverse("v1:youthapplication-list")
response = client.get(list_url, headers=HEADERS_ACCEPT_APPLICATION_JSON)
@@ -103,12 +103,15 @@ def test_api_root_get_forbidden_to_anonymous_user(client):
api_root_url = reverse("v1:api-root")
response = client.get(api_root_url, headers=HEADERS_ACCEPT_APPLICATION_JSON)
assert response.status_code == status.HTTP_403_FORBIDDEN
- assert response.data == {
- "detail": ErrorDetail(
- string="Autentikaatiotunnuksia ei annettu.", # Default server language is Finnish
- code="not_authenticated",
- )
- }
+ assert (
+ response.data
+ == {
+ "detail": ErrorDetail(
+ string="Autentikaatiotunnuksia ei annettu.", # Default server language is Finnish
+ code="not_authenticated",
+ )
+ }
+ )
assert isinstance(response.accepted_renderer, JSONRenderer)
assert response.wsgi_request.user.is_anonymous
@@ -119,8 +122,8 @@ def test_youth_application_fetch_employee_data_get_method_not_allowed_to_anonymo
client,
):
"""
- Test that using GET on youth application's fetch_employee_data endpoint returns
- method not allowed to anonymous users.
+ Test that using GET on youth application's fetch_employee_data endpoint
+ returns method not allowed to anonymous users.
"""
url = reverse("v1:youthapplication-fetch-employee-data")
response = client.get(url, headers=HEADERS_ACCEPT_APPLICATION_JSON)
@@ -170,8 +173,8 @@ def test_youth_application_create_without_ssn_get_method_not_allowed_to_anonymou
client,
):
"""
- Test that using GET on youth application's create_without_ssn endpoint returns
- method not allowed to anonymous users.
+ Test that using GET on youth application's create_without_ssn endpoint
+ returns method not allowed to anonymous users.
"""
url = reverse("v1:youthapplication-create-without-ssn")
response = client.get(url, headers=HEADERS_ACCEPT_APPLICATION_JSON)
@@ -230,7 +233,8 @@ def test_not_acceptable_response_to_anonymous_user_requesting_html_from_endpoint
):
"""
Test that endpoints return 406 Not Acceptable response to anonymous user
- when asking for HTML type response (i.e. request header's "Accept" is "text/html").
+ when asking for HTML type response (i.e. request header's "Accept" is
+ "text/html").
"""
response = client.generic(
method=method,
@@ -238,12 +242,15 @@ def test_not_acceptable_response_to_anonymous_user_requesting_html_from_endpoint
headers={"Accept": "text/html"},
)
assert response.status_code == status.HTTP_406_NOT_ACCEPTABLE
- assert response.data == {
- "detail": ErrorDetail(
- string="Ei voitu vastata pyynnön Accept-otsakkeen mukaisesti.", # Default server language is Finnish
- code="not_acceptable",
- ),
- }
+ assert (
+ response.data
+ == {
+ "detail": ErrorDetail(
+ string="Ei voitu vastata pyynnön Accept-otsakkeen mukaisesti.", # Default server language is Finnish
+ code="not_acceptable",
+ ),
+ }
+ )
assert response.content == b"" or json.loads(response.content.decode("utf-8")) == {
"detail": "Ei voitu vastata pyynnön Accept-otsakkeen mukaisesti."
}
diff --git a/backend/kesaseteli/applications/tests/test_security_with_non_staff_user.py b/backend/kesaseteli/applications/tests/test_security_with_non_staff_user.py
index 4032dda735..20963a00e0 100644
--- a/backend/kesaseteli/applications/tests/test_security_with_non_staff_user.py
+++ b/backend/kesaseteli/applications/tests/test_security_with_non_staff_user.py
@@ -34,13 +34,15 @@ def create_attachment(
user: User, company: Company, status: EmployerApplicationStatus
) -> Attachment:
"""
- Create an attachment with an employer summer voucher and employer application.
+ Create an attachment with an employer summer voucher and employer
+ application.
- Refresh the attachment, employer summer voucher and employer application from
- database to ensure that the data is up to date.
+ Refresh the attachment, employer summer voucher and employer application
+ from database to ensure that the data is up to date.
- :return: Attachment that has an employer summer voucher and employer application.
- The employer application has the given user, company and status.
+ :return: Attachment that has an employer summer voucher and employer
+ application. The employer application has the given user, company and
+ status.
"""
result = AttachmentFactory(
summer_voucher=EmployerSummerVoucherFactory(
@@ -71,8 +73,9 @@ def test_employer_application_list_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer application list endpoint returns draft and submitted
- employer applications but only those that are the user's and use the user's company.
+ Test that the employer application list endpoint returns draft and
+ submitted employer applications but only those that are the user's and use
+ the user's company.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -113,8 +116,9 @@ def test_employer_application_detail_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer application detail endpoint returns draft and submitted
- employer applications but only those that are the user's and use the user's company.
+ Test that the employer application detail endpoint returns draft and
+ submitted employer applications but only those that are the user's and use
+ the user's company.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -172,9 +176,9 @@ def test_employer_summer_voucher_handle_attachment_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer summer voucher's handle attachment endpoint returns draft and
- submitted employer applications' attachments but only those that are the user's and
- use the user's company.
+ Test that the employer summer voucher's handle attachment endpoint returns
+ draft and submitted employer applications' attachments but only those that
+ are the user's and use the user's company.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -240,9 +244,9 @@ def test_employer_summer_voucher_handle_attachment_non_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer summer voucher's handle attachment endpoint doesn't return
- any attachments that are connected to an employer application which is neither a
- draft nor submitted.
+ Test that the employer summer voucher's handle attachment endpoint doesn't
+ return any attachments that are connected to an employer application which
+ is neither a draft nor submitted.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -295,9 +299,9 @@ def get_attachment(client: Client, attachment: Attachment):
@pytest.mark.django_db
def test_employer_summer_voucher_handle_attachment_delete_draft():
"""
- Test that the employer summer voucher's handle attachment endpoint can be used to
- delete draft employer applications' attachments but only those that are the user's
- and use the user's company.
+ Test that the employer summer voucher's handle attachment endpoint can be
+ used to delete draft employer applications' attachments but only those that
+ are the user's and use the user's company.
"""
application_status = EmployerApplicationStatus.DRAFT
user1, user2 = UserFactory.create_batch(size=2)
@@ -361,9 +365,9 @@ def del_attachment(client: Client, attachment: Attachment):
@pytest.mark.django_db
def test_employer_summer_voucher_handle_attachment_delete_submitted():
"""
- Test that the employer summer voucher's handle attachment endpoint can not be used
- to delete submitted employer applications' attachments at all, not the user's and
- the user's company's nor anyone else's.
+ Test that the employer summer voucher's handle attachment endpoint can not
+ be used to delete submitted employer applications' attachments at all, not
+ the user's and the user's company's nor anyone else's.
"""
application_status = EmployerApplicationStatus.SUBMITTED
user1, user2 = UserFactory.create_batch(size=2)
@@ -430,9 +434,9 @@ def test_employer_summer_voucher_handle_attachment_delete_non_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer summer voucher's handle attachment endpoint can't be used to
- delete any attachments that are connected to an employer application which is
- neither a draft nor submitted.
+ Test that the employer summer voucher's handle attachment endpoint can't be
+ used to delete any attachments that are connected to an employer
+ application which is neither a draft nor submitted.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -488,8 +492,8 @@ def test_employer_summer_voucher_handle_attachment_unallowed_methods(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer summer voucher's handle attachment endpoint doesn't allow
- HTTP methods patch, post and put.
+ Test that the employer summer voucher's handle attachment endpoint doesn't
+ allow HTTP methods patch, post and put.
"""
user = UserFactory()
company = CompanyFactory()
@@ -515,8 +519,8 @@ def test_employer_summer_voucher_post_attachment_unallowed_methods(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer summer voucher's post attachment endpoint doesn't allow
- HTTP methods delete, get, patch and put.
+ Test that the employer summer voucher's post attachment endpoint doesn't
+ allow HTTP methods delete, get, patch and put.
"""
user = UserFactory()
company = CompanyFactory()
@@ -540,8 +544,8 @@ def test_employer_summer_voucher_detail_unallowed_methods(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer summer voucher detail endpoint doesn't allow HTTP methods
- delete, get, patch, post and put.
+ Test that the employer summer voucher detail endpoint doesn't allow HTTP
+ methods delete, get, patch, post and put.
"""
user = UserFactory()
company = CompanyFactory()
@@ -574,8 +578,8 @@ def test_employer_application_list_non_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer application list endpoint doesn't return any employer
- applications at all for statuses that are not draft or submitted.
+ Test that the employer application list endpoint doesn't return any
+ employer applications at all for statuses that are not draft or submitted.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -588,7 +592,7 @@ def test_employer_application_list_non_viewable_statuses(
user2_company1_attachment = create_attachment(user2, company1, application_status)
user2_company2_attachment = create_attachment(user2, company2, application_status)
- for user, client, company, attachment in [
+ for _user, client, company, _attachment in [
(user1, user1_client, company1, user1_company1_attachment),
(user1, user1_client, company2, user1_company2_attachment),
(user2, user2_client, company1, user2_company1_attachment),
@@ -616,8 +620,8 @@ def test_employer_application_detail_non_viewable_statuses(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer application detail endpoint doesn't return any employer
- applications at all for statuses that are not draft or submitted.
+ Test that the employer application detail endpoint doesn't return any
+ employer applications at all for statuses that are not draft or submitted.
"""
user1, user2 = UserFactory.create_batch(size=2)
user1_client = force_login_user(user1)
@@ -667,8 +671,8 @@ def test_employer_application_list_unallowed_methods(
user_client,
):
"""
- Test that the employer application list endpoint doesn't allow HTTP methods delete,
- patch and put.
+ Test that the employer application list endpoint doesn't allow HTTP methods
+ delete, patch and put.
"""
url = reverse("v1:employerapplication-list")
assert user_client.delete(url).status_code == status.HTTP_405_METHOD_NOT_ALLOWED
@@ -683,8 +687,8 @@ def test_employer_application_detail_unallowed_methods(
application_status: EmployerApplicationStatus,
):
"""
- Test that the employer application detail endpoint doesn't allow HTTP methods delete
- and post.
+ Test that the employer application detail endpoint doesn't allow HTTP
+ methods delete and post.
"""
user = UserFactory()
company = CompanyFactory()
@@ -702,8 +706,8 @@ def test_employer_application_detail_unallowed_methods(
"excel_download_url",
[
reverse("excel-download"),
- f'{reverse("excel-download")}?download=annual',
- f'{reverse("excel-download")}?download=unhandled',
+ f"{reverse('excel-download')}?download=annual",
+ f"{reverse('excel-download')}?download=unhandled",
reverse("youth-excel-download"),
],
)
@@ -725,8 +729,8 @@ def test_youth_application_list_unallowed_methods(
user_client,
):
"""
- Test that the youth application list endpoint doesn't allow HTTP methods delete,
- get, patch and put.
+ Test that the youth application list endpoint doesn't allow HTTP methods
+ delete, get, patch and put.
"""
url = reverse("v1:youthapplication-list")
assert user_client.delete(url).status_code == status.HTTP_405_METHOD_NOT_ALLOWED
@@ -739,7 +743,8 @@ def test_youth_application_list_unallowed_methods(
@pytest.mark.django_db
def test_youth_application_list_empty_post(user_client):
"""
- Test that an empty post to youth application list endpoint results in a bad request.
+ Test that an empty post to youth application list endpoint results in a bad
+ request.
"""
response = user_client.post(reverse("v1:youthapplication-list"))
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -755,8 +760,8 @@ def test_youth_application_list_empty_post(user_client):
@pytest.mark.django_db
def test_youth_application_list_valid_post(user_client):
"""
- Test that a valid post request to the youth application list endpoint creates a new
- youth application and only returns its ID and nothing else.
+ Test that a valid post request to the youth application list endpoint
+ creates a new youth application and only returns its ID and nothing else.
"""
list_url = reverse("v1:youthapplication-list")
@@ -811,8 +816,8 @@ def test_employer_summer_voucher_list_unallowed_methods(
user_client,
):
"""
- Test that the employer summer voucher list endpoint doesn't allow HTTP methods
- delete, get, patch, post and put.
+ Test that the employer summer voucher list endpoint doesn't allow HTTP
+ methods delete, get, patch, post and put.
"""
url = reverse("v1:employersummervoucher-list")
assert user_client.delete(url).status_code == status.HTTP_405_METHOD_NOT_ALLOWED
@@ -839,9 +844,9 @@ def test_school_list_openly_accessible_to_non_staff_user(user_client):
@pytest.mark.django_db
def test_company_openly_accessible_to_non_staff_user(user_client):
"""
- Test that the company endpoint is openly accessible to non-staff users and that it
- returns the business ID, city, company form, ID, industry, name, postcode and street
- address of the company and nothing else.
+ Test that the company endpoint is openly accessible to non-staff users and
+ that it returns the business ID, city, company form, ID, industry, name,
+ postcode and street address of the company and nothing else.
NOTE:
Any company's information can be queried by any non-staff user through this
@@ -882,7 +887,8 @@ def test_youth_application_accept_patch_redirect_to_forbidden_page(
user_client, application_status
):
"""
- Test that youth application accept endpoint using patch redirects to forbidden page.
+ Test that youth application accept endpoint using patch redirects to
+ forbidden page.
"""
application = YouthApplicationFactory(status=application_status)
accept_url = reverse("v1:youthapplication-accept", kwargs={"pk": application.id})
@@ -896,8 +902,8 @@ def test_youth_application_accept_patch_redirect_to_forbidden_page(
@pytest.mark.parametrize("application_status", YouthApplicationStatus.values)
def test_youth_application_accept_unallowed_methods(user_client, application_status):
"""
- Test that youth application accept endpoint doesn't allow HTTP methods delete, get,
- post and put.
+ Test that youth application accept endpoint doesn't allow HTTP methods
+ delete, get, post and put.
"""
application = YouthApplicationFactory(status=application_status)
url = reverse("v1:youthapplication-accept", kwargs={"pk": application.id})
@@ -914,7 +920,8 @@ def test_youth_application_reject_patch_redirect_to_forbidden_page(
user_client, application_status
):
"""
- Test that youth application reject endpoint using patch redirects to forbidden page.
+ Test that youth application reject endpoint using patch redirects to
+ forbidden page.
"""
application = YouthApplicationFactory(status=application_status)
reject_url = reverse("v1:youthapplication-reject", kwargs={"pk": application.id})
@@ -928,8 +935,8 @@ def test_youth_application_reject_patch_redirect_to_forbidden_page(
@pytest.mark.parametrize("application_status", YouthApplicationStatus.values)
def test_youth_application_reject_unallowed_methods(user_client, application_status):
"""
- Test that youth application reject endpoint doesn't allow HTTP methods delete, get,
- post and put.
+ Test that youth application reject endpoint doesn't allow HTTP methods
+ delete, get, post and put.
"""
application = YouthApplicationFactory(status=application_status)
url = reverse("v1:youthapplication-reject", kwargs={"pk": application.id})
@@ -943,9 +950,9 @@ def test_youth_application_reject_unallowed_methods(user_client, application_sta
@pytest.mark.django_db
def test_youth_application_status_openly_accessible_to_non_staff_user(user_client):
"""
- Test that youth application's status endpoint is openly accessible to non-staff
- users and returns only the single queried youth application's status and nothing
- else.
+ Test that youth application's status endpoint is openly accessible to non-
+ staff users and returns only the single queried youth application's status
+ and nothing else.
NOTE:
The youth application's status endpoint is open to everyone and can be used to
@@ -969,7 +976,8 @@ def test_youth_application_detail_redirect_to_forbidden_page(
user_client, youth_application
):
"""
- Test that youth application detail endpoint using get redirects to forbidden page.
+ Test that youth application detail endpoint using get redirects to
+ forbidden page.
"""
detail_url = reverse(
"v1:youthapplication-detail", kwargs={"pk": youth_application.id}
@@ -983,8 +991,8 @@ def test_youth_application_detail_redirect_to_forbidden_page(
@pytest.mark.django_db
def test_youth_application_detail_unallowed_methods(user_client, youth_application):
"""
- Test that youth application's detail endpoint doesn't allow HTTP methods delete,
- patch, post and put.
+ Test that youth application's detail endpoint doesn't allow HTTP methods
+ delete, patch, post and put.
"""
url = reverse("v1:youthapplication-detail", kwargs={"pk": youth_application.id})
assert user_client.delete(url).status_code == status.HTTP_405_METHOD_NOT_ALLOWED
@@ -1001,8 +1009,8 @@ def test_youth_application_activate_expired(
make_youth_application_activation_link_expired,
):
"""
- Test that youth application's activate endpoint redirects to expired page if the
- youth application has expired.
+ Test that youth application's activate endpoint redirects to expired page
+ if the youth application has expired.
"""
activate_url = reverse(
"v1:youthapplication-activate", kwargs={"pk": inactive_youth_application.id}
@@ -1024,8 +1032,8 @@ def test_youth_application_activate_need_additional_info(
make_youth_application_activation_link_unexpired,
):
"""
- Test that youth application's activate endpoint redirects to additional information
- page if additional information is required.
+ Test that youth application's activate endpoint redirects to additional
+ information page if additional information is required.
"""
app = InactiveNeedAdditionalInfoYouthApplicationFactory()
activate_url = reverse("v1:youthapplication-activate", kwargs={"pk": app.id})
@@ -1046,8 +1054,8 @@ def test_youth_application_activate_automatically_acceptable(
make_youth_application_activation_link_unexpired,
):
"""
- Test that youth application's activate endpoint redirects to accepted page if youth
- application is automatically accepted.
+ Test that youth application's activate endpoint redirects to accepted page
+ if youth application is automatically accepted.
"""
app = InactiveNoNeedAdditionalInfoYouthApplicationFactory()
activate_url = reverse("v1:youthapplication-activate", kwargs={"pk": app.id})
@@ -1062,7 +1070,8 @@ def test_youth_application_process_redirect_to_forbidden_page(
user_client, youth_application
):
"""
- Test that youth application process endpoint using get redirects to forbidden page.
+ Test that youth application process endpoint using get redirects to
+ forbidden page.
"""
process_url = reverse(
"v1:youthapplication-process", kwargs={"pk": youth_application.id}
@@ -1076,8 +1085,8 @@ def test_youth_application_process_redirect_to_forbidden_page(
@pytest.mark.django_db
def test_youth_application_process_unallowed_methods(user_client, youth_application):
"""
- Test that youth application's process endpoint doesn't allow HTTP methods delete,
- patch, post and put.
+ Test that youth application's process endpoint doesn't allow HTTP methods
+ delete, patch, post and put.
"""
url = reverse("v1:youthapplication-process", kwargs={"pk": youth_application.id})
assert user_client.delete(url).status_code == status.HTTP_405_METHOD_NOT_ALLOWED
@@ -1092,8 +1101,8 @@ def test_youth_application_additional_info_unallowed_methods(
user_client, youth_application
):
"""
- Test that youth application's additional info endpoint doesn't allow HTTP methods
- delete, get, patch and put.
+ Test that youth application's additional info endpoint doesn't allow HTTP
+ methods delete, get, patch and put.
"""
url = reverse(
"v1:youthapplication-additional-info", kwargs={"pk": youth_application.id}
@@ -1108,8 +1117,8 @@ def test_youth_application_additional_info_unallowed_methods(
@pytest.mark.django_db
def test_youth_application_additional_info_empty_post(user_client):
"""
- Test that an empty post to youth application's additional info endpoint results in a
- bad request.
+ Test that an empty post to youth application's additional info endpoint
+ results in a bad request.
"""
app = AdditionalInfoRequestedYouthApplicationFactory()
url = reverse("v1:youthapplication-additional-info", kwargs={"pk": app.id})
@@ -1120,8 +1129,8 @@ def test_youth_application_additional_info_empty_post(user_client):
@pytest.mark.django_db
def test_youth_application_additional_info_valid_post(user_client):
"""
- Test that a valid post to the additional info endpoint creates new additional
- information and returns the additional_info_user_reasons and
+ Test that a valid post to the additional info endpoint creates new
+ additional information and returns the additional_info_user_reasons and
additional_info_description fields but nothing else.
"""
app = AdditionalInfoRequestedYouthApplicationFactory()
diff --git a/backend/kesaseteli/applications/tests/test_settings.py b/backend/kesaseteli/applications/tests/test_settings.py
index f40c3731ca..43e6a7590b 100644
--- a/backend/kesaseteli/applications/tests/test_settings.py
+++ b/backend/kesaseteli/applications/tests/test_settings.py
@@ -6,9 +6,9 @@ def test_django_rest_framework_browsable_api_disabled():
"""
Test that Django Rest Framework's Browsable API is disabled.
- This is done to make sure that no information is leaked through
- the Browsable API interface as it can populate dropdown menus with
- information from the backend if it is enabled.
+ This is done to make sure that no information is leaked through the
+ Browsable API interface as it can populate dropdown menus with information
+ from the backend if it is enabled.
"""
for renderer_class in api_settings.DEFAULT_RENDERER_CLASSES:
assert not issubclass(renderer_class, BrowsableAPIRenderer)
diff --git a/backend/kesaseteli/applications/tests/test_youth_applications_api.py b/backend/kesaseteli/applications/tests/test_youth_applications_api.py
index d10e3dadef..77309821ee 100644
--- a/backend/kesaseteli/applications/tests/test_youth_applications_api.py
+++ b/backend/kesaseteli/applications/tests/test_youth_applications_api.py
@@ -36,6 +36,8 @@
from common.permissions import HandlerPermission
from common.tests.conftest import (
api_client,
+)
+from common.tests.conftest import (
unauthenticated_api_client as unauth_api_client,
)
from common.tests.factories import (
@@ -244,9 +246,9 @@ def test_youth_application_encrypted_fields():
def test_youth_application_serializer_fields():
"""
- Test that YouthApplicationSerializer's fields are all handled and categorized
- into required/optional/write-only/read-only partitions. Also test that handler
- views' show all fields except write-only fields.
+ Test that YouthApplicationSerializer's fields are all handled and
+ categorized into required/soptional/write-only/read-only partitions. Also
+ test that handler views' show all fields except write-only fields.
If this test breaks then update the following:
- get_required_fields()
@@ -1245,12 +1247,14 @@ def test_youth_application_post_valid_random_data( # noqa: C901
json.loads(created_app.encrypted_handler_vtj_json), dict
)
else:
- assert False, f"Please add manual check for field {manually_checked_field}"
+ raise AssertionError(
+ f"Please add manual check for field {manually_checked_field}"
+ )
for required_field in required_fields:
- assert (
- getattr(created_app, required_field) == data[required_field]
- ), f"{required_field} created youth application attribute incorrect"
+ assert getattr(created_app, required_field) == data[required_field], (
+ f"{required_field} created youth application attribute incorrect"
+ )
for optional_field in optional_fields:
assert getattr(created_app, optional_field) == data.get(
@@ -2460,8 +2464,8 @@ def test_youth_applications_set_excess_additional_info(
expected_status_code,
):
"""
- Test that providing excess POST data when setting additional info for a youth
- application does not matter and does not change anything.
+ Test that providing excess POST data when setting additional info for a
+ youth application does not matter and does not change anything.
"""
settings.NEXT_PUBLIC_MOCK_FLAG = mock_flag
settings.NEXT_PUBLIC_DISABLE_VTJ = disable_vtj
diff --git a/backend/kesaseteli/applications/views.py b/backend/kesaseteli/applications/views.py
index cfe55bba6b..b8d49ec204 100644
--- a/backend/kesaseteli/applications/views.py
+++ b/backend/kesaseteli/applications/views.py
@@ -36,8 +36,9 @@
class EmployerApplicationExcelDownloadView(TemplateView):
"""
TODO: This should be removed after the actual controller UI is implemented.
- This is a temporary view implemented by Django for MVP purposes. Basically it provides
- a very simple view for the controllers to export the applications as Excel files.
+ This is a temporary view implemented by Django for MVP purposes. Basically it
+ provides a very simple view for the controllers to export the applications as Excel
+ files.
"""
template_name = "application_excel_download.html"
@@ -114,7 +115,9 @@ def get_xlsx_response(
serializer=serializer,
batch_size=settings.EXCEL_DOWNLOAD_BATCH_SIZE,
),
- content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ content_type=(
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ),
)
response["Content-Disposition"] = "attachment; filename={}".format(
get_xlsx_filename(columns)
@@ -137,8 +140,11 @@ def export_and_download_unhandled_applications(
self, columns: ExcelColumns
) -> Union[StreamingHttpResponse, HttpResponseRedirect]:
"""
- Export unhandled applications and redirect back to the excel download page.
- The user will see a new xlsx file generated in the generated files list.
+ Export unhandled applications and redirect back to the excel download
+ page.
+
+ The user will see a new xlsx file generated in the generated files
+ list.
"""
queryset_without_pks = self.base_queryset().filter(
is_exported=False,
@@ -170,9 +176,12 @@ def export_and_download_annual_applications(
self, columns: ExcelColumns, year: int
) -> Union[StreamingHttpResponse, HttpResponseRedirect]:
"""
- Export all applications from the given year to xlsx file and download the file.
- The file is returned as a response, thus automatically downloaded. The generated
- xlsx file will not be saved on disk and will not be shown on the xlsx files list.
+ Export all applications from the given year to xlsx file and download
+ the file.
+
+ The file is returned as a response, thus automatically downloaded. The
+ generated xlsx file will not be saved on disk and will not be shown on
+ the xlsx files list.
"""
queryset = (
self.base_queryset()
@@ -266,11 +275,13 @@ def list(
serializer=self.serializer,
batch_size=settings.EXCEL_DOWNLOAD_BATCH_SIZE,
),
- content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ content_type=(
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ ),
+ )
+ response["Content-Disposition"] = (
+ f"attachment; filename={self.xlsx_filename}"
)
- response[
- "Content-Disposition"
- ] = f"attachment; filename={self.xlsx_filename}"
return response
@property
diff --git a/backend/kesaseteli/common/backward_compatibility.py b/backend/kesaseteli/common/backward_compatibility.py
index bc0adcfcb2..d4eaaefc30 100644
--- a/backend/kesaseteli/common/backward_compatibility.py
+++ b/backend/kesaseteli/common/backward_compatibility.py
@@ -8,10 +8,10 @@ def convert_to_django_4_2_csrf_trusted_origin(
target_schemes: Tuple[str] = DEFAULT_TARGET_SCHEMES,
) -> List[str]:
"""
- Convert the input CSRF trusted origin from Django 3.2 -> 4.2 format
- using the given target schemes, if not already in Django 4.2 format. If the
- origin is already in Django 4.2 format, return it as it is. Also if the origin
- is empty, then return an empty list.
+ Convert the input CSRF trusted origin from Django 3.2 -> 4.2 format using
+ the given target schemes, if not already in Django 4.2 format. If the
+ origin is already in Django 4.2 format, return it as it is. Also if the
+ origin is empty, then return an empty list.
Django 3.2 and 4.2 CSRF_TRUSTED_ORIGINS documentations:
- https://docs.djangoproject.com/en/3.2/ref/settings/#csrf-trusted-origins
@@ -37,9 +37,10 @@ def convert_to_django_4_2_csrf_trusted_origins(
target_schemes: Tuple[str] = DEFAULT_TARGET_SCHEMES,
):
"""
- Convert the input CSRF_TRUSTED_ORIGINS setting from Django 3.2 -> 4.2 format
- using the given target schemes, if not already in Django 4.2 format. If any
- of the origins are already in Django 4.2 format, return them as they are.
+ Convert the input CSRF_TRUSTED_ORIGINS setting from Django 3.2 -> 4.2
+ format using the given target schemes, if not already in Django 4.2 format.
+ If any of the origins are already in Django 4.2 format, return them as they
+ are.
Django 3.2 and 4.2 CSRF_TRUSTED_ORIGINS documentations:
- https://docs.djangoproject.com/en/3.2/ref/settings/#csrf-trusted-origins
diff --git a/backend/kesaseteli/common/permissions.py b/backend/kesaseteli/common/permissions.py
index c2007619a0..3e768751e8 100644
--- a/backend/kesaseteli/common/permissions.py
+++ b/backend/kesaseteli/common/permissions.py
@@ -35,8 +35,8 @@ def get_handler_users_queryset():
Queryset of the users who have permission to act as handlers for youth
applications / youth summer vouchers.
- :return: All users if NEXT_PUBLIC_MOCK_FLAG setting is set, otherwise active
- users who are staff or superuser users.
+ :return: All users if NEXT_PUBLIC_MOCK_FLAG setting is set, otherwise
+ active users who are staff or superuser users.
"""
if settings.NEXT_PUBLIC_MOCK_FLAG:
return get_user_model().objects.all()
@@ -48,11 +48,11 @@ def get_handler_users_queryset():
@staticmethod
def has_user_permission(user):
"""
- Does the user have permission to act as a handler for youth applications / youth
- summer vouchers?
+ Does the user have permission to act as a handler for youth
+ applications / youth summer vouchers?
- :return: True if NEXT_PUBLIC_MOCK_FLAG setting is set, or user is an active
- staff or superuser user, otherwise False.
+ :return: True if NEXT_PUBLIC_MOCK_FLAG setting is set, or user is an
+ active staff or superuser user, otherwise False.
"""
if settings.NEXT_PUBLIC_MOCK_FLAG:
return True
@@ -63,7 +63,7 @@ def has_permission(self, request, view):
"""
Does the request's user have permission to the given view?
- :return: True if NEXT_PUBLIC_MOCK_FLAG setting is set, or request has an active
- staff or superuser user, otherwise False.
+ :return: True if NEXT_PUBLIC_MOCK_FLAG setting is set, or request has
+ an active staff or superuser user, otherwise False.
"""
return HandlerPermission.has_user_permission(request.user)
diff --git a/backend/kesaseteli/common/tests/conftest.py b/backend/kesaseteli/common/tests/conftest.py
index 648314ddda..f6db7b0823 100644
--- a/backend/kesaseteli/common/tests/conftest.py
+++ b/backend/kesaseteli/common/tests/conftest.py
@@ -181,7 +181,7 @@ def unauthenticated_api_client():
@pytest.fixture
def school_list():
- TEST_SCHOOL_NAMES = [
+ test_school_names = [
"Aleksis Kiven peruskoulu",
"Apollon yhteiskoulu",
"Arabian peruskoulu",
@@ -261,6 +261,6 @@ def school_list():
"Östersundom skola",
]
School.objects.bulk_create(
- objs=[School(name=name) for name in TEST_SCHOOL_NAMES],
+ objs=[School(name=name) for name in test_school_names],
ignore_conflicts=True, # Ignore conflicts if a school with name already exists
)
diff --git a/backend/kesaseteli/common/tests/factories.py b/backend/kesaseteli/common/tests/factories.py
index 15718935ef..cd6d2916cb 100644
--- a/backend/kesaseteli/common/tests/factories.py
+++ b/backend/kesaseteli/common/tests/factories.py
@@ -435,7 +435,8 @@ class AbstractNonVtjYouthApplicationFactory(AbstractYouthApplicationFactory):
These youth applications don't have a social security number or VTJ data.
"""
- # Non-VTJ youth applications always have empty social security number and no VTJ data:
+ # Non-VTJ youth applications always have empty social security number and no VTJ
+ # data:
social_security_number = ""
encrypted_original_vtj_json = None
encrypted_handler_vtj_json = None
@@ -480,7 +481,8 @@ class Meta:
class AcceptableNonVtjYouthApplicationFactory(AbstractNonVtjYouthApplicationFactory):
"""
- A youth application created using YouthApplicationViewSet.create_without_ssn endpoint.
+ A youth application created using
+ YouthApplicationViewSet.create_without_ssn endpoint.
"""
status = YouthApplicationStatus.ADDITIONAL_INFORMATION_PROVIDED.value
@@ -488,8 +490,8 @@ class AcceptableNonVtjYouthApplicationFactory(AbstractNonVtjYouthApplicationFact
class AcceptedNonVtjYouthApplicationFactory(AbstractNonVtjYouthApplicationFactory):
"""
- A youth application created using YouthApplicationViewSet.create_without_ssn endpoint
- and then accepted.
+ A youth application created using
+ YouthApplicationViewSet.create_without_ssn endpoint and then accepted.
"""
status = YouthApplicationStatus.ACCEPTED.value
@@ -497,8 +499,8 @@ class AcceptedNonVtjYouthApplicationFactory(AbstractNonVtjYouthApplicationFactor
class RejectedNonVtjYouthApplicationFactory(AbstractNonVtjYouthApplicationFactory):
"""
- A youth application created using YouthApplicationViewSet.create_without_ssn endpoint
- and then rejected.
+ A youth application created using
+ YouthApplicationViewSet.create_without_ssn endpoint and then rejected.
"""
status = YouthApplicationStatus.REJECTED.value
diff --git a/backend/kesaseteli/common/tests/mixins.py b/backend/kesaseteli/common/tests/mixins.py
index 27153fa462..d7f307271b 100644
--- a/backend/kesaseteli/common/tests/mixins.py
+++ b/backend/kesaseteli/common/tests/mixins.py
@@ -17,7 +17,9 @@ class TestFactory(SaveAfterPostGenerationMixin, factory.django.DjangoModelFactor
@classmethod
def _after_postgeneration(cls, instance, create, results=None):
- """Save again the instance if creating and at least one hook ran."""
+ """
+ Save again the instance if creating and at least one hook ran.
+ """
if create and results:
# Some post-generation hooks ran, and may have modified us.
instance.save()
diff --git a/backend/kesaseteli/common/tests/test_backward_compatibility.py b/backend/kesaseteli/common/tests/test_backward_compatibility.py
index a08ace16ff..55ace891fd 100644
--- a/backend/kesaseteli/common/tests/test_backward_compatibility.py
+++ b/backend/kesaseteli/common/tests/test_backward_compatibility.py
@@ -11,7 +11,7 @@
@pytest.mark.parametrize("origin", ["", None])
def test_convert_to_django_4_2_csrf_trusted_origin_falsy(origin):
"""
- Test convert_to_django_4_2_csrf_trusted_origin with falsy inputs
+ Test convert_to_django_4_2_csrf_trusted_origin with falsy inputs.
"""
assert convert_to_django_4_2_csrf_trusted_origin(origin) == []
@@ -28,8 +28,8 @@ def test_convert_to_django_4_2_csrf_trusted_origin_falsy(origin):
)
def test_convert_to_django_4_2_csrf_trusted_origin_changed(origin, expected_output):
"""
- Test convert_to_django_4_2_csrf_trusted_origin with Django 4.2 incompatible origins
- i.e. those that need to be changed.
+ Test convert_to_django_4_2_csrf_trusted_origin with Django 4.2 incompatible
+ origins i.e. those that need to be changed.
"""
assert expected_output != [origin]
assert convert_to_django_4_2_csrf_trusted_origin(origin) == expected_output
@@ -45,8 +45,8 @@ def test_convert_to_django_4_2_csrf_trusted_origin_changed(origin, expected_outp
)
def test_convert_to_django_4_2_csrf_trusted_origin_already_compatible(origin):
"""
- Test convert_to_django_4_2_csrf_trusted_origin with Django 4.2 compatible origins
- i.e. those that do not need to be changed.
+ Test convert_to_django_4_2_csrf_trusted_origin with Django 4.2 compatible
+ origins i.e. those that do not need to be changed.
"""
assert convert_to_django_4_2_csrf_trusted_origin(origin) == [origin]
@@ -74,7 +74,7 @@ def test_convert_to_django_4_2_csrf_trusted_origin_already_compatible(origin):
)
def test_convert_to_django_4_2_csrf_trusted_origins(origins, expected_output):
"""
- Test convert_to_django_4_2_csrf_trusted_origins with varying origins
+ Test convert_to_django_4_2_csrf_trusted_origins with varying origins.
"""
assert convert_to_django_4_2_csrf_trusted_origins(origins) == expected_output
@@ -114,7 +114,8 @@ def test_convert_to_django_4_2_csrf_trusted_origins_with_schemes(
origins, schemes, expected_output
):
"""
- Test convert_to_django_4_2_csrf_trusted_origins with varying origins & schemes
+ Test convert_to_django_4_2_csrf_trusted_origins with varying origins &
+ schemes.
"""
assert (
convert_to_django_4_2_csrf_trusted_origins(origins, schemes) == expected_output
@@ -124,7 +125,7 @@ def test_convert_to_django_4_2_csrf_trusted_origins_with_schemes(
def test_convert_to_django_4_2_csrf_trusted_origins_call():
"""
Test that convert_to_django_4_2_csrf_trusted_origins calls
- convert_to_django_4_2_csrf_trusted_origin
+ convert_to_django_4_2_csrf_trusted_origin.
"""
with mock.patch(
"common.backward_compatibility.convert_to_django_4_2_csrf_trusted_origin"
diff --git a/backend/kesaseteli/common/tests/test_factories.py b/backend/kesaseteli/common/tests/test_factories.py
index 84091c7a9a..11f4019191 100644
--- a/backend/kesaseteli/common/tests/test_factories.py
+++ b/backend/kesaseteli/common/tests/test_factories.py
@@ -232,9 +232,7 @@ def test_youth_application_factory( # noqa: C901
elif vtj_test_case == VtjTestCase.WRONG_LAST_NAME:
assert not youth_application.is_last_name_as_in_vtj
elif vtj_test_case == VtjTestCase.NOT_FOUND:
- assert (
- not youth_application.is_social_security_number_valid_according_to_vtj
- )
+ assert not youth_application.is_social_security_number_valid_according_to_vtj
elif vtj_test_case == VtjTestCase.NO_ANSWER:
assert youth_application.encrypted_original_vtj_json is None
elif vtj_test_case == VtjTestCase.HOME_MUNICIPALITY_HELSINKI:
@@ -334,6 +332,6 @@ def test_youth_summer_voucher_factory():
youth_summer_voucher.youth_application_id
for youth_summer_voucher in youth_summer_vouchers
]
- assert len(set(youth_application_pks)) == len(
- youth_application_pks
- ), "Duplicates in youth application primary keys"
+ assert len(set(youth_application_pks)) == len(youth_application_pks), (
+ "Duplicates in youth application primary keys"
+ )
diff --git a/backend/kesaseteli/common/tests/utils.py b/backend/kesaseteli/common/tests/utils.py
index 2617cac6a4..fdcdd98c23 100644
--- a/backend/kesaseteli/common/tests/utils.py
+++ b/backend/kesaseteli/common/tests/utils.py
@@ -10,7 +10,8 @@
def get_random_social_security_number_for_year(year: int) -> str:
"""
- Create a random non-temporary Finnish social security number for the given year
+ Create a random non-temporary Finnish social security number for the given
+ year.
"""
start_of_year: datetime = datetime(year=year, month=1, day=1, tzinfo=timezone.utc)
return create_finnish_social_security_number(
@@ -28,8 +29,9 @@ def get_random_social_security_number_for_year(year: int) -> str:
def set_company_business_id_to_client(company: Company, client: Client) -> None:
"""
- Set company's business ID to client's session so the given company is fetched when
- calling companies.services.get_or_create_company_using_organization_roles
+ Set company's business ID to client's session so the given company is
+ fetched when calling
+ companies.services.get_or_create_company_using_organization_roles.
"""
session = client.session
session.update({"organization_roles": {"identifier": company.business_id}})
diff --git a/backend/kesaseteli/common/urls.py b/backend/kesaseteli/common/urls.py
index c4dd375a16..52208c4fdc 100644
--- a/backend/kesaseteli/common/urls.py
+++ b/backend/kesaseteli/common/urls.py
@@ -9,6 +9,7 @@
def handler_403_url():
"""
Get handlers' 403 (i.e. Forbidden) URL.
+
:return: URL for handlers' 403 page.
"""
return urljoin(settings.HANDLER_URL, "/fi/403")
@@ -16,8 +17,11 @@ def handler_403_url():
def handler_create_application_without_ssn_url():
"""
- Get handlers' URL "create youth application without social security number" page URL.
- :return: URL for handlers' "create youth application without social security number" page.
+ Get handlers' URL "create youth application without social security number"
+ page URL.
+
+ :return: URL for handlers' "create youth application without social
+ security number" page.
"""
return urljoin(settings.HANDLER_URL, "/create-application-without-ssn")
@@ -25,6 +29,7 @@ def handler_create_application_without_ssn_url():
def handler_youth_application_processing_url(youth_application_pk):
"""
Get handlers' youth application processing URL.
+
:param youth_application_pk: Youth application's primary key.
:return: URL for processing the youth application.
"""
@@ -34,16 +39,20 @@ def handler_youth_application_processing_url(youth_application_pk):
def get_list_url():
"""
Get youth application list URL.
+
:return: URL for youth application list. Can be used for posting new youth
- applications.
+ applications.
"""
return reverse("v1:youthapplication-list")
def get_create_without_ssn_url():
"""
- Get backend's URL for creating a youth application without social security number.
- :return: Backend's URL for creating a youth application without social security number.
+ Get backend's URL for creating a youth application without social security
+ number.
+
+ :return: Backend's URL for creating a youth application without social
+ security number.
"""
return reverse("v1:youthapplication-create-without-ssn")
@@ -51,8 +60,9 @@ def get_create_without_ssn_url():
def reverse_youth_application_action(action, pk):
"""
Reverse youth application's action URL.
- :param action: Action to reverse, e.g. "accept", "activate", "additional-info",
- "detail", "process", "reject"
+
+ :param action: Action to reverse, e.g. "accept", "activate", "additional-
+ info", "detail", "process", "reject"
:param pk: Youth application's primary key.
:return: URL for the given youth application's given action.
"""
@@ -62,6 +72,7 @@ def reverse_youth_application_action(action, pk):
def get_activation_url(pk):
"""
Get youth application's activation URL.
+
:param pk: Youth application's primary key.
:return: URL for activating the youth application.
"""
@@ -71,6 +82,7 @@ def get_activation_url(pk):
def get_detail_url(pk):
"""
Get youth application's detail info URL.
+
:param pk: Youth application's primary key.
:return: URL for viewing the youth application's detail info.
"""
@@ -79,7 +91,9 @@ def get_detail_url(pk):
def get_processing_url(pk):
"""
- Get youth application's processing URL in the backend, not in the handlers' UI.
+ Get youth application's processing URL in the backend, not in the handlers'
+ UI.
+
:param pk: Youth application's primary key.
:return: URL for processing the youth application.
"""
@@ -89,6 +103,7 @@ def get_processing_url(pk):
def get_accept_url(pk):
"""
Get youth application's accept URL.
+
:param pk: Youth application's primary key.
:return: URL for accepting the youth application.
"""
@@ -98,6 +113,7 @@ def get_accept_url(pk):
def get_additional_info_url(pk):
"""
Get youth application's additional info URL.
+
:param pk: Youth application's primary key.
:return: URL for providing additional info for the youth application.
"""
@@ -107,6 +123,7 @@ def get_additional_info_url(pk):
def get_reject_url(pk):
"""
Get youth application's reject URL.
+
:param pk: Youth application's primary key.
:return: URL for rejecting the youth application.
"""
@@ -116,8 +133,10 @@ def get_reject_url(pk):
def get_django_adfs_login_url(redirect_url):
"""
Get Django ADFS login URL.
+
:param redirect_url: URL to redirect to after successful login.
- :return: URL for Django ADFS login with the redirect URL as the "next" parameter.
+ :return: URL for Django ADFS login with the redirect URL as the "next"
+ parameter.
"""
return "{login_url}?{redirect_field_name}={redirect_url}".format(
login_url=reverse("django_auth_adfs:login"),
@@ -144,9 +163,10 @@ class RedirectTo(Enum):
def get_redirect_url(redirect_to, youth_application_action, youth_application_pk):
"""
Get redirect URL based on the given redirect enum value.
+
:param redirect_to: Enum value for redirecting to different URLs.
- :param youth_application_action: Action to reverse, e.g. "accept", "activate",
- "additional-info", "detail", "process", "reject"
+ :param youth_application_action: Action to reverse, e.g. "accept",
+ "activate", "additional-info", "detail", "process", "reject"
:param youth_application_pk: Youth application's primary key.
:return: URL for the given redirect enum value.
"""
diff --git a/backend/kesaseteli/common/utils.py b/backend/kesaseteli/common/utils.py
index 25fdf06d59..7dc86d6d6f 100644
--- a/backend/kesaseteli/common/utils.py
+++ b/backend/kesaseteli/common/utils.py
@@ -19,31 +19,35 @@ def has_whitespace(value):
def is_uppercase(value):
"""
- Is the value all uppercase? Returns True also if there are no alphabetic characters.
+ Is the value all uppercase?
+
+ Returns True also if there are no alphabetic characters.
"""
return value == value.upper()
def normalize_for_string_comparison(text):
"""
- Normalize text for string comparison. Converts None to an empty string, strips
- leading and trailing whitespace, and makes result case-insensitive by folding case.
+ Normalize text for string comparison.
+
+ Converts None to an empty string, strips leading and trailing whitespace,
+ and makes result case-insensitive by folding case.
"""
return "" if text is None else str(text).strip().casefold()
def are_same_texts(a, b) -> bool:
"""
- Are the two given values same when compared after first normalizing them using
- normalize_for_string_comparison?
+ Are the two given values same when compared after first normalizing them
+ using normalize_for_string_comparison?
"""
return normalize_for_string_comparison(a) == normalize_for_string_comparison(b)
def are_same_text_lists(a, b) -> bool:
"""
- Are the two given value lists same when compared after first normalizing their
- values using normalize_for_string_comparison?
+ Are the two given value lists same when compared after first normalizing
+ their values using normalize_for_string_comparison?
"""
return list(map(normalize_for_string_comparison, a)) == list(
map(normalize_for_string_comparison, b)
@@ -61,7 +65,8 @@ def send_mail_with_error_logging(
images: Optional[List[MIMEImage]] = None,
) -> bool:
"""
- Send email with given parameters and log given error message in case of failure.
+ Send email with given parameters and log given error message in case of
+ failure.
:param subject: Email subject
:param message: Plain text email body
@@ -69,12 +74,12 @@ def send_mail_with_error_logging(
:param recipient_list: List of email recipients
:param error_message: Error message to be logged in case of failure
:param bcc: Send a hidden copy of the message to the list of recipients
- :param html_message: Optional html message. If provided the resulting email will be
- a multipart/alternative email with message as the text/plain
- content type and html_message as the text/html content type.
- :param images: Optional attachable images. Must also provide html_message if any
- images are provided. If provided will change mail's mixed_subtype to
- related.
+ :param html_message: Optional html message. If provided the resulting email
+ will be a multipart/alternative email with message as the text/plain
+ content type and html_message as the text/html content type.
+ :param images: Optional attachable images. Must also provide html_message
+ if any images are provided. If provided will change mail's
+ mixed_subtype to related.
:return: True if email was sent, otherwise False.
"""
connection = get_connection(fail_silently=True)
@@ -96,8 +101,8 @@ def send_mail_with_error_logging(
def validate_finnish_social_security_number(value):
"""
- Raise a ValidationError if the given value is not an uppercase Finnish social
- security number with no whitespace.
+ Raise a ValidationError if the given value is not an uppercase Finnish
+ social security number with no whitespace.
"""
if (
not is_valid_finnish_social_security_number(value)
@@ -115,8 +120,8 @@ def validate_finnish_social_security_number(value):
def validate_optional_finnish_social_security_number(value):
"""
- Raise a ValidationError if the given value is not None, an empty string or an
- uppercase Finnish social security number with no whitespace.
+ Raise a ValidationError if the given value is not None, an empty string or
+ an uppercase Finnish social security number with no whitespace.
"""
if value is not None and value != "":
validate_finnish_social_security_number(value)
diff --git a/backend/kesaseteli/companies/migrations/0001_initial.py b/backend/kesaseteli/companies/migrations/0001_initial.py
index 9805961215..4bd9f1ef6e 100644
--- a/backend/kesaseteli/companies/migrations/0001_initial.py
+++ b/backend/kesaseteli/companies/migrations/0001_initial.py
@@ -1,11 +1,11 @@
# Generated by Django 3.2 on 2021-05-05 08:32
-from django.db import migrations, models
import uuid
+from django.db import migrations, models
+
class Migration(migrations.Migration):
-
initial = True
dependencies = []
diff --git a/backend/kesaseteli/companies/migrations/0002_company_optional_fields.py b/backend/kesaseteli/companies/migrations/0002_company_optional_fields.py
index 0829a46d91..0ef3c4b6ec 100644
--- a/backend/kesaseteli/companies/migrations/0002_company_optional_fields.py
+++ b/backend/kesaseteli/companies/migrations/0002_company_optional_fields.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0001_initial"),
]
diff --git a/backend/kesaseteli/companies/migrations/0003_company_eauth_profile.py b/backend/kesaseteli/companies/migrations/0003_company_eauth_profile.py
index 9a3fa6ab64..f30833d45c 100644
--- a/backend/kesaseteli/companies/migrations/0003_company_eauth_profile.py
+++ b/backend/kesaseteli/companies/migrations/0003_company_eauth_profile.py
@@ -1,11 +1,10 @@
# Generated by Django 3.2.4 on 2021-06-28 08:10
-from django.db import migrations, models
import django.db.models.deletion
+from django.db import migrations, models
class Migration(migrations.Migration):
-
dependencies = [
("oidc", "0002_eauthorizationprofile"),
("companies", "0002_company_optional_fields"),
diff --git a/backend/kesaseteli/companies/migrations/0004_company_remove_manual_fields.py b/backend/kesaseteli/companies/migrations/0004_company_remove_manual_fields.py
index 110a74ddb2..49bfec7b9a 100644
--- a/backend/kesaseteli/companies/migrations/0004_company_remove_manual_fields.py
+++ b/backend/kesaseteli/companies/migrations/0004_company_remove_manual_fields.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0003_company_eauth_profile"),
]
diff --git a/backend/kesaseteli/companies/migrations/0005_remove_company_eauth_profile.py b/backend/kesaseteli/companies/migrations/0005_remove_company_eauth_profile.py
index a493ed8c62..f7d0b0637d 100644
--- a/backend/kesaseteli/companies/migrations/0005_remove_company_eauth_profile.py
+++ b/backend/kesaseteli/companies/migrations/0005_remove_company_eauth_profile.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("companies", "0004_company_remove_manual_fields"),
]
diff --git a/backend/kesaseteli/companies/services.py b/backend/kesaseteli/companies/services.py
index aa892c87c3..b718d8607a 100644
--- a/backend/kesaseteli/companies/services.py
+++ b/backend/kesaseteli/companies/services.py
@@ -18,8 +18,8 @@ def get_or_create_company_using_company_data(
company_data: dict, ytj_data: dict
) -> Company:
"""
- Get or create a company instance using a dict of the company data and attach the ytj_data json
- for the instance.
+ Get or create a company instance using a dict of the company data and
+ attach the ytj_data json for the instance.
"""
company, _ = Company.objects.get_or_create(
**company_data, defaults={"ytj_json": ytj_data}
@@ -44,8 +44,8 @@ def get_or_create_company_with_name_and_business_id(
business_id: str,
) -> Company:
"""
- Get or create a company instance using a dict of the company data and attach the ytj_data json
- for the instance.
+ Get or create a company instance using a dict of the company data and
+ attach the ytj_data json for the instance.
"""
company, _ = Company.objects.get_or_create(
name=name,
@@ -83,18 +83,22 @@ def handle_mock_company(request: HttpRequest):
def get_or_create_company_using_organization_roles(request: HttpRequest) -> Company:
"""
- The flow will execute only step 1 or steps 2-5 if company does not exist in db.
+ The flow will execute only step 1 or steps 2-5 if company does not exist in
+ db.
Steps:
- 1. If mock flag is set, create a mock company and store dummy organization_roles in session.
- 2. Looks for organization_roles in session. If missing fetches the company name and business id from suomi.fi
- eauthorizations API and stores them in session.
- 3. Tries to fetch a company from database with the business id from the organization_roles session variable.
+ 1. If mock flag is set, create a mock company and store dummy organization_roles in
+ session.
+ 2. Looks for organization_roles in session. If missing fetches the company name and
+ business id from suomi.fi eauthorizations API and stores them in session.
+ 3. Tries to fetch a company from database with the business id from the
+ organization_roles session variable.
4. If company is missing, fetch the company info
- (company_form, industry, street_address, postcode and city) from YTJ API.
- 5. If company is missing, create a company to db with the fetched info. If company info is not found from YTJ API
- (no company found with the provided business id or the request limit of YTJ API has been met), the company is
- created only with the name and business id.
+ (company_form, industry, street_address, postcode and city) from YTJ API.
+ 5. If company is missing, create a company to db with the fetched info. If company
+ info is not found from YTJ API (no company found with the provided business id
+ or the request limit of YTJ API has been met), the company is created only with
+ the name and business id.
"""
if settings.NEXT_PUBLIC_MOCK_FLAG:
return handle_mock_company(request)
@@ -117,7 +121,8 @@ def get_or_create_company_using_organization_roles(request: HttpRequest) -> Comp
raise NotFound(detail="Could not handle the response from YTJ API")
except RequestException:
LOGGER.warning(
- f"YTJ API is under heavy load or no company found with the given business id: {business_id}"
+ "YTJ API is under heavy load or no company found with the given"
+ f" business id: {business_id}"
)
name = organization_roles.get("name")
company = get_or_create_company_with_name_and_business_id(name, business_id)
diff --git a/backend/kesaseteli/companies/tests/data/company_data.py b/backend/kesaseteli/companies/tests/data/company_data.py
index 0a76257e16..31e63cc134 100644
--- a/backend/kesaseteli/companies/tests/data/company_data.py
+++ b/backend/kesaseteli/companies/tests/data/company_data.py
@@ -68,63 +68,81 @@
"registrationDate": "2021-01-01",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/55730X",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/55730X"
+ ),
},
{
"recordNumber": "2020/290401",
"registrationDate": "2020-06-15",
"typeOfRegistration": "M",
"entryCodes": [""],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/290401",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2020/290401"
+ ),
},
{
"recordNumber": "2019/53986T",
"registrationDate": "2019-12-05",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/53986T",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/53986T"
+ ),
},
{
"recordNumber": "2019/250695",
"registrationDate": "2019-07-09",
"typeOfRegistration": "M",
"entryCodes": ["HAL"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/250695",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2019/250695"
+ ),
},
{
"recordNumber": "2018/50210V",
"registrationDate": "2018-10-19",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2018/50210V",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2018/50210V"
+ ),
},
{
"recordNumber": "2017/46683V",
"registrationDate": "2017-10-21",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2017/46683V",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2017/46683V"
+ ),
},
{
"recordNumber": "2016/86280V",
"registrationDate": "2016-11-03",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2016/86280V",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2016/86280V"
+ ),
},
{
"recordNumber": "2015/739492",
"registrationDate": "2015-11-04",
"typeOfRegistration": "M",
"entryCodes": ["TILTAR"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/739492",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/739492"
+ ),
},
{
"recordNumber": "2015/84509U",
"registrationDate": "2015-10-08",
"typeOfRegistration": "TA",
"entryCodes": ["TASE"],
- "detailsUri": "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/84509U",
+ "detailsUri": (
+ "http://avoindata.prh.fi/opendata/tr/v1/publicnotices/2015/84509U"
+ ),
},
],
"registeredOffices": [
@@ -630,7 +648,9 @@
"endDate": None,
"statusDate": "2008-07-21",
"language": "SE",
- "description": "För överlåtelse av nyttjanderätten till en fastighet",
+ "description": (
+ "För överlåtelse av nyttjanderätten till en fastighet"
+ ),
},
{
"authority": 1,
@@ -640,7 +660,10 @@
"endDate": None,
"statusDate": "2008-07-21",
"language": "EN",
- "description": "VAT-obliged for the transfer of rights to use immovable property",
+ "description": (
+ "VAT-obliged for the transfer of rights to use immovable"
+ " property"
+ ),
},
{
"authority": 1,
diff --git a/backend/kesaseteli/companies/tests/test_company_api.py b/backend/kesaseteli/companies/tests/test_company_api.py
index 63fad42c49..f9700cf8dc 100644
--- a/backend/kesaseteli/companies/tests/test_company_api.py
+++ b/backend/kesaseteli/companies/tests/test_company_api.py
@@ -22,7 +22,9 @@ def get_company_api_url():
def set_up_mock_requests(
ytj_response: dict, business_details_response: dict, requests_mock
):
- """Set up the mock responses."""
+ """
+ Set up the mock responses.
+ """
business_id = ytj_response["results"][0]["businessId"]
ytj_url = f"{settings.YTJ_BASE_URL}/{business_id}"
business_details_url = ytj_response["results"][0]["bisDetailsUri"]
diff --git a/backend/kesaseteli/docker-entrypoint.sh b/backend/kesaseteli/docker-entrypoint.sh
index 855c7ebf22..7b0fedd063 100755
--- a/backend/kesaseteli/docker-entrypoint.sh
+++ b/backend/kesaseteli/docker-entrypoint.sh
@@ -3,7 +3,7 @@
set -e
# Wait for the database
-if [ -z "$SKIP_DATABASE_CHECK" -o "$SKIP_DATABASE_CHECK" = "0" ]; then
+if [ -z "$SKIP_DATABASE_CHECK" ] || [ "$SKIP_DATABASE_CHECK" = "0" ]; then
until nc -z -v -w30 "${DATABASE_HOST}" "${DATABASE_PORT-5432}"
do
echo "Waiting for postgres database connection..."
@@ -42,7 +42,7 @@ if [[ "$CREATE_SUPERUSER" = "1" ]]; then
fi
# Start server
-if [[ ! -z "$@" ]]; then
+if [[ "$#" -gt 0 ]]; then
"$@"
elif [[ "$DEV_SERVER" = "1" ]]; then
python -Wd ./manage.py runserver 0.0.0.0:8000
diff --git a/backend/kesaseteli/kesaseteli/settings.py b/backend/kesaseteli/kesaseteli/settings.py
index 6f13477b53..b19d452817 100644
--- a/backend/kesaseteli/kesaseteli/settings.py
+++ b/backend/kesaseteli/kesaseteli/settings.py
@@ -84,7 +84,8 @@
AZURE_ACCOUNT_KEY=(str, ""),
AZURE_CONTAINER=(str, ""),
AUDIT_LOG_ORIGIN=(str, ""),
- # Random 32 bytes AES key, for testing purpose only, DO NOT use it value in staging/production
+ # Random 32 bytes AES key, for testing purpose only, DO NOT use it value in
+ # staging/production
# Always override this value from env variables
ENCRYPTION_KEY=(
str,
@@ -556,11 +557,15 @@
"lang": "fi",
},
{
- "text": "https://nuorten.hel.fi/sv/studier-och-jobb/sommarsedeln/",
+ "text": (
+ "https://nuorten.hel.fi/sv/studier-och-jobb/sommarsedeln/"
+ ),
"lang": "sv",
},
{
- "text": "https://nuorten.hel.fi/en/studies-and-work/the-summer-job-voucher/",
+ "text": (
+ "https://nuorten.hel.fi/en/studies-and-work/the-summer-job-voucher/"
+ ),
"lang": "en",
},
],
@@ -645,7 +650,8 @@
)
if SUOMIFI_TEST:
- # Test authentication method which is only available in the customer testing environment
+ # Test authentication method which is only available in the customer testing
+ # environment
SAML_CONFIG["entity_attributes"][0]["values"].append(
"urn:oid:1.2.246.517.3002.110.999"
)
diff --git a/backend/kesaseteli/manage.py b/backend/kesaseteli/manage.py
index 3f2263417d..44d99a23b7 100755
--- a/backend/kesaseteli/manage.py
+++ b/backend/kesaseteli/manage.py
@@ -1,5 +1,8 @@
#!/usr/bin/env python
-"""Django's command-line utility for administrative tasks."""
+"""
+Django's command-line utility for administrative tasks.
+"""
+
import os
import sys
diff --git a/backend/kesaseteli/pyproject.toml b/backend/kesaseteli/pyproject.toml
index 319ad03f1d..9f0bfc5ab7 100644
--- a/backend/kesaseteli/pyproject.toml
+++ b/backend/kesaseteli/pyproject.toml
@@ -1,8 +1,26 @@
-[tool.black]
-extend-exclude = '''
-(
- .pytest_cache
- | var/media
- | migrations
-)
-'''
+[tool.ruff]
+target-version = "py39"
+
+[tool.ruff.lint]
+select = [
+ # Pyflakes
+ "F",
+ # pycodestyle
+ "E",
+ "W",
+ # isort
+ "I",
+ # pep8-naming
+ "N",
+ # flake8-bugbear without opinionated rules
+ "B0",
+ # flake8-pie
+ "PIE",
+ # flake8-print
+ "T20",
+]
+extend-per-file-ignores = { "*/migrations/*" = ["E501"], "*/tests/*" = ["E501"] }
+
+[tool.ruff.lint.isort]
+known-first-party = ["shared"]
+order-by-type = false
diff --git a/backend/kesaseteli/requirements-dev.in b/backend/kesaseteli/requirements-dev.in
index f540869eda..2307f94b4b 100644
--- a/backend/kesaseteli/requirements-dev.in
+++ b/backend/kesaseteli/requirements-dev.in
@@ -2,10 +2,8 @@
# Otherwise, you might get an "Unnamed requirements are not allowed as constraints" error.
-c requirements.txt
-# These need to be kept in sync with .pre-commit-config.yaml in the root of the repository.
-black==23.1.0
-flake8==6.0.0
-isort==5.12.0
+# This needs to be kept in sync with .pre-commit-config.yaml in the root of the repository.
+ruff==0.13.1
langdetect
openpyxl
diff --git a/backend/kesaseteli/requirements-dev.txt b/backend/kesaseteli/requirements-dev.txt
index 5b1bb35a21..df773991fe 100644
--- a/backend/kesaseteli/requirements-dev.txt
+++ b/backend/kesaseteli/requirements-dev.txt
@@ -4,8 +4,6 @@
#
# pip-compile requirements-dev.in
#
-black==23.1.0
- # via -r requirements-dev.in
build==1.2.1
# via pip-tools
certifi==2024.7.4
@@ -19,9 +17,7 @@ charset-normalizer==3.3.2
# -c requirements.txt
# requests
click==8.1.7
- # via
- # black
- # pip-tools
+ # via pip-tools
coverage[toml]==7.6.0
# via pytest-cov
distlib==0.3.8
@@ -36,8 +32,6 @@ execnet==2.1.1
# via pytest-xdist
filelock==3.15.4
# via virtualenv
-flake8==6.0.0
- # via -r requirements-dev.in
freezegun==1.5.1
# via pytest-freezegun
identify==2.6.0
@@ -50,43 +44,28 @@ importlib-metadata==8.0.0
# via build
iniconfig==2.0.0
# via pytest
-isort==5.12.0
- # via -r requirements-dev.in
langdetect==1.0.9
# via -r requirements-dev.in
markupsafe==2.1.5
# via werkzeug
-mccabe==0.7.0
- # via flake8
-mypy-extensions==1.0.0
- # via black
nodeenv==1.9.1
# via pre-commit
openpyxl==3.1.5
# via -r requirements-dev.in
packaging==24.1
# via
- # black
# build
# pytest
-pathspec==0.12.1
- # via black
pip-tools==7.4.1
# via -r requirements-dev.in
platformdirs==4.2.2
- # via
- # black
- # virtualenv
+ # via virtualenv
pluggy==1.5.0
# via pytest
-pre-commit==3.7.1
+pre-commit==4.3.0
# via -r requirements-dev.in
psutil==6.0.0
# via pytest-xdist
-pycodestyle==2.10.0
- # via flake8
-pyflakes==3.0.1
- # via flake8
pyproject-hooks==1.1.0
# via
# build
@@ -118,6 +97,8 @@ requests==2.32.3
# requests-mock
requests-mock==1.12.1
# via -r requirements-dev.in
+ruff==0.13.1
+ # via -r requirements-dev.in
six==1.16.0
# via
# -c requirements.txt
@@ -125,15 +106,10 @@ six==1.16.0
# python-dateutil
tomli==2.0.1
# via
- # black
# build
# coverage
# pip-tools
# pytest
-typing-extensions==4.12.2
- # via
- # -c requirements.txt
- # black
urllib3==1.26.19
# via
# -c requirements.txt
diff --git a/backend/shared/pyproject.toml b/backend/shared/pyproject.toml
index f9d4c852cb..e9faee147f 100644
--- a/backend/shared/pyproject.toml
+++ b/backend/shared/pyproject.toml
@@ -1,7 +1,25 @@
-[tool.black]
-extend-exclude = '''
-(
- .pytest_cache
- | migrations
-)
-'''
+[tool.ruff]
+target-version = "py39"
+
+[tool.ruff.lint]
+select = [
+ # Pyflakes
+ "F",
+ # pycodestyle
+ "E",
+ "W",
+ # isort
+ "I",
+ # pep8-naming
+ "N",
+ # flake8-bugbear without opinionated rules
+ "B0",
+ # flake8-pie
+ "PIE",
+ # flake8-print
+ "T20",
+]
+extend-per-file-ignores = { "*/migrations/*" = ["E501"], "*/tests/*" = ["E501"] }
+
+[tool.ruff.lint.isort]
+known-first-party = ["shared"]
diff --git a/backend/shared/shared/audit_log/audit_logging.py b/backend/shared/shared/audit_log/audit_logging.py
index 243be8ca3f..6e90ef5588 100644
--- a/backend/shared/shared/audit_log/audit_logging.py
+++ b/backend/shared/shared/audit_log/audit_logging.py
@@ -15,12 +15,16 @@
def _now() -> datetime:
- """Returns the current time in UTC timezone."""
+ """
+ Returns the current time in UTC timezone.
+ """
return datetime.now(tz=timezone.utc)
def _iso8601_date(time: datetime) -> str:
- """Formats the timestamp in ISO-8601 format, e.g. '2020-06-01T00:00:00.000Z'."""
+ """
+ Formats the timestamp in ISO-8601 format, e.g. '2020-06-01T00:00:00.000Z'.
+ """
return f"{time.replace(tzinfo=None).isoformat(timespec='milliseconds')}Z"
@@ -37,14 +41,13 @@ def log(
"""
Write an event to the audit log.
- Each audit log event has an actor (or None for system events),
- an operation(e.g. READ or UPDATE), the target of the operation
- (a Django model instance), status (e.g. SUCCESS), and a timestamp.
+ Each audit log event has an actor (or None for system events), an
+ operation(e.g. READ or UPDATE), the target of the operation (a Django model
+ instance), status (e.g. SUCCESS), and a timestamp.
- If additional information is provided, the function assumes that
- there were no changes to the object iteself but it was (re-)sent
- to another system for example. Thus it will not log the "changes"
- of the object.
+ If additional information is provided, the function assumes that there were
+ no changes to the object iteself but it was (re-)sent to another system for
+ example. Thus it will not log the "changes" of the object.
"""
current_time = get_time()
user_id = str(actor.pk) if getattr(actor, "pk", None) else ""
diff --git a/backend/shared/shared/audit_log/migrations/0001_initial.py b/backend/shared/shared/audit_log/migrations/0001_initial.py
index 90345927cf..3ad5ec2184 100644
--- a/backend/shared/shared/audit_log/migrations/0001_initial.py
+++ b/backend/shared/shared/audit_log/migrations/0001_initial.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
initial = True
dependencies = []
diff --git a/backend/shared/shared/audit_log/migrations/0002_auditlogentry_created_at.py b/backend/shared/shared/audit_log/migrations/0002_auditlogentry_created_at.py
index 7965ea82c5..f9745e2e8f 100644
--- a/backend/shared/shared/audit_log/migrations/0002_auditlogentry_created_at.py
+++ b/backend/shared/shared/audit_log/migrations/0002_auditlogentry_created_at.py
@@ -5,7 +5,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("audit_log", "0001_initial"),
]
diff --git a/backend/shared/shared/audit_log/models.py b/backend/shared/shared/audit_log/models.py
index a8a8f07bf8..11a01dde00 100644
--- a/backend/shared/shared/audit_log/models.py
+++ b/backend/shared/shared/audit_log/models.py
@@ -23,7 +23,9 @@ def __str__(self):
def _safe_get(value: dict, *keys: str) -> str:
- """Look up a nested key in the given dict, or return "UNKNOWN" on KeyError."""
+ """
+ Look up a nested key in the given dict, or return "UNKNOWN" on KeyError.
+ """
for key in keys:
try:
value = value[key]
diff --git a/backend/shared/shared/audit_log/tasks.py b/backend/shared/shared/audit_log/tasks.py
index e6913c7fc8..099a4fa012 100644
--- a/backend/shared/shared/audit_log/tasks.py
+++ b/backend/shared/shared/audit_log/tasks.py
@@ -25,7 +25,8 @@ def send_audit_log_to_elastic_search() -> int:
and settings.ELASTICSEARCH_PASSWORD
):
LOGGER.warning(
- "Trying to send audit log to Elasticsearch without proper configuration, process skipped"
+ "Trying to send audit log to Elasticsearch without proper configuration,"
+ " process skipped"
)
return 0
es = Elasticsearch(
@@ -62,8 +63,8 @@ def send_audit_log_to_elastic_search() -> int:
def clear_audit_log_entries(days_to_keep=30) -> int:
"""
- Delete AuditLogEntry entries that have been sent to Elasticsearch and are older than
- `days_to_keep` days.
+ Delete AuditLogEntry entries that have been sent to Elasticsearch and are
+ older than `days_to_keep` days.
:return: The number of deleted AuditLogEntry objects
"""
diff --git a/backend/shared/shared/audit_log/viewsets.py b/backend/shared/shared/audit_log/viewsets.py
index e5c779dc1b..656bede256 100644
--- a/backend/shared/shared/audit_log/viewsets.py
+++ b/backend/shared/shared/audit_log/viewsets.py
@@ -48,7 +48,8 @@ def update(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
except Http404:
if self._get_target_object():
- # _get_target_object() performs the lookup using the unfiltered queryset.
+ # _get_target_object() performs the lookup using the unfiltered
+ # queryset.
# Here we'll assume that the queryset was limited based on user's
# permissions. Since the object exists, the 404 actually indicates
# an attempt to access something they don't have permission to.
@@ -85,10 +86,12 @@ def record_action(
self, target: Optional[Model] = None, additional_information: str = ""
):
"""
- This context manager will run the managed code in a transaction and writes
- a new audit log entry in the same transaction. If an exception is raised,
- the transaction will be rolled back. If the user has no permission to perform
- the given action, a "FORBIDDEN" audit log event will be recorded.
+ This context manager will run the managed code in a transaction and
+ writes a new audit log entry in the same transaction.
+
+ If an exception is raised, the transaction will be rolled back. If the
+ user has no permission to perform the given action, a "FORBIDDEN" audit
+ log event will be recorded.
"""
actor = copy(self._get_actor()) # May be destroyed if actor is also the target
actor_backend = self._get_actor_backend()
diff --git a/backend/shared/shared/azure_adfs/auth.py b/backend/shared/shared/azure_adfs/auth.py
index 6ea36addd9..7706a384f1 100644
--- a/backend/shared/shared/azure_adfs/auth.py
+++ b/backend/shared/shared/azure_adfs/auth.py
@@ -14,18 +14,19 @@
def adfs_login_group_name():
"""
- Name of the user group that signifies that the user has logged in using ADFS i.e.
- HelsinkiAdfsAuthCodeBackend at some point
+ Name of the user group that signifies that the user has logged in using
+ ADFS i.e. HelsinkiAdfsAuthCodeBackend at some point.
:return: Value of settings.ADFS_LOGIN_GROUP_NAME if it exists, otherwise
- "ADFS login"
+ "ADFS login"
"""
return getattr(django_settings, "ADFS_LOGIN_GROUP_NAME", "ADFS login")
def is_adfs_login(user) -> bool:
"""
- Has user logged in using ADFS i.e. HelsinkiAdfsAuthCodeBackend at some point?
+ Has user logged in using ADFS i.e. HelsinkiAdfsAuthCodeBackend at some
+ point?
.. warning::
Return value of True does NOT mean that user is currently logged in and active
@@ -42,8 +43,8 @@ def get_member_objects_from_graph_api(
self, user_oid: str, graph_api_access_token: str
):
"""
- Fetches user groups from MS Graph API, validates the group names and adds
- "adfs-" prefix for them.
+ Fetches user groups from MS Graph API, validates the group names and
+ adds "adfs-" prefix for them.
:returns A list of group names
"""
@@ -79,7 +80,8 @@ def update_user_groups_from_graph_api(
self, user, user_oid: str, graph_api_access_token: str
):
"""
- This method is derived from `django_auth_adfs.backend.AdfsBaseBackend.update_user_groups`.
+ This method is derived from
+ `django_auth_adfs.backend.AdfsBaseBackend.update_user_groups`.
"""
groups = self.get_member_objects_from_graph_api(
user_oid, graph_api_access_token
@@ -93,8 +95,8 @@ def update_user_groups_from_graph_api(
def get_userinfo_from_graph_api(self, graph_api_access_token: str):
"""
- Makes a call to https://docs.microsoft.com/en-us/graph/api/user-get to get more information
- about the logged in user.
+ Makes a call to https://docs.microsoft.com/en-us/graph/api/user-get to get more
+ information about the logged in user.
:returns dictionary of user's requested properties
"""
@@ -125,11 +127,12 @@ def update_userinfo_from_graph_api(self, user, graph_api_access_token: str):
def get_graph_api_access_token(self, access_token):
"""
- Handles the Microsoft On-Behalf-Of flow to fetch an access token that can be
- used with Microsoft Graph API. We will use the v2.0 enpoint to fetch this
- token.
- This method is derived from `django_auth_adfs.backend.AdfsBaseBackend.exchange_auth_code` but the
- data is changed according to the OBO flow and the token endpiont is changed to v2.0.
+ Handles the Microsoft On-Behalf-Of flow to fetch an access token that
+ can be used with Microsoft Graph API. We will use the v2.0 enpoint to
+ fetch this token. This method is derived from
+ `django_auth_adfs.backend.AdfsBaseBackend.exchange_auth_code` but the
+ data is changed according to the OBO flow and the token endpiont is
+ changed to v2.0.
Docs: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
"""
@@ -154,7 +157,8 @@ def get_graph_api_access_token(self, access_token):
# 400 = 'something' is wrong in our request
if response.status_code == 400:
if response.json().get("error_description", "").startswith("AADSTS50076"):
- # This error description indicates that multi factor authentication is required.
+ # This error description indicates that multi factor authentication is
+ # required.
raise MFARequired
LOGGER.error(
"ADFS (OBO) server returned an error: %s",
@@ -195,10 +199,10 @@ def assign_local_groups(self, user):
def authenticate(self, request=None, authorization_code=None, **kwargs):
"""
- Override the authenticate method to fetch the user groups from Microsoft Graph API
- instead of getting them from the claims.
- This is done because of the limited size of the (JWT) access token that sometimes
- cannot fit all of the groups in the claims.
+ Override the authenticate method to fetch the user groups from
+ Microsoft Graph API instead of getting them from the claims. This is
+ done because of the limited size of the (JWT) access token that
+ sometimes cannot fit all of the groups in the claims.
Docs: https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#groups-overage-claim
"""
@@ -208,7 +212,8 @@ def authenticate(self, request=None, authorization_code=None, **kwargs):
except ConfigLoadError:
return
- # If there's no token or code, we pass control to the next authentication backend
+ # If there's no token or code, we pass control to the next authentication
+ # backend
if authorization_code is None or authorization_code == "":
return
diff --git a/backend/shared/shared/azure_adfs/mock_views.py b/backend/shared/shared/azure_adfs/mock_views.py
index e6477219e6..fde15950e3 100644
--- a/backend/shared/shared/azure_adfs/mock_views.py
+++ b/backend/shared/shared/azure_adfs/mock_views.py
@@ -25,7 +25,9 @@ def get(self, request):
is_staff=True,
)
auth.login(
- request, user, backend="django.contrib.auth.backends.ModelBackend" # type: ignore
+ request,
+ user,
+ backend="django.contrib.auth.backends.ModelBackend", # type: ignore
)
request.session["_adfs_user_id"] = str(user.id)
return redirect(settings.ADFS_LOGIN_REDIRECT_URL)
diff --git a/backend/shared/shared/azure_adfs/tests/test_adfs_login.py b/backend/shared/shared/azure_adfs/tests/test_adfs_login.py
index 480ce02f61..8479d2ccb3 100644
--- a/backend/shared/shared/azure_adfs/tests/test_adfs_login.py
+++ b/backend/shared/shared/azure_adfs/tests/test_adfs_login.py
@@ -9,8 +9,8 @@
from django.urls import reverse
from shared.azure_adfs.auth import (
- adfs_login_group_name,
HelsinkiAdfsAuthCodeBackend,
+ adfs_login_group_name,
is_adfs_login,
provider_config,
)
@@ -92,7 +92,9 @@ def test_update_userinfo_from_graph_api(requests_mock, user):
auth_backend = HelsinkiAdfsAuthCodeBackend()
user_get_response = {
- "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(givenName,surname)/$entity",
+ "@odata.context": (
+ "https://graph.microsoft.com/v1.0/$metadata#users(givenName,surname)/$entity"
+ ),
"givenName": "Ad",
"surname": "Tester",
}
@@ -152,7 +154,8 @@ def test_authenticate(
user,
):
auth_backend = HelsinkiAdfsAuthCodeBackend()
- # if helsinkibenefit fixture django_db_setup has been done, then the group has been already created
+ # if helsinkibenefit fixture django_db_setup has been done, then the group has been
+ # already created
Group.objects.get_or_create(name=settings.HANDLERS_GROUP_NAME)
with mock.patch("shared.azure_adfs.auth.provider_config"):
with mock.patch.multiple(
diff --git a/backend/shared/shared/azure_adfs/views.py b/backend/shared/shared/azure_adfs/views.py
index abe49e22ba..fc6dbf3dd8 100644
--- a/backend/shared/shared/azure_adfs/views.py
+++ b/backend/shared/shared/azure_adfs/views.py
@@ -74,6 +74,7 @@ def get(self, request):
else:
error_message = "Login failed."
LOGGER.error(
- f"Invalid login. Status code: {response.status_code}. Error message: {error_message}."
+ f"Invalid login. Status code: {response.status_code}. Error message:"
+ f" {error_message}."
)
return redirect(settings.ADFS_LOGIN_REDIRECT_URL_FAILURE)
diff --git a/backend/shared/shared/common/decorators.py b/backend/shared/shared/common/decorators.py
index 4e78abddb4..b20ce01677 100644
--- a/backend/shared/shared/common/decorators.py
+++ b/backend/shared/shared/common/decorators.py
@@ -12,7 +12,7 @@
def set_use_original_redirect_url_into_session(request: HttpRequest) -> None:
"""
- Set request.session["USE_ORIGINAL_REDIRECT_URL"] to True
+ Set request.session["USE_ORIGINAL_REDIRECT_URL"] to True.
"""
request.session["USE_ORIGINAL_REDIRECT_URL"] = True
@@ -21,8 +21,8 @@ def is_request_user_unauthenticated(request: HttpRequest) -> bool:
"""
Is the request's user unauthenticated i.e. not authenticated?
- :return: True if request has no user or the user is not authenticated, otherwise
- False.
+ :return: True if request has no user or the user is not authenticated,
+ otherwise False.
"""
return not bool(request.user and request.user.is_authenticated)
@@ -36,26 +36,28 @@ def permit_view_if_permissions_or_redirect(
forbidden_response_func: Optional[Callable[[HttpRequest], HttpResponseBase]] = None,
):
"""
- Decorator for permitting a view if all permissions pass, otherwise redirecting to
- login URL with optional check (e.g. to remove redirection loops) and side effect
- (e.g. set session variables) function calls before redirection. If not all
- permissions pass nor redirection is taken then returns 403 Forbidden.
+ Decorator for permitting a view if all permissions pass, otherwise
+ redirecting to login URL with optional check (e.g. to remove redirection
+ loops) and side effect (e.g. set session variables) function calls before
+ redirection. If not all permissions pass nor redirection is taken then
+ returns 403 Forbidden.
- :param permission_classes: The permission classes as in Django REST Framework, e.g.
- [IsAuthenticated | ReadOnly]
- :param login_url: Login URL to be redirected to in case at least one permission
- doesn't pass
- :param redirect_field_name: Name of the URL parameter to pass the current URL in
- :param redirect_only_if_func: Function to check if redirecting should be done when
- user does not pass all the permissions. The default
- value is None which means redirecting should always be
- done when user does not pass all the permissions.
- :param run_before_redirect_func: Function to run before redirection, e.g. to set a
- value in request's session.
- :param forbidden_response_func: Function to generate the response to return if not
- all permissions pass nor redirection is taken. The
- default value is None which means that a response
- with status 403 Forbidden is returned.
+ :param permission_classes: The permission classes as in Django REST
+ Framework, e.g. [IsAuthenticated | ReadOnly]
+ :param login_url: Login URL to be redirected to in case at least one
+ permission doesn't pass
+ :param redirect_field_name: Name of the URL parameter to pass the current
+ URL in
+ :param redirect_only_if_func: Function to check if redirecting should be
+ done when user does not pass all the permissions. The default value is
+ None which means redirecting should always be done when user does not
+ pass all the permissions.
+ :param run_before_redirect_func: Function to run before redirection, e.g.
+ to set a value in request's session.
+ :param forbidden_response_func: Function to generate the response to return
+ if not all permissions pass nor redirection is taken. The default value
+ is None which means that a response with status 403 Forbidden is
+ returned.
"""
def decorator(view_func):
diff --git a/backend/shared/shared/common/lang_test_utils.py b/backend/shared/shared/common/lang_test_utils.py
index 5cf900ad93..4518999ae8 100644
--- a/backend/shared/shared/common/lang_test_utils.py
+++ b/backend/shared/shared/common/lang_test_utils.py
@@ -3,17 +3,17 @@
def assert_email_subject_language(email_subject, expected_language):
detected_language = langdetect.detect(email_subject)
- assert (
- detected_language == expected_language
- ), "Email subject '{}' used language {} instead of expected {}".format(
- email_subject, detected_language, expected_language
+ assert detected_language == expected_language, (
+ "Email subject '{}' used language {} instead of expected {}".format(
+ email_subject, detected_language, expected_language
+ )
)
def assert_email_body_language(email_body, expected_language):
detected_language = langdetect.detect(email_body)
- assert (
- detected_language == expected_language
- ), "Email body '{}' used language {} instead of expected {}".format(
- email_body, detected_language, expected_language
+ assert detected_language == expected_language, (
+ "Email body '{}' used language {} instead of expected {}".format(
+ email_body, detected_language, expected_language
+ )
)
diff --git a/backend/shared/shared/common/tests/factories.py b/backend/shared/shared/common/tests/factories.py
index aa7352d0a6..8cbfc4f222 100644
--- a/backend/shared/shared/common/tests/factories.py
+++ b/backend/shared/shared/common/tests/factories.py
@@ -4,7 +4,7 @@
class UserFactory(factory.django.DjangoModelFactory):
"""
- Create a Django user with a unique username
+ Create a Django user with a unique username.
"""
first_name = factory.Faker("first_name")
@@ -26,7 +26,7 @@ class Meta:
class DuplicateAllowingUserFactory(UserFactory):
"""
- Create or get a Django user with a possibly duplicated username
+ Create or get a Django user with a possibly duplicated username.
"""
class Meta:
diff --git a/backend/shared/shared/common/tests/test_mock_enabled_proxy_view.py b/backend/shared/shared/common/tests/test_mock_enabled_proxy_view.py
index c5952693d9..2ca0e2c2f2 100644
--- a/backend/shared/shared/common/tests/test_mock_enabled_proxy_view.py
+++ b/backend/shared/shared/common/tests/test_mock_enabled_proxy_view.py
@@ -23,8 +23,8 @@ def _test_func(
cls, called_method_name: str, request, *args, **kwargs
) -> ViewCallInfo:
"""
- Return class name, called method name, request, positional arguments and
- keyword arguments for testing purposes.
+ Return class name, called method name, request, positional arguments
+ and keyword arguments for testing purposes.
"""
return ViewCallInfo(cls.__name__, called_method_name, request, args, kwargs)
diff --git a/backend/shared/shared/common/tests/test_utils.py b/backend/shared/shared/common/tests/test_utils.py
index 9d8e3e90f0..aa69368800 100644
--- a/backend/shared/shared/common/tests/test_utils.py
+++ b/backend/shared/shared/common/tests/test_utils.py
@@ -32,8 +32,8 @@ def _test_settings(settings):
def test_test_settings(_test_settings):
- assert getattr(_test_settings, "EXISTING_TRUE_SETTING") is True
- assert getattr(_test_settings, "EXISTING_FALSE_SETTING") is False
+ assert _test_settings.EXISTING_TRUE_SETTING is True
+ assert _test_settings.EXISTING_FALSE_SETTING is False
assert not hasattr(_test_settings, "INEXISTENT_SETTING")
@@ -195,10 +195,11 @@ def test_valid_create_finnish_social_security_number(
)
def test_valid_consecutive_create_finnish_social_security_number(birthdate: date):
"""
- Testing consecutive social security numbers for validity to ensure all their parts
- are calculated correctly, including the checksum (i.e. the last character).
+ Testing consecutive social security numbers for validity to ensure all
+ their parts are calculated correctly, including the checksum (i.e. the last
+ character).
"""
- for century_variant in range(0, 6):
+ for century_variant in range(6):
for individual_number in range(2, 900):
result = create_finnish_social_security_number(
birthdate, century_variant, individual_number
diff --git a/backend/shared/shared/common/tests/utils.py b/backend/shared/shared/common/tests/utils.py
index ec2f9d7aa0..d68ecd3af8 100644
--- a/backend/shared/shared/common/tests/utils.py
+++ b/backend/shared/shared/common/tests/utils.py
@@ -8,37 +8,40 @@ def create_finnish_social_security_number(
birthdate: date, century_variant: int, individual_number: int
) -> str:
"""
- Create a Finnish social security number based on birthdate, century variant and
- individual number
+ Create a Finnish social security number based on birthdate, century variant
+ and individual number.
:param birthdate: Date of birth
- :param century_variant: Non-negative integer value for deciding which century
- character variant to use, e.g. birthdates in 2000–2099 may
- have century character A, B, C, D, E or F. There's no upper
- limit as (century_variant % available_century_characters) is
- the value being used.
+ :param century_variant: Non-negative integer value for deciding which
+ century character variant to use, e.g. birthdates in 2000–2099 may have
+ century character A, B, C, D, E or F. There's no upper limit as
+ (century_variant % available_century_characters) is the value being
+ used.
:param individual_number: Integer value where 2 <= individual_number <= 999
- :return: Finnish social security number in format where
- dd = day of birth with leading zeroes,
- mm = month of birth with leading zeroes,
- yy = year of birth modulo 100 with leading zeroes,
- c = century of birth, where c is
- "+" = 1800,
- "-" = 1900 if (century_variant % 6) == 0,
- "Y" = 1900 if (century_variant % 6) == 1,
- "X" = 1900 if (century_variant % 6) == 2,
- "W" = 1900 if (century_variant % 6) == 3,
- "V" = 1900 if (century_variant % 6) == 4,
- "U" = 1900 if (century_variant % 6) == 5,
- "A" = 2000 if (century_variant % 6) == 0,
- "B" = 2000 if (century_variant % 6) == 1,
- "C" = 2000 if (century_variant % 6) == 2,
- "D" = 2000 if (century_variant % 6) == 3,
- "E" = 2000 if (century_variant % 6) == 4,
- "F" = 2000 if (century_variant % 6) == 5,
- iii = individual number in range 2–999 with leading zeroes,
- s = checksum value calculated from .
- :raises ValueError: if not (1800 <= birthdate.year <= 2099)
+ :return: Finnish social security number in format ````.
+
+ Format parts:
+ - ``dd`` = day of birth with leading zeroes
+ - ``mm`` = month of birth with leading zeroes
+ - ``yy`` = year of birth modulo 100 with leading zeroes
+ - ``c`` = century of birth, chosen as follows::
+
+ "+" = 1800
+ "-" = 1900 if (century_variant % 6) == 0
+ "Y" = 1900 if (century_variant % 6) == 1
+ "X" = 1900 if (century_variant % 6) == 2
+ "W" = 1900 if (century_variant % 6) == 3
+ "V" = 1900 if (century_variant % 6) == 4
+ "U" = 1900 if (century_variant % 6) == 5
+ "A" = 2000 if (century_variant % 6) == 0
+ "B" = 2000 if (century_variant % 6) == 1
+ "C" = 2000 if (century_variant % 6) == 2
+ "D" = 2000 if (century_variant % 6) == 3
+ "E" = 2000 if (century_variant % 6) == 4
+ "F" = 2000 if (century_variant % 6) == 5
+
+ - ``iii`` = individual number in range 2–999 with leading zeroes
+ - ``s`` = checksum value calculated from ```` :raises ValueError: if not (1800 <= birthdate.year <= 2099)
:raises ValueError: if century_variant < 0
:raises ValueError: if not (2 <= individual_number <= 999)
"""
@@ -59,8 +62,8 @@ def create_finnish_social_security_number(
def normalize_whitespace(value: str) -> str:
"""
- Normalize whitespace by compacting inner whitespace to single space and removing
- leading and trailing whitespace.
+ Normalize whitespace by compacting inner whitespace to single space and
+ removing leading and trailing whitespace.
For example:
normalize_whitespace(" 1st 2nd 3rd ") == "1st 2nd 3rd"
@@ -70,8 +73,8 @@ def normalize_whitespace(value: str) -> str:
def set_setting_to_value_or_del_with_none(setting_name: str, setting_value) -> None:
"""
- Set setting to value if is not None,
- otherwise delete the setting if it exists.
+ Set setting to value if is
+ not None, otherwise delete the setting if it exists.
"""
if setting_value is None:
if hasattr(settings, setting_name):
diff --git a/backend/shared/shared/common/utils.py b/backend/shared/shared/common/utils.py
index 69c4554ac9..bc5c430832 100644
--- a/backend/shared/shared/common/utils.py
+++ b/backend/shared/shared/common/utils.py
@@ -10,6 +10,8 @@
from django.shortcuts import resolve_url
from stdnum.fi.hetu import (
compact as compact_finnish_social_security_number,
+)
+from stdnum.fi.hetu import (
validate as validate_finnish_social_security_number,
)
@@ -36,8 +38,9 @@
def any_of_q_filter(**kwargs):
"""
- Return Q filters combined with | i.e. match any of the given keyword arguments.
- Return an always false Q filter if no keyword arguments are given.
+ Return Q filters combined with | i.e. match any of the given keyword
+ arguments. Return an always false Q filter if no keyword arguments are
+ given.
NOTE: Supports "not__" prefix to invert a particular Q expression i.e. ~Q().
@@ -80,9 +83,9 @@ class MatchesAnyOfQuerySet(QuerySet):
def matches_any_of(self, **kwargs):
"""
- Do any of the given expressions match? If none match or there are no expressions
- then return an empty queryset. If there is some match then return the queryset
- with the objects that matched.
+ Do any of the given expressions match? If none match or there are no
+ expressions then return an empty queryset. If there is some match then
+ return the queryset with the objects that matched.
NOTE: Supports "not__" prefix to invert a particular expression.
@@ -101,7 +104,8 @@ def redirect_to_login_using_request(
request, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME
) -> HttpResponseRedirect:
"""
- Redirect to login page similarly as in django.contrib.auth.decorators.user_passes_test.
+ Redirect to login page similarly as in
+ django.contrib.auth.decorators.user_passes_test.
See user_passes_test for reference:
https://github.com/django/django/blob/3.2.4/django/contrib/auth/decorators.py#L22-L33
@@ -125,8 +129,8 @@ def social_security_number_birthdate(social_security_number) -> date:
"""
Calculate birthdate based on the given Finnish social security number.
- :raises stdnum.exceptions.ValidationError: If social_security_number is not a valid
- Finnish social security number.
+ :raises stdnum.exceptions.ValidationError: If social_security_number is not
+ a valid Finnish social security number.
:return: Birthdate calculated from the social_security_number.
"""
compacted_social_security_number = compact_finnish_social_security_number(
diff --git a/backend/shared/shared/common/validators.py b/backend/shared/shared/common/validators.py
index c31f1ca703..18587d8c1c 100644
--- a/backend/shared/shared/common/validators.py
+++ b/backend/shared/shared/common/validators.py
@@ -26,32 +26,35 @@
def validate_phone_number(phone_number) -> None:
"""
- Function wrapper for PHONE_NUMBER_REGEX_VALIDATOR. If used as a validator in a
- Django model's field this does not hardcode the underlying regular expression into
- the migration nor into the model.
+ Function wrapper for PHONE_NUMBER_REGEX_VALIDATOR. If used as a validator
+ in a Django model's field this does not hardcode the underlying regular
+ expression into the migration nor into the model.
- Raise ValidationError if the given value doesn't pass PHONE_NUMBER_REGEX_VALIDATOR.
+ Raise ValidationError if the given value doesn't pass
+ PHONE_NUMBER_REGEX_VALIDATOR.
"""
PHONE_NUMBER_REGEX_VALIDATOR(phone_number)
def validate_postcode(postcode) -> None:
"""
- Function wrapper for POSTAL_CODE_REGEX_VALIDATOR. If used as a validator in a
- Django model's field this does not hardcode the underlying regular expression into
- the migration nor into the model.
+ Function wrapper for POSTAL_CODE_REGEX_VALIDATOR. If used as a validator in
+ a Django model's field this does not hardcode the underlying regular
+ expression into the migration nor into the model.
- Raise ValidationError if the given value doesn't pass POSTAL_CODE_REGEX_VALIDATOR.
+ Raise ValidationError if the given value doesn't pass
+ POSTAL_CODE_REGEX_VALIDATOR.
"""
POSTAL_CODE_REGEX_VALIDATOR(postcode)
def validate_name(name) -> None:
"""
- Validates name to be a non-empty string with no trailing or leading whitespace.
+ Validates name to be a non-empty string with no trailing or leading
+ whitespace.
- Raise ValidationError if the given value is not a non-empty string with no trailing
- or leading whitespace.
+ Raise ValidationError if the given value is not a non-empty string with no
+ trailing or leading whitespace.
"""
if not (isinstance(name, str) and name == name.strip() and name.strip()):
raise ValidationError(
@@ -61,7 +64,8 @@ def validate_name(name) -> None:
def validate_json(value) -> None:
"""
- Raise ValidationError if the given value can not be interpreted as valid JSON.
+ Raise ValidationError if the given value can not be interpreted as valid
+ JSON.
"""
try:
json.loads(value)
@@ -71,8 +75,8 @@ def validate_json(value) -> None:
def validate_optional_json(value) -> None:
"""
- Raise a ValidationError if the given value is not None, an empty string or can not
- be interpreted as valid JSON.
+ Raise a ValidationError if the given value is not None, an empty string or
+ can not be interpreted as valid JSON.
"""
if value is not None and value != "":
validate_json(value)
@@ -85,17 +89,18 @@ def validate_unique_comma_separated_choices(
allow_blank: bool,
) -> None:
"""
- Validate values_string as unique comma separated choices from choices_class.
+ Validate values_string as unique comma separated choices from
+ choices_class.
:param values_string: Input string containing the comma separated choices
:param choices_class: Type, not an instance, of class derived from Choices
:param allow_null: Is values_string allowed to be None?
:param allow_blank: Is values_string allowed to be an empty string i.e. ""?
-
- :raises ValidationError: If values_string is None and allow_null isn't True, or if
- values_string is an empty string and allow_blank isn't True, otherwise if
- values_string can't be split into parts on commas, or if the split parts aren't
- unique, or if the split parts aren't values from choices_class.values.
+ :raises ValidationError: If values_string is None and allow_null isn't
+ True, or if values_string is an empty string and allow_blank isn't
+ True, otherwise if values_string can't be split into parts on commas,
+ or if the split parts aren't unique, or if the split parts aren't
+ values from choices_class.values.
"""
if values_string is None:
if allow_null:
diff --git a/backend/shared/shared/common/views.py b/backend/shared/shared/common/views.py
index 8d67fa40cc..d4e2e73495 100644
--- a/backend/shared/shared/common/views.py
+++ b/backend/shared/shared/common/views.py
@@ -6,8 +6,8 @@
class MockEnabledProxyView:
"""
- A view that changes on-the-fly between the real and mocked view based on the current
- value of NEXT_PUBLIC_MOCK_FLAG.
+ A view that changes on-the-fly between the real and mocked view based on
+ the current value of NEXT_PUBLIC_MOCK_FLAG.
An instance of this class tries to act like
mock_view_class.as_view(**initkwargs) when NEXT_PUBLIC_MOCK_FLAG setting is set,
@@ -29,10 +29,12 @@ def __init__(
Initialize the real view to real_view_class.as_view(**initkwargs) and
mock view to mock_view_class.as_view(**initkwargs).
- :param real_view_class: Type of View class to use when mocking is turned off
- :param mock_view_class: Type of View class to use when mocking is turned on
- :param initkwargs: The keyword arguments passed to real_view_class.as_view and
- mock_view_class.as_view functions
+ :param real_view_class: Type of View class to use when mocking is
+ turned off
+ :param mock_view_class: Type of View class to use when mocking is
+ turned on
+ :param initkwargs: The keyword arguments passed to
+ real_view_class.as_view and mock_view_class.as_view functions
"""
self.__real_view = real_view_class.as_view(**initkwargs)
self.__mock_view = mock_view_class.as_view(**initkwargs)
@@ -40,22 +42,25 @@ def __init__(
@property
def __view(self):
"""
- The underlying view initialized using .as_view(**initkwargs) based
- on the current value of NEXT_PUBLIC_MOCK_FLAG setting.
+ The underlying view initialized using .as_view(**initkwargs)
+ based on the current value of NEXT_PUBLIC_MOCK_FLAG setting.
- :return: mock_view_class.as_view(**initkwargs) if NEXT_PUBLIC_MOCK_FLAG setting
- exists and is truthy, otherwise real_view_class.as_view(**initkwargs)
+ :return: mock_view_class.as_view(**initkwargs) if NEXT_PUBLIC_MOCK_FLAG
+ setting exists and is truthy, otherwise
+ real_view_class.as_view(**initkwargs)
"""
is_mocked = getattr(settings, "NEXT_PUBLIC_MOCK_FLAG", False)
return self.__mock_view if is_mocked else self.__real_view
def __getattr__(self, name):
"""
- Read all attributes not found in this instance from the underlying view.
+ Read all attributes not found in this instance from the underlying
+ view.
- This is needed because django.views.generic.base.View.as_view returns a function
- which has attributes written into it, e.g. view_class and view_initkwargs, and
- they need to be accessible directly through this instance.
+ This is needed because django.views.generic.base.View.as_view returns a
+ function which has attributes written into it, e.g. view_class and
+ view_initkwargs, and they need to be accessible directly through this
+ instance.
"""
return getattr(self.__view, name)
@@ -63,8 +68,9 @@ def __call__(self, *args, **kwargs):
"""
Redirect all calls made to this instance to the underlying view.
- This is needed because django.views.generic.base.View.as_view returns a function
- which can be called like function(request, *args, **kwargs) and calling it with
- the passed parameters needs to be doable directly through this instance.
+ This is needed because django.views.generic.base.View.as_view returns a
+ function which can be called like function(request, *args, **kwargs)
+ and calling it with the passed parameters needs to be doable directly
+ through this instance.
"""
return self.__view.__call__(*args, **kwargs)
diff --git a/backend/shared/shared/helsinki_profile/exceptions.py b/backend/shared/shared/helsinki_profile/exceptions.py
index ebce7f15be..a454a541c5 100644
--- a/backend/shared/shared/helsinki_profile/exceptions.py
+++ b/backend/shared/shared/helsinki_profile/exceptions.py
@@ -1,4 +1,4 @@
-class HelsinkiProfileException(Exception):
- """Common class for exceptions raised by `HelsinkiProfileClient`"""
-
- pass
+class HelsinkiProfileError(Exception):
+ """
+ Common class for exceptions raised by `HelsinkiProfileClient`
+ """
diff --git a/backend/shared/shared/helsinki_profile/hp_client.py b/backend/shared/shared/helsinki_profile/hp_client.py
index a31984bade..ced5652141 100644
--- a/backend/shared/shared/helsinki_profile/hp_client.py
+++ b/backend/shared/shared/helsinki_profile/hp_client.py
@@ -2,15 +2,15 @@
from django.conf import settings
from requests import RequestException
-from shared.helsinki_profile.exceptions import HelsinkiProfileException
+from shared.helsinki_profile.exceptions import HelsinkiProfileError
class HelsinkiProfileClient:
"""
- Client for reading data from the Helsinki Profile GraphQL API
+ Client for reading data from the Helsinki Profile GraphQL API.
- See [backend/README.md](https://github.com/City-of-Helsinki/yjdh/blob/main/backend/README.md) for details
- about the auth flow.
+ See [backend/README.md](https://github.com/City-of-Helsinki/yjdh/blob/main/backend/README.md)
+ for details about the auth flow.
https://helsinkisolutionoffice.atlassian.net/wiki/spaces/KAN/pages/6172606574/Full+Helsinki-profile+with+citizen+profile+and+API+authorization+support+features
"""
@@ -24,18 +24,16 @@ def __init__(self):
settings.HELSINKI_PROFILE_SCOPE,
]
):
- raise HelsinkiProfileException(
- "HelsinkiProfileClient settings not configured."
- )
+ raise HelsinkiProfileError("HelsinkiProfileClient settings not configured.")
def get_profile(self, oidc_access_token):
"""
Reads user's profile from the API.
- Currently only reads the `nationalIdentificationNumber`, but can easily be modified to read
- other data if needed.
+ Currently only reads the `nationalIdentificationNumber`, but can easily be
+ modified to read other data if needed.
- :raises HelsinkiProfileException if profile cannot be succesfully read
+ :raises HelsinkiProfileError if profile cannot be succesfully read
:return dict with queried values (value may be `None`)
"""
@@ -48,7 +46,8 @@ def get_profile(self, oidc_access_token):
try:
payload = {
- "query": """
+ "query": (
+ """
query myProfile {
myProfile {
verifiedPersonalInformation {
@@ -56,7 +55,8 @@ def get_profile(self, oidc_access_token):
}
}
}
- """,
+ """
+ ),
}
response = requests.post(
settings.HELSINKI_PROFILE_API_URL,
@@ -67,14 +67,12 @@ def get_profile(self, oidc_access_token):
)
response.raise_for_status()
except RequestException as e:
- raise HelsinkiProfileException(str(e))
+ raise HelsinkiProfileError(str(e))
profile_data = response.json()
if "errors" in profile_data:
- raise HelsinkiProfileException(
- f"GraphQL error: {str(profile_data['errors'])}"
- )
+ raise HelsinkiProfileError(f"GraphQL error: {str(profile_data['errors'])}")
national_identification_number = (
profile_data.get("data", {})
@@ -87,7 +85,7 @@ def get_profile(self, oidc_access_token):
def get_api_access_token(self, oidc_access_token):
"""
- Exchanges OIDC access token for API access token using Tunnistamo
+ Exchanges OIDC access token for API access token using Tunnistamo.
"""
try:
response = requests.get(
@@ -98,17 +96,19 @@ def get_api_access_token(self, oidc_access_token):
response.raise_for_status()
data = response.json()
except RequestException as e:
- raise HelsinkiProfileException(str(e))
+ raise HelsinkiProfileError(str(e))
if settings.HELSINKI_PROFILE_SCOPE not in data:
- raise HelsinkiProfileException(
- "Could not obtain API access token, check setting HELSINKI_PROFILE_SCOPE"
+ raise HelsinkiProfileError(
+ "Could not obtain API access token, check setting"
+ " HELSINKI_PROFILE_SCOPE"
)
return data[settings.HELSINKI_PROFILE_SCOPE]
def get_api_access_token_tunnistus(self, oidc_access_token):
"""
- Exchanges OIDC access token for API access token using Tunnistus Keycloak
+ Exchanges OIDC access token for API access token using Tunnistus
+ Keycloak.
"""
if "test" in settings.HELSINKI_PROFILE_API_URL:
@@ -136,10 +136,11 @@ def get_api_access_token_tunnistus(self, oidc_access_token):
data = response.json()
except RequestException as e:
- raise HelsinkiProfileException(str(e))
+ raise HelsinkiProfileError(str(e))
if settings.HELSINKI_PROFILE_SCOPE not in data:
- raise HelsinkiProfileException(
- "Could not obtain API access token, check setting HELSINKI_PROFILE_SCOPE"
+ raise HelsinkiProfileError(
+ "Could not obtain API access token, check setting"
+ " HELSINKI_PROFILE_SCOPE"
)
return data[settings.HELSINKI_PROFILE_SCOPE]
diff --git a/backend/shared/shared/models/mixins.py b/backend/shared/shared/models/mixins.py
index f9253effe4..535ff2745a 100644
--- a/backend/shared/shared/models/mixins.py
+++ b/backend/shared/shared/models/mixins.py
@@ -1,9 +1,10 @@
class LockForUpdateMixin:
def lock_for_update(self, *args, **kwargs):
"""
- Lock current model instance for update using select_for_update
+ Lock current model instance for update using select_for_update.
- :param args: Optional positional arguments to select_for_update function
+ :param args: Optional positional arguments to select_for_update
+ function
:param kwargs: Optional keyword arguments to select_for_update function
:return: The locked model instance
"""
diff --git a/backend/shared/shared/oidc/auth.py b/backend/shared/shared/oidc/auth.py
index 9653f48806..9966960273 100644
--- a/backend/shared/shared/oidc/auth.py
+++ b/backend/shared/shared/oidc/auth.py
@@ -17,7 +17,9 @@
class HelsinkiOIDCAuthenticationBackend(OIDCAuthenticationBackend):
- """Override Mozilla Django OIDC authentication."""
+ """
+ Override Mozilla Django OIDC authentication.
+ """
@staticmethod
def should_personally_identifiable_info_be_saved() -> bool:
@@ -25,17 +27,22 @@ def should_personally_identifiable_info_be_saved() -> bool:
Should personally identifiable information be saved to user model?
:return: True if OIDC_SAVE_PERSONALLY_IDENTIFIABLE_INFO setting exists
- and is truthy, otherwise False.
+ and is truthy, otherwise False.
"""
return bool(getattr(settings, "OIDC_SAVE_PERSONALLY_IDENTIFIABLE_INFO", False))
def verify_claims(self, claims):
- """Override the original verify_claims method because it verifies the claim from the email and
- email is not a mandatory field for suomi.fi authentication."""
+ """
+ Override the original verify_claims method because it verifies the
+ claim from the email and email is not a mandatory field for suomi.fi
+ authentication.
+ """
return True
def filter_users_by_claims(self, claims):
- """Return all users matching the specified username (sub)."""
+ """
+ Return all users matching the specified username (sub).
+ """
username = claims.get("sub")
if not username:
return self.UserModel.objects.none()
@@ -45,11 +52,12 @@ def create_user(self, claims):
"""
Return object for a newly created user account.
- :return: User with username set to "sub" claim, and if and only if personally
- identifiable information should be saved then with first_name set to
- "given_name" claim, last_name set to "family_name" claim and email set
- to "email" claim. In case personally identifiable information shouldn't
- be saved then first_name, last_name and email are set to empty strings.
+ :return: User with username set to "sub" claim, and if and only if
+ personally identifiable information should be saved then with
+ first_name set to "given_name" claim, last_name set to
+ "family_name" claim and email set to "email" claim. In case
+ personally identifiable information shouldn't be saved then
+ first_name, last_name and email are set to empty strings.
"""
save_pii = self.should_personally_identifiable_info_be_saved()
return self.UserModel.objects.create_user(
@@ -60,7 +68,9 @@ def create_user(self, claims):
)
def authenticate(self, request, **kwargs):
- """Authenticates a user based on the OIDC code flow."""
+ """
+ Authenticates a user based on the OIDC code flow.
+ """
if not request:
return None
@@ -108,7 +118,9 @@ def authenticate(self, request, **kwargs):
return None
def refresh_tokens(self, request):
- """Refreshes the tokens of the oidc session of the user and return it."""
+ """
+ Refreshes the tokens of the oidc session of the user and return it.
+ """
if not is_active_oidc_refresh_token(request):
raise SuspiciousOperation("Refresh token expired or does not exist")
diff --git a/backend/shared/shared/oidc/migrations/0001_initial.py b/backend/shared/shared/oidc/migrations/0001_initial.py
index 518c38dee0..f159b2798e 100644
--- a/backend/shared/shared/oidc/migrations/0001_initial.py
+++ b/backend/shared/shared/oidc/migrations/0001_initial.py
@@ -8,7 +8,6 @@
class Migration(migrations.Migration):
-
initial = True
dependencies = [
diff --git a/backend/shared/shared/oidc/migrations/0002_eauthorizationprofile.py b/backend/shared/shared/oidc/migrations/0002_eauthorizationprofile.py
index 75dedb87c6..bf209eea0f 100644
--- a/backend/shared/shared/oidc/migrations/0002_eauthorizationprofile.py
+++ b/backend/shared/shared/oidc/migrations/0002_eauthorizationprofile.py
@@ -7,7 +7,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("contenttypes", "0002_remove_content_type_name"),
("oidc", "0001_initial"),
diff --git a/backend/shared/shared/oidc/migrations/0003_remove_models.py b/backend/shared/shared/oidc/migrations/0003_remove_models.py
index e6db841518..95b488a6fc 100644
--- a/backend/shared/shared/oidc/migrations/0003_remove_models.py
+++ b/backend/shared/shared/oidc/migrations/0003_remove_models.py
@@ -4,7 +4,6 @@
class Migration(migrations.Migration):
-
dependencies = [
("oidc", "0002_eauthorizationprofile"),
]
diff --git a/backend/shared/shared/oidc/tests/test_backchannel_logout.py b/backend/shared/shared/oidc/tests/test_backchannel_logout.py
index e395dfe3c2..929d569c23 100644
--- a/backend/shared/shared/oidc/tests/test_backchannel_logout.py
+++ b/backend/shared/shared/oidc/tests/test_backchannel_logout.py
@@ -12,7 +12,9 @@ def get_token_claims():
return {
"iat": 1613023879,
"jti": "85d6778d-3fed-4988-95c1-10443a5e981f",
- "iss": "https://helsinki-profile-keycloak-dev.agw.arodevtest.hel.fi/auth/realms/helsinki-tunnistus",
+ "iss": (
+ "https://helsinki-profile-keycloak-dev.agw.arodevtest.hel.fi/auth/realms/helsinki-tunnistus"
+ ),
"aud": "tunnistamo",
"sub": "e9dbc682-2d93-4b5e-a472-6ee0ebe79fc7",
"typ": "Logout",
diff --git a/backend/shared/shared/oidc/tests/test_eauth_views.py b/backend/shared/shared/oidc/tests/test_eauth_views.py
index 2aa6c25c5e..55811a5524 100644
--- a/backend/shared/shared/oidc/tests/test_eauth_views.py
+++ b/backend/shared/shared/oidc/tests/test_eauth_views.py
@@ -37,8 +37,8 @@ def test_get_checksum_header():
checksum = get_checksum_header(path)
assert (
- checksum
- == "ed4b7ae7 2017-02-09T10:29:42.090000+00:00 GeRKoGmGd0RFk33s2vNHutJf/TrEdwSM2Vb7qWXLESY="
+ checksum == "ed4b7ae7 2017-02-09T10:29:42.090000+00:00"
+ " GeRKoGmGd0RFk33s2vNHutJf/TrEdwSM2Vb7qWXLESY="
)
diff --git a/backend/shared/shared/oidc/tests/test_oidc_views.py b/backend/shared/shared/oidc/tests/test_oidc_views.py
index 3eecf4b6c6..df015fde3a 100644
--- a/backend/shared/shared/oidc/tests/test_oidc_views.py
+++ b/backend/shared/shared/oidc/tests/test_oidc_views.py
@@ -79,7 +79,9 @@ def test_userinfo_view(requests_mock, user_client, user):
"sub": "82e17287-f34e-4e4b-b3d2-15857b3f952a",
"national_id_num": "210281-9988",
"name": "Nordea Demo",
- "preferred_username": "e29a380628e06d3e0e903b8fb245f1910bceee063cda47c27df1f976dc60aa9b",
+ "preferred_username": (
+ "e29a380628e06d3e0e903b8fb245f1910bceee063cda47c27df1f976dc60aa9b"
+ ),
"given_name": "Nordea",
"family_name": "Demo",
}
diff --git a/backend/shared/shared/oidc/utils.py b/backend/shared/shared/oidc/utils.py
index 1b566eee15..badcdc45e1 100644
--- a/backend/shared/shared/oidc/utils.py
+++ b/backend/shared/shared/oidc/utils.py
@@ -29,8 +29,8 @@ def refresh_hki_tokens(request: HttpRequest) -> dict:
def get_checksum_header(path: str) -> str:
"""
suomi.fi has a custom checksum that needs to be added for the requests.
- Docs (only in Finnish):
- Search for "4.3 Tarkistesumman laskeminen" and :
+
+ Docs (only in Finnish): Search for "4.3 Tarkistesumman laskeminen" and :
https://palveluhallinta.suomi.fi/fi/tuki/artikkelit/5a781dc75cb4f10dde9735e4
"""
timestamp = timezone.now().isoformat()
@@ -70,8 +70,9 @@ def request_organization_roles(request: HttpRequest) -> dict:
def get_organization_roles(request: HttpRequest) -> dict:
"""
Docs (only in Finnish):
- Search for "Taulukossa 14"
- https://palveluhallinta.suomi.fi/fi/tuki/artikkelit/592d774503f6d100018db5dd
+
+ Search for "Taulukossa 1
+ "https://palveluhallinta.suomi.fi/fi/tuki/artikkelit/592d774503f6d100018db5dd
"""
org_roles = request.session.get("organization_roles")
@@ -111,7 +112,9 @@ def store_token_info_in_session(request: HttpRequest, token_info: dict, prefix="
def store_token_info_in_oidc_session(request: HttpRequest, token_info: dict) -> dict:
- """Store token info in the session and return the values as dict."""
+ """
+ Store token info in the session and return the values as dict.
+ """
return store_token_info_in_session(request, token_info, "oidc")
@@ -119,7 +122,9 @@ def store_token_info_in_eauth_session(
request: HttpRequest,
token_info: dict,
) -> dict:
- """Store token info in the session and return the values as dict."""
+ """
+ Store token info in the session and return the values as dict.
+ """
return store_token_info_in_session(request, token_info, "eauth")
diff --git a/backend/shared/shared/oidc/views/eauth_views.py b/backend/shared/shared/oidc/views/eauth_views.py
index e1e27f1c25..d6c5d19099 100644
--- a/backend/shared/shared/oidc/views/eauth_views.py
+++ b/backend/shared/shared/oidc/views/eauth_views.py
@@ -13,7 +13,7 @@
from requests.auth import HTTPBasicAuth
from requests.exceptions import HTTPError
-from shared.helsinki_profile.exceptions import HelsinkiProfileException
+from shared.helsinki_profile.exceptions import HelsinkiProfileError
from shared.helsinki_profile.hp_client import HelsinkiProfileClient
from shared.oidc.utils import (
get_checksum_header,
@@ -26,10 +26,10 @@
class EauthAuthenticationRequestView(View):
"""
- Eauth client authentication HTTP endpoint
+ Eauth client authentication HTTP endpoint.
- See [backend/README.md](https://github.com/City-of-Helsinki/yjdh/blob/main/backend/README.md) for details
- about the auth flow.
+ See [backend/README.md](https://github.com/City-of-Helsinki/yjdh/blob/main/backend/README.md)
+ for details about the auth flow.
Docs that describe the flow (only in Finnish):
https://palveluhallinta.suomi.fi/fi/tuki/artikkelit/592d774503f6d100018db5dd
@@ -43,11 +43,15 @@ def login_failure(self):
def register_user(self, person_id):
"""
Docs of this method (only in Finnish):
- Search for "Web API -session aloitus eli rekisteröintipyyntö"
- https://palveluhallinta.suomi.fi/fi/tuki/artikkelit/592d774503f6d100018db5dd
+
+ Search for "Web API -session aloitus eli rekisteröintipyynt
+ "https://palveluhallinta.suomi.fi/fi/tuki/artikkelit/592d774503f6d100018db5dd
"""
request_id = uuid4()
- path = f"/service/ypa/user/register/{settings.EAUTHORIZATIONS_CLIENT_ID}/{person_id}?requestId={request_id}"
+ path = (
+ f"/service/ypa/user/register/{settings.EAUTHORIZATIONS_CLIENT_ID}"
+ f"/{person_id}?requestId={request_id}"
+ )
checksum_header = get_checksum_header(path)
@@ -61,11 +65,12 @@ def register_user(self, person_id):
return response.json()
def get(self, request):
- """Eauth client authentication initialization HTTP endpoint
+ """
+ Eauth client authentication initialization HTTP endpoint.
- NOTE: We should avoid raising exceptions from the method, because it results in user's auth flow
- ending on Django's 500 error page. We should instead call `self.login_failure()` to redirect the
- user to the login error page in the UI.
+ NOTE: We should avoid raising exceptions from the method, because it results in
+ user's auth flow ending on Django's 500 error page. We should instead call
+ `self.login_failure()` to redirect the user to the login error page in the UI.
"""
suomifi_enabled = getattr(settings, "NEXT_PUBLIC_ENABLE_SUOMIFI", False)
@@ -78,31 +83,29 @@ def get(self, request):
else:
if not request.session.get("oidc_access_token"):
return self.login_failure()
- print("session:", request.session.__dict__)
user_info = get_userinfo(request)
user_ssn = user_info.get("national_id_num")
- # When authenticating via Tunnistamo, we need to call Helsinki Profile GraphQL API
+ # When authenticating via Tunnistamo, we need to call Helsinki Profile
+ # GraphQL API
if user_ssn is None:
try:
profile = HelsinkiProfileClient().get_profile(
request.session.get("oidc_access_token")
)
- except HelsinkiProfileException as e:
- print(
- "Reading nationalIdentificationNumber from Helsinki Profile API failed: ",
- e,
- )
+ except HelsinkiProfileError as e:
logger.warning(
- f"Reading nationalIdentificationNumber from Helsinki Profile API failed: {str(e)}"
+ "Reading nationalIdentificationNumber from Helsinki Profile"
+ f" API failed: {str(e)}"
)
return self.login_failure()
user_ssn = profile["user_ssn"]
if user_ssn is None:
logger.warning(
- "Cannot use eauthorizations API due to missing nationalIdentificationNumber"
+ "Cannot use eauthorizations API due to missing"
+ " nationalIdentificationNumber"
)
return self.login_failure()
@@ -118,9 +121,11 @@ def get(self, request):
params = {
"client_id": settings.EAUTHORIZATIONS_CLIENT_ID,
"response_type": "code",
- "redirect_uri": request.build_absolute_uri(
- reverse("eauth_authentication_callback")
- ).replace("http://", "https://"),
+ "redirect_uri": (
+ request.build_absolute_uri(
+ reverse("eauth_authentication_callback")
+ ).replace("http://", "https://")
+ ),
"user": user_id,
}
@@ -136,7 +141,9 @@ def get(self, request):
class EauthAuthenticationCallbackView(View):
- """Eauth client callback HTTP endpoint"""
+ """
+ Eauth client callback HTTP endpoint.
+ """
http_method_names = ["get"]
@@ -159,7 +166,9 @@ def login_failure(self):
return HttpResponseRedirect(url)
def get_token_info(self, code):
- """Return token object as a dictionary."""
+ """
+ Return token object as a dictionary.
+ """
auth_header = HTTPBasicAuth(
settings.EAUTHORIZATIONS_CLIENT_ID,
settings.EAUTHORIZATIONS_API_OAUTH_SECRET,
@@ -170,9 +179,11 @@ def get_token_info(self, code):
params = {
"code": code,
"grant_type": "authorization_code",
- "redirect_uri": self.request.build_absolute_uri(
- reverse("eauth_authentication_callback")
- ).replace("http://", "https://"),
+ "redirect_uri": (
+ self.request.build_absolute_uri(
+ reverse("eauth_authentication_callback")
+ ).replace("http://", "https://")
+ ),
}
query = urlencode(params)
@@ -187,7 +198,9 @@ def get_token_info(self, code):
@method_decorator(ensure_csrf_cookie)
def get(self, request):
- """Eauth client authentication callback HTTP endpoint"""
+ """
+ Eauth client authentication callback HTTP endpoint.
+ """
if request.GET.get("error"):
if request.user.is_authenticated:
auth.logout(request)
diff --git a/backend/shared/shared/oidc/views/hki_views.py b/backend/shared/shared/oidc/views/hki_views.py
index acb5086b99..780c0f708b 100644
--- a/backend/shared/shared/oidc/views/hki_views.py
+++ b/backend/shared/shared/oidc/views/hki_views.py
@@ -25,7 +25,9 @@
class HelsinkiOIDCAuthenticationRequestView(OIDCAuthenticationRequestView):
- """Override OIDC client authentication request get method"""
+ """
+ Override OIDC client authentication request get method.
+ """
def get(self, request):
lang = request.GET.get("lang")
@@ -48,7 +50,9 @@ def get(self, request):
class HelsinkiOIDCAuthenticationCallbackView(OIDCAuthenticationCallbackView):
- """Override OIDC client authentication callback login success method"""
+ """
+ Override OIDC client authentication callback login success method.
+ """
def login_success(self):
super().login_success()
@@ -67,7 +71,9 @@ def login_failure(self):
class HelsinkiOIDCLogoutView(View):
"""
Initiate logout process with Keycloak.
- Use GET request like e.g. Django auth logout does."""
+
+ Use GET request like e.g. Django auth logout does.
+ """
http_method_names = ["get"]
@@ -92,20 +98,27 @@ def get(self, request):
class HelsinkiOIDCLogoutCallbackView(View):
- """This callback is called after the suomi.fi logout has been performed at the city profile"""
+ """
+ This callback is called after the suomi.fi logout has been performed at the
+ city profile.
+ """
http_method_names = ["get"]
def get(self, request):
- # As of 2021-12, the city profile does not provide any error/status codes along with the
- # callback. If such parameters are added in the future, we would handle them here.
+ # As of 2021-12, the city profile does not provide any error/status codes along
+ # with the
+ # callback. If such parameters are added in the future, we would handle them
+ # here.
# Now we just assume that the logout has been done successfully and redirect to
# the logout landing URL in the frontend.
return HttpResponseRedirect(settings.LOGOUT_REDIRECT_URL)
class HelsinkiOIDCUserInfoView(View):
- """Gets the userinfo from OP"""
+ """
+ Gets the userinfo from OP.
+ """
http_method_names = ["get"]
@@ -148,7 +161,7 @@ def get(self, request):
class HelsinkiOIDCBackchannelLogoutView(View):
"""
- Backchannel logout endpoint that can be called by helsinki profiili
+ Backchannel logout endpoint that can be called by helsinki profiili.
# noqa
Docs: https://helsinkisolutionoffice.atlassian.net/wiki/spaces/KAN/pages/1209040912/SSO+session+handling#About-backchannel-logout-requests
@@ -205,7 +218,8 @@ def post(self, request):
# In the rare case that two user accounts have the same email address,
# bail. Randomly selecting one seems really wrong.
logger.error(
- f"Login failed: Multiple users found with the given 'sub' claim: {claims.get('sub', None)}"
+ "Login failed: Multiple users found with the given 'sub' claim:"
+ f" {claims.get('sub', None)}"
)
return HttpResponse(
"Multiple users found with the given 'sub' claim",
diff --git a/backend/shared/shared/oidc/views/mock_views.py b/backend/shared/shared/oidc/views/mock_views.py
index c1194233d8..bcd7badc64 100644
--- a/backend/shared/shared/oidc/views/mock_views.py
+++ b/backend/shared/shared/oidc/views/mock_views.py
@@ -9,7 +9,9 @@
class MockLogoutView(View):
- """Mocked user logout"""
+ """
+ Mocked user logout.
+ """
http_method_names = ["get", "post"]
@@ -27,7 +29,9 @@ def post(self, request):
class MockLogoutCallbackView(View):
- """Mocked user logout callback URL"""
+ """
+ Mocked user logout callback URL.
+ """
http_method_names = ["get"]
@@ -36,7 +40,9 @@ def get(self, request):
class MockUserInfoView(View):
- """Get mocked userinfo of the logged in user"""
+ """
+ Get mocked userinfo of the logged in user.
+ """
http_method_names = ["get"]
@@ -54,7 +60,9 @@ def get(self, request):
class MockAuthenticationRequestView(View):
- """Mocked OIDC client authentication HTTP endpoint"""
+ """
+ Mocked OIDC client authentication HTTP endpoint.
+ """
http_method_names = ["get"]
@@ -66,6 +74,8 @@ def get(self, request, *args, **kwargs):
is_superuser=getattr(settings, "OIDC_MOCK_USER_IS_SUPERUSER", False),
)
auth.login(
- request, user, backend="django.contrib.auth.backends.ModelBackend" # type: ignore
+ request,
+ user,
+ backend="django.contrib.auth.backends.ModelBackend", # type: ignore
)
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL or "/")
diff --git a/backend/shared/shared/service_bus/enums.py b/backend/shared/shared/service_bus/enums.py
index 97c26f516c..88506659cd 100644
--- a/backend/shared/shared/service_bus/enums.py
+++ b/backend/shared/shared/service_bus/enums.py
@@ -8,8 +8,8 @@ class YtjOrganizationCode(models.IntegerChoices):
file: suomi_fi_palveluvayla_ytj_rajapinta_koodistot_v1_4.xlsx
Only the default organization form codes are listed here.
- The document from YTJ only has the names for the codes in Finnish. Also, the code names are only
- used in the handler UI so no translation required currently.
+ The document from YTJ only has the names for the codes in Finnish. Also, the code
+ names are only used in the handler UI so no translation required currently.
"""
ASSOCIATION_FORM_CODE_DEFAULT = 29, _("Muu yhdistys")
diff --git a/backend/shared/shared/service_bus/service_bus_client.py b/backend/shared/shared/service_bus/service_bus_client.py
index bfd5dc3e57..1877d58754 100644
--- a/backend/shared/shared/service_bus/service_bus_client.py
+++ b/backend/shared/shared/service_bus/service_bus_client.py
@@ -65,9 +65,11 @@ def _get_organisation_data_from_service_bus_data(
cls, service_bus_data: dict
) -> dict:
"""
- Get the required company fields from YTJ data. All data will be in Finnish
- Might throw ValueError if the data is not in correct format or there is a case
- that hasn't been covered in the code
+ Get the required company fields from YTJ data.
+
+ All data will be in Finnish Might throw ValueError if the data is not
+ in correct format or there is a case that hasn't been covered in the
+ code
"""
try:
@@ -106,7 +108,8 @@ def _get_company_form(cls, legal_form_json: dict) -> str:
def _get_industry(cls, business_line_json: dict) -> str:
# The BusinessLine value is a code, which is not human-readable.
# We'll try to get the description of the code in Finnish
- # In suomi.fi test env, some companies do not have this data, so assuming production
+ # In suomi.fi test env, some companies do not have this data, so assuming
+ # production
# env might have companies with missing data, too
try:
code_description = business_line_json["Type"]["Descriptions"][
diff --git a/backend/shared/shared/suomi_fi/attributemaps/user.py b/backend/shared/shared/suomi_fi/attributemaps/user.py
index 60a55eb4de..4ed6369f0a 100644
--- a/backend/shared/shared/suomi_fi/attributemaps/user.py
+++ b/backend/shared/shared/suomi_fi/attributemaps/user.py
@@ -67,8 +67,12 @@
# Limited personal information + eIDAS
"http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName": "FirstName",
# eIDAS
- "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName": "FamilyName",
- "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier": "PersonIdentifier",
+ "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName": (
+ "FamilyName"
+ ),
+ "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier": (
+ "PersonIdentifier"
+ ),
"http://eidas.europa.eu/attributes/naturalperson/DateOfBirth": "DateOfBirth",
},
"to": {
@@ -81,8 +85,12 @@
# Limited personal information + eIDAS
"FirstName": "http://eidas.europa.eu/attributes/naturalperson/CurrentGivenName",
# eIDAS
- "FamilyName": "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName",
- "PersonIdentifier": "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier",
+ "FamilyName": (
+ "http://eidas.europa.eu/attributes/naturalperson/CurrentFamilyName"
+ ),
+ "PersonIdentifier": (
+ "http://eidas.europa.eu/attributes/naturalperson/PersonIdentifier"
+ ),
"DateOfBirth": "http://eidas.europa.eu/attributes/naturalperson/DateOfBirth",
},
}
diff --git a/backend/shared/shared/suomi_fi/auth.py b/backend/shared/shared/suomi_fi/auth.py
index 55bf6d4759..6336cc8431 100644
--- a/backend/shared/shared/suomi_fi/auth.py
+++ b/backend/shared/shared/suomi_fi/auth.py
@@ -6,7 +6,8 @@
class SuomiFiSAML2AuthenticationBackend(Saml2Backend):
def clean_user_main_attribute(self, main_attribute: Any) -> Any:
- """Return hash of Suomi.fi SSO session identifier.
+ """
+ Return hash of Suomi.fi SSO session identifier.
SSO session identifier is over the normal 150 character username limit.
"""
diff --git a/backend/shared/shared/suomi_fi/utils.py b/backend/shared/shared/suomi_fi/utils.py
index 9775b94978..37b29e7cb5 100644
--- a/backend/shared/shared/suomi_fi/utils.py
+++ b/backend/shared/shared/suomi_fi/utils.py
@@ -9,7 +9,9 @@ def get_contact_person_configuration(
phone: str = None,
contact_type: str = None,
) -> Optional[dict]:
- """Get contact person configuration."""
+ """
+ Get contact person configuration.
+ """
if not (first_name and last_name and email and contact_type):
return None
diff --git a/backend/shared/shared/suomi_fi/views.py b/backend/shared/shared/suomi_fi/views.py
index c26582e460..d7805a3548 100644
--- a/backend/shared/shared/suomi_fi/views.py
+++ b/backend/shared/shared/suomi_fi/views.py
@@ -10,13 +10,16 @@
@method_decorator(csrf_exempt, name="dispatch")
class SuomiFiAssertionConsumerServiceView(AssertionConsumerServiceView):
"""
- Store user's national identification number into session instead of any User model.
+ Store user's national identification number into session instead of any
+ User model.
"""
def post_login_hook(
self, request: HttpRequest, user: settings.AUTH_USER_MODEL, session_info: dict
) -> None:
- """Pick national identification number from ava and put it to the session."""
+ """
+ Pick national identification number from ava and put it to the session.
+ """
ava = session_info.get("ava", {})
if user_ssn := ava.get("nationalIdentificationNumber"):
@@ -29,8 +32,8 @@ def post_login_hook(
class SuomiFiMetadataView(MetadataView):
"""
- Returns an XML with the SAML 2.0 metadata for this SP as
- configured in the settings.py file.
+ Returns an XML with the SAML 2.0 metadata for this SP as configured in the
+ settings.py file.
"""
def get(self, request, *args, **kwargs):
diff --git a/backend/shared/shared/vtj/vtj_client.py b/backend/shared/shared/vtj/vtj_client.py
index 28e4f1e83a..0a777b1ecb 100644
--- a/backend/shared/shared/vtj/vtj_client.py
+++ b/backend/shared/shared/vtj/vtj_client.py
@@ -8,7 +8,8 @@
class VTJClient:
"""
- Client for VTJ / Väestötietojärjestelmä i.e. Finnish Population Information System.
+ Client for VTJ / Väestötietojärjestelmä i.e. Finnish Population Information
+ System.
https://dvv.fi/en/population-information-system
"""
@@ -64,7 +65,7 @@ def get_personal_info(
auth=self._auth,
json=self._json(social_security_number, end_user),
timeout=self._timeout,
- **kwargs
+ **kwargs,
)
response.raise_for_status()
return response.json()
diff --git a/backend/shared/shared/yrtti/yrtti_client.py b/backend/shared/shared/yrtti/yrtti_client.py
index 1219e6013c..773ea85f22 100644
--- a/backend/shared/shared/yrtti/yrtti_client.py
+++ b/backend/shared/shared/yrtti/yrtti_client.py
@@ -80,21 +80,25 @@ def _get_association_data_from_yrtti_data(cls, yrtti_data: dict) -> dict:
"""
Get the required company fields from YRTTI data.
- The YRTTI API only returns data for associations, so the response does not contain
- a field for company form.
- Use the YTJ "yritysmuoto" code for associations when creating the Company objects
+ The YRTTI API only returns data for associations, so the response does
+ not contain a field for company form. Use the YTJ "yritysmuoto" code
+ for associations when creating the Company objects
"""
association_name_info = cls._get_active_association_name(
yrtti_data["AssociationNameInfo"]
)
- # There might be a list of addresses, but it is impossible to identify which one is the primary address from
- # the data so we just select the first one. Most of the time there is only 1 address
+ # There might be a list of addresses, but it is impossible to identify which one
+ # is the primary address from
+ # the data so we just select the first one. Most of the time there is only 1
+ # address
address = yrtti_data["Address"][0]
company_data = {
"name": association_name_info["AssociationName"],
"business_id": yrtti_data["BusinessId"],
"company_form": YtjOrganizationCode.ASSOCIATION_FORM_CODE_DEFAULT.label,
- "company_form_code": YtjOrganizationCode.ASSOCIATION_FORM_CODE_DEFAULT.value,
+ "company_form_code": (
+ YtjOrganizationCode.ASSOCIATION_FORM_CODE_DEFAULT.value
+ ),
"industry": association_name_info["AssociationIndustry"] or "",
"street_address": cls._sanitize_text(address["StreetName"]),
"postcode": address["PostCode"],
@@ -126,7 +130,8 @@ def _format_search_results(cls, search_results: list) -> list:
@classmethod
def _get_active_association_name(cls, name_info: list) -> dict:
- # If active Finnish name found, return it, otherwise return the first active name
+ # If active Finnish name found, return it, otherwise return the first active
+ # name
target_language_names = [
name
for name in name_info
diff --git a/package.json b/package.json
index 3a53d89933..07c9dec0b5 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,5 @@
{
"devDependencies": {
- "@commitlint/cli": "^19.8.0",
- "@commitlint/config-conventional": "^19.8.0",
"cross-env": "^7.0.3",
"husky": "^9.1.7"
},
@@ -9,7 +7,6 @@
"node": ">=22.13.1 <23.11.0"
},
"scripts": {
- "prepare": "husky",
"// clean: stop and remove docker containers and database volume": "",
"clean": "docker compose -f compose.handler.yml down --remove-orphans; docker compose -f compose.employer.yml down --remove-orphans; docker compose -f compose.benefit.yml down --remove-orphans; docker rm -f $(docker ps -a -q); docker volume rm $(docker volume ls -q);",
"// partial docker compose commands per service, dont use these straight. Use :up, :build or :rebuild instead ": "",
diff --git a/yarn.lock b/yarn.lock
index 76cf9ef0fa..28adee4ea9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,345 +2,6 @@
# yarn lockfile v1
-"@babel/code-frame@^7.0.0":
- version "7.22.13"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
- integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
- dependencies:
- "@babel/highlight" "^7.22.13"
- chalk "^2.4.2"
-
-"@babel/helper-validator-identifier@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193"
- integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==
-
-"@babel/highlight@^7.22.13":
- version "7.22.13"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16"
- integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==
- dependencies:
- "@babel/helper-validator-identifier" "^7.22.5"
- chalk "^2.4.2"
- js-tokens "^4.0.0"
-
-"@commitlint/cli@^19.8.0":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.8.1.tgz#85f7d9f331344e1f0a2b9d8b24fd3695466e1158"
- integrity sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==
- dependencies:
- "@commitlint/format" "^19.8.1"
- "@commitlint/lint" "^19.8.1"
- "@commitlint/load" "^19.8.1"
- "@commitlint/read" "^19.8.1"
- "@commitlint/types" "^19.8.1"
- tinyexec "^1.0.0"
- yargs "^17.0.0"
-
-"@commitlint/config-conventional@^19.8.0":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.8.1.tgz#eab42df58cda44f18410ae0cbd6785ece00f214b"
- integrity sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==
- dependencies:
- "@commitlint/types" "^19.8.1"
- conventional-changelog-conventionalcommits "^7.0.2"
-
-"@commitlint/config-validator@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-19.8.1.tgz#29e9bb1360fa41b9439b23d8e25deaaf097306b5"
- integrity sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==
- dependencies:
- "@commitlint/types" "^19.8.1"
- ajv "^8.11.0"
-
-"@commitlint/ensure@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-19.8.1.tgz#938c54d6f586bda600b5c8e8e842edb281546e14"
- integrity sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==
- dependencies:
- "@commitlint/types" "^19.8.1"
- lodash.camelcase "^4.3.0"
- lodash.kebabcase "^4.1.1"
- lodash.snakecase "^4.1.1"
- lodash.startcase "^4.4.0"
- lodash.upperfirst "^4.3.1"
-
-"@commitlint/execute-rule@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-19.8.1.tgz#53000363b737773e2d25e97c20f15eaa78742067"
- integrity sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==
-
-"@commitlint/format@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-19.8.1.tgz#3e09b1291b3e29092d7a86f0afbbcfc0d99d3ad4"
- integrity sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==
- dependencies:
- "@commitlint/types" "^19.8.1"
- chalk "^5.3.0"
-
-"@commitlint/is-ignored@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.8.1.tgz#fed0851360ea2d21799eaf8ec9ef6d98c15536e3"
- integrity sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==
- dependencies:
- "@commitlint/types" "^19.8.1"
- semver "^7.6.0"
-
-"@commitlint/lint@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.8.1.tgz#c21bf9000ca54e41c5b0139c98aaf12473c03bb0"
- integrity sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==
- dependencies:
- "@commitlint/is-ignored" "^19.8.1"
- "@commitlint/parse" "^19.8.1"
- "@commitlint/rules" "^19.8.1"
- "@commitlint/types" "^19.8.1"
-
-"@commitlint/load@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.8.1.tgz#b997b1f65a961bf0a47189f15f6dc8786ceb4576"
- integrity sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==
- dependencies:
- "@commitlint/config-validator" "^19.8.1"
- "@commitlint/execute-rule" "^19.8.1"
- "@commitlint/resolve-extends" "^19.8.1"
- "@commitlint/types" "^19.8.1"
- chalk "^5.3.0"
- cosmiconfig "^9.0.0"
- cosmiconfig-typescript-loader "^6.1.0"
- lodash.isplainobject "^4.0.6"
- lodash.merge "^4.6.2"
- lodash.uniq "^4.5.0"
-
-"@commitlint/message@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-19.8.1.tgz#d5d0d87837483d9f9b4559ffa06e1aaa26d266d6"
- integrity sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==
-
-"@commitlint/parse@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-19.8.1.tgz#73125d04f07f11477cf563cbfe0cc9f6dc85a747"
- integrity sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==
- dependencies:
- "@commitlint/types" "^19.8.1"
- conventional-changelog-angular "^7.0.0"
- conventional-commits-parser "^5.0.0"
-
-"@commitlint/read@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-19.8.1.tgz#812930fd0f616e796e122751cb983346e5454ec8"
- integrity sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==
- dependencies:
- "@commitlint/top-level" "^19.8.1"
- "@commitlint/types" "^19.8.1"
- git-raw-commits "^4.0.0"
- minimist "^1.2.8"
- tinyexec "^1.0.0"
-
-"@commitlint/resolve-extends@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-19.8.1.tgz#a44bb4c22e3e7d407cc9a3758fcf58f5c360b694"
- integrity sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==
- dependencies:
- "@commitlint/config-validator" "^19.8.1"
- "@commitlint/types" "^19.8.1"
- global-directory "^4.0.1"
- import-meta-resolve "^4.0.0"
- lodash.mergewith "^4.6.2"
- resolve-from "^5.0.0"
-
-"@commitlint/rules@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-19.8.1.tgz#1cea53d5bf970ce56dc105e1da5e6655a2fe7a5f"
- integrity sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==
- dependencies:
- "@commitlint/ensure" "^19.8.1"
- "@commitlint/message" "^19.8.1"
- "@commitlint/to-lines" "^19.8.1"
- "@commitlint/types" "^19.8.1"
-
-"@commitlint/to-lines@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-19.8.1.tgz#c1a28a84542c7ba321c1c11178b83ae024257b47"
- integrity sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==
-
-"@commitlint/top-level@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-19.8.1.tgz#2c942189d83a29b21ff7ba6e91607301efdf5916"
- integrity sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==
- dependencies:
- find-up "^7.0.0"
-
-"@commitlint/types@^19.8.1":
- version "19.8.1"
- resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-19.8.1.tgz#7971fbd56b0cfb31692a4e1941b74ac8217c44e5"
- integrity sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==
- dependencies:
- "@types/conventional-commits-parser" "^5.0.0"
- chalk "^5.3.0"
-
-"@types/conventional-commits-parser@^5.0.0":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz#8cb81cf170853496cbc501a3b32dcf5e46ffb61a"
- integrity sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==
- dependencies:
- "@types/node" "*"
-
-"@types/node@*":
- version "24.0.4"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-24.0.4.tgz#dbae889912bda33a7f57669fb8587c1a56bc0c1f"
- integrity sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA==
- dependencies:
- undici-types "~7.8.0"
-
-JSONStream@^1.3.5:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
- integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
- dependencies:
- jsonparse "^1.2.0"
- through ">=2.2.7 <3"
-
-ajv@^8.11.0:
- version "8.12.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
- integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
- dependencies:
- fast-deep-equal "^3.1.1"
- json-schema-traverse "^1.0.0"
- require-from-string "^2.0.2"
- uri-js "^4.2.2"
-
-ansi-regex@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
- integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
-
-ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
-ansi-styles@^4.0.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
- integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
- dependencies:
- color-convert "^2.0.1"
-
-argparse@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
- integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-
-array-ify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece"
- integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==
-
-callsites@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
- integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
-chalk@^2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^5.3.0:
- version "5.4.1"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8"
- integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==
-
-cliui@^8.0.1:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
- integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
- dependencies:
- string-width "^4.2.0"
- strip-ansi "^6.0.1"
- wrap-ansi "^7.0.0"
-
-color-convert@^1.9.0:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
- integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
- dependencies:
- color-name "1.1.3"
-
-color-convert@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
- integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
- dependencies:
- color-name "~1.1.4"
-
-color-name@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-
-color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-compare-func@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3"
- integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==
- dependencies:
- array-ify "^1.0.0"
- dot-prop "^5.1.0"
-
-conventional-changelog-angular@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a"
- integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==
- dependencies:
- compare-func "^2.0.0"
-
-conventional-changelog-conventionalcommits@^7.0.2:
- version "7.0.2"
- resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz#aa5da0f1b2543094889e8cf7616ebe1a8f5c70d5"
- integrity sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==
- dependencies:
- compare-func "^2.0.0"
-
-conventional-commits-parser@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#57f3594b81ad54d40c1b4280f04554df28627d9a"
- integrity sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==
- dependencies:
- JSONStream "^1.3.5"
- is-text-path "^2.0.0"
- meow "^12.0.1"
- split2 "^4.0.0"
-
-cosmiconfig-typescript-loader@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz#7f644503e1c2bff90aed2d29a637008f279646bb"
- integrity sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==
- dependencies:
- jiti "^2.4.1"
-
-cosmiconfig@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d"
- integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==
- dependencies:
- env-paths "^2.2.1"
- import-fresh "^3.3.0"
- js-yaml "^4.1.0"
- parse-json "^5.2.0"
-
cross-env@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
@@ -357,305 +18,21 @@ cross-spawn@^7.0.1:
shebang-command "^2.0.0"
which "^2.0.1"
-dargs@^8.0.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/dargs/-/dargs-8.1.0.tgz#a34859ea509cbce45485e5aa356fef70bfcc7272"
- integrity sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==
-
-dot-prop@^5.1.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
- integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
- dependencies:
- is-obj "^2.0.0"
-
-emoji-regex@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
- integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-
-env-paths@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
- integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
-
-error-ex@^1.3.1:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
- integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
- dependencies:
- is-arrayish "^0.2.1"
-
-escalade@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
- integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-escape-string-regexp@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
-
-fast-deep-equal@^3.1.1:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
- integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-
-find-up@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-7.0.0.tgz#e8dec1455f74f78d888ad65bf7ca13dd2b4e66fb"
- integrity sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==
- dependencies:
- locate-path "^7.2.0"
- path-exists "^5.0.0"
- unicorn-magic "^0.1.0"
-
-get-caller-file@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
- integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
-
-git-raw-commits@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285"
- integrity sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==
- dependencies:
- dargs "^8.0.0"
- meow "^12.0.1"
- split2 "^4.0.0"
-
-global-directory@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e"
- integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==
- dependencies:
- ini "4.1.1"
-
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
-
husky@^9.1.7:
version "9.1.7"
resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d"
integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==
-import-fresh@^3.3.0:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf"
- integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-import-meta-resolve@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#f9db8bead9fafa61adb811db77a2bf22c5399706"
- integrity sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==
-
-ini@4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1"
- integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==
-
-is-arrayish@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
- integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
-
-is-fullwidth-code-point@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
- integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-
-is-obj@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
- integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
-
-is-text-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636"
- integrity sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==
- dependencies:
- text-extensions "^2.0.0"
-
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-jiti@^2.4.1:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560"
- integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==
-
-js-tokens@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
- integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-
-js-yaml@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
- integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
- dependencies:
- argparse "^2.0.1"
-
-json-parse-even-better-errors@^2.3.0:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
- integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-
-json-schema-traverse@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
- integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
-
-jsonparse@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
- integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
-
-lines-and-columns@^1.1.6:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
- integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-
-locate-path@^7.2.0:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a"
- integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==
- dependencies:
- p-locate "^6.0.0"
-
-lodash.camelcase@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
- integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
-
-lodash.isplainobject@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
- integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
-
-lodash.kebabcase@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
- integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==
-
-lodash.merge@^4.6.2:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
- integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-
-lodash.mergewith@^4.6.2:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
- integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
-
-lodash.snakecase@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
- integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==
-
-lodash.startcase@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8"
- integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==
-
-lodash.uniq@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
- integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
-
-lodash.upperfirst@^4.3.1:
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce"
- integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==
-
-meow@^12.0.1:
- version "12.1.1"
- resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6"
- integrity sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==
-
-minimist@^1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
- integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
-
-p-limit@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644"
- integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==
- dependencies:
- yocto-queue "^1.0.0"
-
-p-locate@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f"
- integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==
- dependencies:
- p-limit "^4.0.0"
-
-parent-module@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
- integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
- dependencies:
- callsites "^3.0.0"
-
-parse-json@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
- integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- error-ex "^1.3.1"
- json-parse-even-better-errors "^2.3.0"
- lines-and-columns "^1.1.6"
-
-path-exists@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7"
- integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==
-
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-punycode@^2.1.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
- integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
-
-require-directory@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
- integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
-
-require-from-string@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
- integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
-
-resolve-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
- integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
-resolve-from@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
- integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
-
-semver@^7.6.0:
- version "7.7.2"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
- integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
-
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -668,106 +45,9 @@ shebang-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-split2@^4.0.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
- integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
-
-string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
-supports-color@^5.3.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
- integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
- dependencies:
- has-flag "^3.0.0"
-
-text-extensions@^2.0.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34"
- integrity sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==
-
-"through@>=2.2.7 <3":
- version "2.3.8"
- resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
- integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
-
-tinyexec@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-1.0.1.tgz#70c31ab7abbb4aea0a24f55d120e5990bfa1e0b1"
- integrity sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==
-
-undici-types@~7.8.0:
- version "7.8.0"
- resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.8.0.tgz#de00b85b710c54122e44fbfd911f8d70174cd294"
- integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==
-
-unicorn-magic@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4"
- integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==
-
-uri-js@^4.2.2:
- version "4.4.1"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
- integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
- dependencies:
- punycode "^2.1.0"
-
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
-
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
-y18n@^5.0.5:
- version "5.0.8"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
- integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
-
-yargs-parser@^21.1.1:
- version "21.1.1"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
- integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
-
-yargs@^17.0.0:
- version "17.7.2"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
- integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
- dependencies:
- cliui "^8.0.1"
- escalade "^3.1.1"
- get-caller-file "^2.0.5"
- require-directory "^2.1.1"
- string-width "^4.2.3"
- y18n "^5.0.5"
- yargs-parser "^21.1.1"
-
-yocto-queue@^1.0.0:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.1.tgz#36d7c4739f775b3cbc28e6136e21aa057adec418"
- integrity sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==