From 73f3887941c05616273e0a5a53743b53ca806faf Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Tue, 11 Oct 2022 13:31:00 +0200 Subject: [PATCH 1/2] Hotfix for ordering of availability * fixes error 500 in case of ordering by availability --- compensation/tables/eco_account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compensation/tables/eco_account.py b/compensation/tables/eco_account.py index 17b8eca..39a74d7 100644 --- a/compensation/tables/eco_account.py +++ b/compensation/tables/eco_account.py @@ -36,7 +36,7 @@ class EcoAccountTable(BaseTable, TableRenderMixin): ) av = tables.Column( verbose_name=_("Available"), - orderable=True, + orderable=False, empty_values=[], attrs={ "th": { -- 2.38.5 From 68dfef18c589b69c28fcd0432cc9cad85c5f93b7 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Tue, 11 Oct 2022 15:20:11 +0200 Subject: [PATCH 2/2] Fixes EcoAccount availability ordering * adds db based table ordering for EcoAccountTable --- .../0011_ecoaccount_deductable_rest.py | 36 +++++++++++++++ compensation/models/eco_account.py | 46 +++++++++++++++---- compensation/tables/eco_account.py | 11 +++-- .../tests/ecoaccount/test_workflow.py | 2 +- compensation/views/eco_account/eco_account.py | 3 +- 5 files changed, 83 insertions(+), 15 deletions(-) create mode 100644 compensation/migrations/0011_ecoaccount_deductable_rest.py diff --git a/compensation/migrations/0011_ecoaccount_deductable_rest.py b/compensation/migrations/0011_ecoaccount_deductable_rest.py new file mode 100644 index 0000000..96ab2d3 --- /dev/null +++ b/compensation/migrations/0011_ecoaccount_deductable_rest.py @@ -0,0 +1,36 @@ +# Generated by Django 3.1.3 on 2022-10-11 11:39 + +from django.db import migrations, models +from django.db.models import Sum + + +def fill_deductable_rest(apps, schema_editor): + EcoAccount = apps.get_model("compensation", "EcoAccount") + accs = EcoAccount.objects.all() + for acc in accs: + + deductions = acc.deductions.filter( + intervention__deleted=None, + ) + deductions_surfaces = deductions.aggregate(Sum("surface"))["surface__sum"] or 0 + available_surfaces = acc.deductable_surface or deductions_surfaces + rest = available_surfaces - deductions_surfaces + + acc.deductable_rest = rest + acc.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('compensation', '0010_auto_20220815_1030'), + ] + + operations = [ + migrations.AddField( + model_name='ecoaccount', + name='deductable_rest', + field=models.FloatField(blank=True, default=0, help_text='Amount of deductable rest', null=True), + ), + migrations.RunPython(fill_deductable_rest) + ] diff --git a/compensation/models/eco_account.py b/compensation/models/eco_account.py index dc9e336..48414cc 100644 --- a/compensation/models/eco_account.py +++ b/compensation/models/eco_account.py @@ -35,6 +35,12 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix help_text="Amount of deductable surface - can be lower than the total surface due to deduction limitations", default=0, ) + deductable_rest = models.FloatField( + blank=True, + null=True, + help_text="Amount of deductable rest", + default=0, + ) legal = models.OneToOneField( "intervention.Legal", @@ -100,28 +106,22 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix """ return self.after_states.all().aggregate(Sum("surface"))["surface__sum"] or 0 - def get_available_rest(self) -> (float, float): + def __calculate_deductable_rest(self): """ Calculates available rest surface of the eco account Args: Returns: ret_val_total (float): Total amount - ret_val_relative (float): Amount as percentage (0-100) """ deductions = self.deductions.filter( intervention__deleted=None, ) deductions_surfaces = deductions.aggregate(Sum("surface"))["surface__sum"] or 0 available_surfaces = self.deductable_surface or deductions_surfaces ## no division by zero - ret_val_total = available_surfaces - deductions_surfaces - - if available_surfaces > 0: - ret_val_relative = int((ret_val_total / available_surfaces) * 100) - else: - ret_val_relative = 0 + ret_val = available_surfaces - deductions_surfaces - return ret_val_total, ret_val_relative + return ret_val def quality_check(self) -> EcoAccountQualityChecker: """ Quality check @@ -181,6 +181,29 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix for team_id in shared_teams: celery_send_mail_deduction_changed_team.delay(self.identifier, self.title, team_id, data_change) + def update_deductable_rest(self): + """ + Updates deductable_rest, which holds the amount of rest surface for this account. + + Returns: + + """ + self.deductable_rest = self.__calculate_deductable_rest() + self.save() + + def get_deductable_rest_relative(self): + """ + Returns deductable_rest relative to deductable_surface mapped to [0,100] + + Returns: + + """ + try: + ret_val = int((self.deductable_rest / (self.deductable_surface or 0)) * 100) + except ZeroDivisionError: + ret_val = 0 + return ret_val + class EcoAccountDocument(AbstractDocument): """ @@ -272,3 +295,8 @@ class EcoAccountDeduction(BaseResource): self.intervention.mark_as_edited(user, edit_comment=DEDUCTION_REMOVED) self.account.mark_as_edited(user, edit_comment=DEDUCTION_REMOVED) super().delete(*args, **kwargs) + self.account.update_deductable_rest() + + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + self.account.update_deductable_rest() diff --git a/compensation/tables/eco_account.py b/compensation/tables/eco_account.py index 39a74d7..7cd121f 100644 --- a/compensation/tables/eco_account.py +++ b/compensation/tables/eco_account.py @@ -36,8 +36,8 @@ class EcoAccountTable(BaseTable, TableRenderMixin): ) av = tables.Column( verbose_name=_("Available"), - orderable=False, - empty_values=[], + orderable=True, + accessor="deductable_rest", attrs={ "th": { "class": "w-20", @@ -100,13 +100,16 @@ class EcoAccountTable(BaseTable, TableRenderMixin): """ Renders the available column for an eco account Args: - value (str): The identifier value + value (float): The deductable_rest record (EcoAccount): The eco account record Returns: """ - value_total, value_relative = record.get_available_rest() + try: + value_relative = record.get_deductable_rest_relative() + except ZeroDivisionError: + value_relative = 0 html = render_to_string("konova/widgets/progressbar.html", {"value": value_relative}) return format_html(html) diff --git a/compensation/tests/ecoaccount/test_workflow.py b/compensation/tests/ecoaccount/test_workflow.py index d1a3cf0..c7efb05 100644 --- a/compensation/tests/ecoaccount/test_workflow.py +++ b/compensation/tests/ecoaccount/test_workflow.py @@ -230,7 +230,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase): self.assertTrue(self.intervention.log.first().action == UserAction.EDITED) def test_edit_deduction(self): - test_surface = self.eco_account.get_available_rest()[0] + test_surface = self.eco_account.deductable_rest self.eco_account.set_recorded(self.superuser) self.intervention.share_with_user(self.superuser) self.eco_account.refresh_from_db() diff --git a/compensation/views/eco_account/eco_account.py b/compensation/views/eco_account/eco_account.py index f75fcc1..1d259b9 100644 --- a/compensation/views/eco_account/eco_account.py +++ b/compensation/views/eco_account/eco_account.py @@ -200,7 +200,8 @@ def detail_view(request: HttpRequest, id: str): sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0 diff_states = abs(sum_before_states - sum_after_states) # Calculate rest of available surface for deductions - available_total, available_relative = acc.get_available_rest() + available_total = acc.deductable_rest + available_relative = acc.get_deductable_rest_relative() # Prefetch related data to decrease the amount of db connections deductions = acc.deductions.filter( -- 2.38.5