Skip to content

Commit

Permalink
HL-897, HL-943, HL-942, HL-977: New terms application forms (#2286)
Browse files Browse the repository at this point in the history
* feat: new benefit terms modifications (handler)

* feat: new subsidy options

* feat: continue new terms changes

* feat: fix date inputs

* fix: wrong i18n import and usage of static props errored in nextjs console

* fix: koros id SSR / client mismatch; use correct bg color for footer

* feat: add font weight and heading level prop to form section

* feat: restructure application step 1

* docs: add some notes to .env example

* fix: de_minimis_aid can be either False or None

* feat!: restructure frontend of application step 2

* refactor!: only use one benefit type; pay_subsidy_granted as string

pay_subsidy_granted can be "default", "aged" or "no"; only use salary_benefit; check apprenticeship_program validation on save

* refactor: localization update per new translations

* feat: use env to set TestCafe timeouts for local testing

* refactor: browser tests are on par with step 1 and 2 changes

* refactor: backend tests compatible with pay_subsidy_granted type change

* feat: merge 943 and companysection

* feat: first handler app with new terms

* feat!: database migration to new terms

* fix: correct translations

* fix: linter

* fix: remove employee phone_number test

* fix: lint, ts, i18n

* fix: skip flaking ahjo test

* fix: merged feature backend tests

* fix: bugs related to step 2

---------

Co-authored-by: Sampo Tawast <sampo.tawast@gmail.com>
Co-authored-by: Janne Juhola <janne.juhola@varaani.com>
  • Loading branch information
3 people committed Sep 26, 2023
1 parent 557e823 commit de31e8a
Show file tree
Hide file tree
Showing 67 changed files with 1,961 additions and 2,026 deletions.
2 changes: 1 addition & 1 deletion .env.benefit-backend.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ CORS_ALLOW_ALL_ORIGINS=1
# Debugging options
#
# if changing DUMMY_COMPANY_FORM_CODE, also set NEXT_PUBLIC_MOCK_FLAG=1
# DUMMY_COMPANY_FORM_CODE=16
# DUMMY_COMPANY_FORM_CODE=16 # or 29 for association (requires db flush and compose down & up)
NEXT_PUBLIC_MOCK_FLAG=1
DISABLE_TOS_APPROVAL_CHECK=1

Expand Down
66 changes: 51 additions & 15 deletions backend/benefit/applications/api/v1/serializers/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
AttachmentType,
BenefitType,
OrganizationType,
PaySubsidyGranted,
)
from applications.models import (
Application,
Expand Down Expand Up @@ -657,7 +658,7 @@ def _validate_de_minimis_aid_set(
if (
OrganizationType.resolve_organization_type(company.company_form_code)
== OrganizationType.ASSOCIATION
and de_minimis_aid is not None
and de_minimis_aid not in [None, False]
and not association_has_business_activities
):
raise serializers.ValidationError(
Expand Down Expand Up @@ -752,11 +753,7 @@ def _validate_co_operation_negotiations(
def _validate_pay_subsidy(
self, pay_subsidy_granted, pay_subsidy_percent, additional_pay_subsidy_percent
):
if pay_subsidy_granted and pay_subsidy_percent is None:
raise serializers.ValidationError(
{"pay_subsidy_percent": _("Pay subsidy percent required")}
)
if not pay_subsidy_granted:
if pay_subsidy_granted == PaySubsidyGranted.NOT_GRANTED:
for key in ["pay_subsidy_percent", "additional_pay_subsidy_percent"]:
if locals()[key] is not None:
raise serializers.ValidationError(
Expand Down Expand Up @@ -813,7 +810,10 @@ def _validate_non_draft_required_fields(self, data):

# if pay_subsidy_granted is selected, then the applicant needs to also select if
# it's an apprenticeship_program or not
if data["pay_subsidy_granted"]:
if data["pay_subsidy_granted"] in [
PaySubsidyGranted.GRANTED_AGED,
PaySubsidyGranted.GRANTED,
]:
required_fields.append("apprenticeship_program")

for field_name in required_fields:
Expand Down Expand Up @@ -862,7 +862,7 @@ def _validate_benefit_type(
apprenticeship_program,
pay_subsidy_granted,
):
if benefit_type == "":
if benefit_type == BenefitType.SALARY_BENEFIT or benefit_type == "":
return
if (
benefit_type
Expand All @@ -877,6 +877,36 @@ def _validate_benefit_type(
{"benefit_type": _("This benefit type can not be selected")}
)

def _validate_apprenticeship_program(
self, apprenticeship_program, pay_subsidy_granted, status
):
if status == ApplicationStatus.DRAFT:
return
if (
pay_subsidy_granted == PaySubsidyGranted.NOT_GRANTED
and apprenticeship_program is not None
):
raise serializers.ValidationError(
{
"apprenticeship_program": _(
"Apprenticeship program can not be selected if there is no granted pay subsidy"
)
}
)

if (
pay_subsidy_granted
in [PaySubsidyGranted.GRANTED_AGED, PaySubsidyGranted.GRANTED]
and apprenticeship_program is None
):
raise serializers.ValidationError(
{
"apprenticeship_program": _(
"Apprenticeship program has to be yes or no if there is a granted pay subsidy"
)
}
)

@staticmethod
def _get_available_benefit_types(
company,
Expand All @@ -888,25 +918,26 @@ 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
"""

if (
OrganizationType.resolve_organization_type(company.company_form_code)
== OrganizationType.ASSOCIATION
and not association_has_business_activities
):
benefit_types = [BenefitType.SALARY_BENEFIT] if pay_subsidy_granted else []
benefit_types = [
BenefitType.SALARY_BENEFIT,
]
else:
if apprenticeship_program:
benefit_types = [BenefitType.EMPLOYMENT_BENEFIT]
if pay_subsidy_granted:
benefit_types.append(BenefitType.SALARY_BENEFIT)
benefit_types = [
BenefitType.EMPLOYMENT_BENEFIT,
BenefitType.SALARY_BENEFIT,
]
else:
benefit_types = [
BenefitType.COMMISSION_BENEFIT,
BenefitType.EMPLOYMENT_BENEFIT,
BenefitType.SALARY_BENEFIT,
]
if pay_subsidy_granted:
benefit_types.append(BenefitType.SALARY_BENEFIT)
return benefit_types

def _handle_breaking_changes(self, company, data):
Expand Down Expand Up @@ -1003,6 +1034,11 @@ def validate(self, data):
data.get("apprenticeship_program"),
data.get("pay_subsidy_granted"),
)
self._validate_apprenticeship_program(
data.get("apprenticeship_program"),
data.get("pay_subsidy_granted"),
data.get("status"),
)
self._validate_non_draft_required_fields(data)
return data

Expand Down
9 changes: 0 additions & 9 deletions backend/benefit/applications/api/v1/serializers/employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from stdnum.fi import hetu

from applications.models import Employee
from common.utils import PhoneNumberField
from helsinkibenefit.settings import MINIMUM_WORKING_HOURS_PER_WEEK


Expand All @@ -13,21 +12,13 @@ class EmployeeSerializer(serializers.ModelSerializer):
Employee objects are meant to be edited together with their Application object.
"""

phone_number = PhoneNumberField(
allow_blank=True,
help_text=(
"Employee phone number normalized (start with zero, without country code)"
),
)

class Meta:
model = Employee
fields = [
"id",
"first_name",
"last_name",
"social_security_number",
"phone_number",
"email",
"employee_language",
"job_title",
Expand Down
6 changes: 6 additions & 0 deletions backend/benefit/applications/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,9 @@ class AhjoDecision(models.TextChoices):
class ApplicationOrigin(models.TextChoices):
HANDLER = "handler", _("Handler")
APPLICANT = "applicant", _("Applicant")


class PaySubsidyGranted(models.TextChoices):
GRANTED = "granted", _("Pay subsidy granted (default)")
GRANTED_AGED = "granted_aged", _("Pay subsidy granted (aged)")
NOT_GRANTED = "not_granted", _("No granted pay subsidy")
78 changes: 78 additions & 0 deletions backend/benefit/applications/migrations/0040_pay_subsidy_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Generated by Django 3.2.18 on 2023-09-21 10:39

from django.db import migrations, models
from applications.enums import PaySubsidyGranted


def migrate_pay_subsidy_types(apps, _):
def _migrate_pay_subsidy_types(applications):
for app in applications.objects.all():
app.pay_subsidy_granted = (
PaySubsidyGranted.GRANTED
if app.pay_subsidy_granted_old
else PaySubsidyGranted.NOT_GRANTED
)
app.save()

application = apps.get_model("applications", "Application")
hist_application = apps.get_model("applications", "HistoricalApplication")
_migrate_pay_subsidy_types(application)
_migrate_pay_subsidy_types(hist_application)


class Migration(migrations.Migration):
dependencies = [
("applications", "0039_alter_paysubsidy_percentages"),
]

operations = [
migrations.RenameField(
model_name="application",
old_name="pay_subsidy_granted",
new_name="pay_subsidy_granted_old",
),
migrations.RenameField(
model_name="historicalapplication",
old_name="pay_subsidy_granted",
new_name="pay_subsidy_granted_old",
),
migrations.AddField(
model_name="application",
name="pay_subsidy_granted",
field=models.CharField(
blank=True,
choices=[
("granted", "Pay subsidy granted (default)"),
("granted_aged", "Pay subsidy granted (aged)"),
("not_granted", "No granted pay subsidy"),
],
max_length=128,
null=True,
),
),
migrations.AddField(
model_name="historicalapplication",
name="pay_subsidy_granted",
field=models.CharField(
blank=True,
choices=[
("granted", "Pay subsidy granted (default)"),
("granted_aged", "Pay subsidy granted (aged)"),
("not_granted", "No granted pay subsidy"),
],
max_length=128,
null=True,
),
),
migrations.RunPython(
migrate_pay_subsidy_types, reverse_code=migrations.RunPython.noop
),
migrations.RemoveField(
model_name="application",
name="pay_subsidy_granted_old",
),
migrations.RemoveField(
model_name="historicalapplication",
name="pay_subsidy_granted_old",
),
]
12 changes: 10 additions & 2 deletions backend/benefit/applications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ApplicationStep,
AttachmentType,
BenefitType,
PaySubsidyGranted,
)
from applications.exceptions import (
BatchCompletionDecisionDateError,
Expand Down Expand Up @@ -255,7 +256,12 @@ class Application(UUIDModel, TimeStampedModel, DurationMixin):
blank=True,
)

pay_subsidy_granted = models.BooleanField(null=True)
pay_subsidy_granted = models.CharField(
choices=PaySubsidyGranted.choices,
max_length=128,
null=True,
blank=True,
)

# The PaySubsidy model stores the values entered by handlers for the calculation.
# This field is filled by the applicant.
Expand Down Expand Up @@ -306,7 +312,9 @@ def get_available_benefit_types(self):
self.is_association_application()
and not self.association_has_business_activities
):
return [BenefitType.SALARY_BENEFIT]
return [
BenefitType.SALARY_BENEFIT,
]
else:
return [
BenefitType.SALARY_BENEFIT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def CSV_COLUMNS(self):
),
CsvColumn("YT-neuvottelut?", "co_operation_negotiations", format_bool),
CsvColumn("YT-neuvottelut/tiedot", "co_operation_negotiations_description"),
CsvColumn("Palkkatuki myönnetty?", "pay_subsidy_granted", format_bool),
CsvColumn("Palkkatuki myönnetty?", "pay_subsidy_granted", str),
csv_default_column("Palkkatukiprosentti", "pay_subsidy_percent"),
csv_default_column(
"Toinen palkkatukiprosentti", "additional_pay_subsidy_percent"
Expand Down
11 changes: 8 additions & 3 deletions backend/benefit/applications/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

import factory

from applications.enums import ApplicationStatus, ApplicationStep, BenefitType
from applications.enums import (
ApplicationStatus,
ApplicationStep,
BenefitType,
PaySubsidyGranted,
)
from applications.models import (
AhjoDecision,
Application,
Expand Down Expand Up @@ -97,12 +102,12 @@ class ApplicationFactory(factory.django.DjangoModelFactory):
co_operation_negotiations_description = factory.Maybe(
"co_operation_negotiations", factory.Faker("paragraph"), ""
)
pay_subsidy_granted = False
pay_subsidy_granted = PaySubsidyGranted.NOT_GRANTED
pay_subsidy_percent = None

additional_pay_subsidy_percent = None

apprenticeship_program = factory.Faker("boolean")
apprenticeship_program = None
archived = False
application_step = ApplicationStep.STEP_1
benefit_type = BenefitType.EMPLOYMENT_BENEFIT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ def test_generate_composed_template_html(mock_pdf_convert):
)


@pytest.mark.skip(reason="flaking because of unique username conflict")
def test_export_application_batch(application_batch):
application_batch.applications.add(
DecidedApplicationFactory.create(
Expand Down
Loading

0 comments on commit de31e8a

Please sign in to comment.