From ad2f4c12f8b9f0366cf372a820c1309f2a32c268 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Fri, 25 Aug 2023 09:13:46 +0200 Subject: [PATCH] # 342 Fix * fixes bug where rounding error on aggregated db SUM() would occur * simplifies code base --- compensation/models/compensation.py | 4 +++- compensation/models/eco_account.py | 19 +++++-------------- compensation/utils/quality.py | 2 +- .../views/compensation/compensation.py | 6 ++---- compensation/views/eco_account/eco_account.py | 4 ++-- ema/views/ema.py | 4 ++-- konova/tests/test_views.py | 2 +- 7 files changed, 16 insertions(+), 25 deletions(-) diff --git a/compensation/models/compensation.py b/compensation/models/compensation.py index 3a23816..33c2008 100644 --- a/compensation/models/compensation.py +++ b/compensation/models/compensation.py @@ -199,7 +199,9 @@ class AbstractCompensation(BaseObject, Returns: """ - return qs.aggregate(Sum("surface"))["surface__sum"] or 0 + val = qs.aggregate(Sum("surface"))["surface__sum"] or 0 + val = float('{:0.2f}'.format(val)) + return val def quality_check(self) -> CompensationQualityChecker: """ Performs data quality check diff --git a/compensation/models/eco_account.py b/compensation/models/eco_account.py index 35e4c02..913937d 100644 --- a/compensation/models/eco_account.py +++ b/compensation/models/eco_account.py @@ -57,7 +57,7 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix def clean(self): # Deductable surface can not be larger than added states after surface - after_state_sum = self.get_state_after_surface_sum() + after_state_sum = self.get_surface_after_states() if self.deductable_surface > after_state_sum: raise ValidationError(_("Deductable surface can not be larger than existing surfaces in after states")) @@ -96,15 +96,9 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix Returns: sum_surface (float) """ - return self.deductions.all().aggregate(Sum("surface"))["surface__sum"] or 0 - - def get_state_after_surface_sum(self) -> float: - """ Calculates the account's after state surface sum - - Returns: - sum_surface (float) - """ - return self.after_states.all().aggregate(Sum("surface"))["surface__sum"] or 0 + val = self.deductions.all().aggregate(Sum("surface"))["surface__sum"] or 0 + val = float('{:0.2f}'.format(val)) + return val def __calculate_deductable_rest(self): """ Calculates available rest surface of the eco account @@ -114,10 +108,7 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix Returns: ret_val_total (float): Total amount """ - deductions = self.deductions.filter( - intervention__deleted=None, - ) - deductions_surfaces = deductions.aggregate(Sum("surface"))["surface__sum"] or 0 + deductions_surfaces = self.get_deductions_surface() available_surface = self.deductable_surface if available_surface is None: diff --git a/compensation/utils/quality.py b/compensation/utils/quality.py index 6edd691..6aa5b11 100644 --- a/compensation/utils/quality.py +++ b/compensation/utils/quality.py @@ -95,7 +95,7 @@ class EcoAccountQualityChecker(CompensationQualityChecker): is_surface_invalid = surface == 0 if is_surface_invalid: self._add_missing_attr_name(_("Available Surface")) - after_state_surface = self.obj.get_state_after_surface_sum() + after_state_surface = self.obj.get_surface_after_states() if surface > after_state_surface: self.messages.append( _("Deductable surface can not be larger than state surface") diff --git a/compensation/views/compensation/compensation.py b/compensation/views/compensation/compensation.py index 32787f8..0a198bb 100644 --- a/compensation/views/compensation/compensation.py +++ b/compensation/views/compensation/compensation.py @@ -228,8 +228,6 @@ def detail_view(request: HttpRequest, id: str): _user = request.user is_data_shared = comp.intervention.is_shared_with(_user) - - # Order states according to surface before_states = comp.before_states.all().prefetch_related("biotope_type").order_by("-surface") after_states = comp.after_states.all().prefetch_related("biotope_type").order_by("-surface") @@ -237,8 +235,8 @@ def detail_view(request: HttpRequest, id: str): # Precalculate logical errors between before- and after-states # Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling - sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0 - sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0 + sum_before_states = comp.get_surface_before_states() + sum_after_states = comp.get_surface_after_states() diff_states = abs(sum_before_states - sum_after_states) request = comp.set_status_messages(request) diff --git a/compensation/views/eco_account/eco_account.py b/compensation/views/eco_account/eco_account.py index 71cfda5..685ddd2 100644 --- a/compensation/views/eco_account/eco_account.py +++ b/compensation/views/eco_account/eco_account.py @@ -208,8 +208,8 @@ def detail_view(request: HttpRequest, id: str): # Precalculate logical errors between before- and after-states # Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling - sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0 - sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0 + sum_before_states = acc.get_surface_before_states() + sum_after_states = acc.get_surface_after_states() diff_states = abs(sum_before_states - sum_after_states) # Calculate rest of available surface for deductions available_total = acc.deductable_rest diff --git a/ema/views/ema.py b/ema/views/ema.py index 53d525a..0296b14 100644 --- a/ema/views/ema.py +++ b/ema/views/ema.py @@ -149,8 +149,8 @@ def detail_view(request: HttpRequest, id: str): # Precalculate logical errors between before- and after-states # Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling - sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0 - sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0 + sum_before_states = ema.get_surface_before_states() + sum_after_states = ema.get_surface_after_states() diff_states = abs(sum_before_states - sum_after_states) ema.set_status_messages(request) diff --git a/konova/tests/test_views.py b/konova/tests/test_views.py index 437f114..a78116f 100644 --- a/konova/tests/test_views.py +++ b/konova/tests/test_views.py @@ -441,7 +441,7 @@ class BaseTestCase(TestCase): eco_account.actions.add(self.comp_action) eco_account.geometry.geom = self.create_dummy_geometry() eco_account.geometry.save() - eco_account.deductable_surface = eco_account.get_state_after_surface_sum() + eco_account.deductable_surface = eco_account.get_surface_after_states() eco_account.deadlines.add(self.finished_deadline) eco_account.save() return eco_account