From 84916efbeff5981eef5a8c025aa9c17472ca982a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Riku=20Kestila=CC=88?= Date: Wed, 23 Oct 2024 17:48:28 +0300 Subject: [PATCH] feat: instalment model --- .../benefit/applications/tests/factories.py | 15 ++++ backend/benefit/calculator/enums.py | 9 ++ .../calculator/migrations/0017_instalment.py | 84 +++++++++++++++++++ backend/benefit/calculator/models.py | 40 ++++++++- backend/benefit/calculator/tests/factories.py | 30 +++++++ 5 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 backend/benefit/calculator/migrations/0017_instalment.py diff --git a/backend/benefit/applications/tests/factories.py b/backend/benefit/applications/tests/factories.py index 9e6caa57da..fd7f1fab2b 100755 --- a/backend/benefit/applications/tests/factories.py +++ b/backend/benefit/applications/tests/factories.py @@ -248,6 +248,7 @@ def handling_log_event(self, created, extracted, **kwargs): @factory.post_generation def calculation(self, created, extracted, **kwargs): from calculator.tests.factories import ( # avoid circular import + InstalmentFactory, PaySubsidyFactory, ) @@ -267,6 +268,20 @@ def calculation(self, created, extracted, **kwargs): start_date=self.calculation.start_date, end_date=self.calculation.end_date, ) + + InstalmentFactory( + calculation=self.calculation, + instalment_number=1, + amount=9600.00, + due_date=self.start_date, + ) + + InstalmentFactory( + calculation=self.calculation, + instalment_number=2, + amount=2000.00, + due_date=self.start_date + timedelta(days=30), + ) self.calculation.calculate() self.status = previous_status self.save() diff --git a/backend/benefit/calculator/enums.py b/backend/benefit/calculator/enums.py index 2aaa54fdd3..a9aca112fa 100644 --- a/backend/benefit/calculator/enums.py +++ b/backend/benefit/calculator/enums.py @@ -28,3 +28,12 @@ class DescriptionType(models.TextChoices): DATE = "date", _("Basic date range description") DATE_TOTAL = "date_total", _("Date range description for total row") DEDUCTION = "deduction", _("Deduction description") + + +class InstalmentStatus(models.TextChoices): + WAITING = "waiting", _("Waiting") + ACCEPTED = "accepted", _("Accepted") + PAID = "paid", _("Paid") + CANCELLED = "cancelled", _("Cancelled") + ERROR_IN_TALPA = "error_in_talpa", _("Error in TALPA") + COMPLETED = "completed", _("Completed") diff --git a/backend/benefit/calculator/migrations/0017_instalment.py b/backend/benefit/calculator/migrations/0017_instalment.py new file mode 100644 index 0000000000..c0611fbd36 --- /dev/null +++ b/backend/benefit/calculator/migrations/0017_instalment.py @@ -0,0 +1,84 @@ +# 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 + + +class Migration(migrations.Migration): + dependencies = [ + ("calculator", "0016_change_pay_subsidy_work_time_default"), + ] + + operations = [ + migrations.CreateModel( + name="Instalment", + 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, + ), + ), + ("instalment_number", models.IntegerField()), + ( + "amount", + models.DecimalField( + blank=True, + decimal_places=2, + max_digits=7, + verbose_name="row amount", + ), + ), + ( + "due_date", + models.DateField(blank=True, null=True, verbose_name="Due date"), + ), + ( + "status", + models.CharField( + blank=True, + choices=[ + ("waiting", "Waiting"), + ("accepted", "Accepted"), + ("paid", "Paid"), + ("cancelled", "Cancelled"), + ("error_in_talpa", "Error in TALPA"), + ("completed", "Completed"), + ], + default="waiting", + max_length=64, + verbose_name="status", + ), + ), + ( + "calculation", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="instalments", + to="calculator.calculation", + verbose_name="calculation", + ), + ), + ], + options={ + "verbose_name": "instalment", + "verbose_name_plural": "instalments", + "db_table": "bf_calculator_instalment", + "ordering": ("created_at",), + }, + ), + ] diff --git a/backend/benefit/calculator/models.py b/backend/benefit/calculator/models.py index 6b8f974a19..f3c76e2d22 100644 --- a/backend/benefit/calculator/models.py +++ b/backend/benefit/calculator/models.py @@ -10,7 +10,7 @@ from simple_history.models import HistoricalRecords from applications.models import Application, PAY_SUBSIDY_PERCENT_CHOICES -from calculator.enums import DescriptionType, RowType +from calculator.enums import DescriptionType, InstalmentStatus, RowType from common.exceptions import BenefitAPIException from common.utils import ( date_range_overlap, @@ -831,3 +831,41 @@ def calculate_amount(self): class Meta: proxy = True + + +class Instalment(UUIDModel, TimeStampedModel): + """ + Instalment model for Helsinki benefit grantend benefits that are paid in (two )instalments + """ + + calculation = models.ForeignKey( + Calculation, + verbose_name=_("calculation"), + related_name="instalments", + on_delete=models.CASCADE, + ) + + instalment_number = models.IntegerField() + + amount = models.DecimalField( + max_digits=7, + decimal_places=2, + verbose_name=_("row amount"), + blank=True, + ) + + due_date = models.DateField(blank=True, null=True, verbose_name=_("Due date")) + + status = models.CharField( + max_length=64, + verbose_name=_("status"), + choices=InstalmentStatus.choices, + default=InstalmentStatus.WAITING, + blank=True, + ) + + class Meta: + db_table = "bf_calculator_instalment" + verbose_name = _("instalment") + verbose_name_plural = _("instalments") + ordering = ("created_at",) diff --git a/backend/benefit/calculator/tests/factories.py b/backend/benefit/calculator/tests/factories.py index bd1d8190e4..376cf0f1a7 100644 --- a/backend/benefit/calculator/tests/factories.py +++ b/backend/benefit/calculator/tests/factories.py @@ -9,6 +9,7 @@ from calculator.models import ( Calculation, CalculationRow, + Instalment, PaySubsidy, PreviousBenefit, STATE_AID_MAX_PERCENTAGE_CHOICES, @@ -142,3 +143,32 @@ class PreviousBenefitFactory(factory.django.DjangoModelFactory): class Meta: model = PreviousBenefit + + +class InstalmentFactory(factory.django.DjangoModelFactory): + due_date = ( + factory.Faker( + "date_between_dates", + date_start=date(date.today().year, 1, 1), + date_end=date.today() + timedelta(days=100), + ), + ) + + class Meta: + model = Instalment + + +class CalculationWithInstalmentsFactory(CalculationFactory): + instalment_1 = factory.RelatedFactory( + InstalmentFactory, + instalment_number=1, + amount=decimal.Decimal("9600"), + factory_related_name="calculation", + ) + + instalment_2 = factory.RelatedFactory( + InstalmentFactory, + instalment_numberr=2, + amount=decimal.Decimal("2000"), + factory_related_name="calculation", + )