From cd5fb9cad60ce563c174c5a123bc54e215f4fd61 Mon Sep 17 00:00:00 2001 From: mipel Date: Mon, 30 Aug 2021 11:29:15 +0200 Subject: [PATCH] Withdraw to deduct * refactors all files and variable names * WIP: Models and attributes --- compensation/account_urls.py | 6 +- compensation/admin.py | 4 +- compensation/models.py | 22 +++--- compensation/tables.py | 2 +- .../{withdraws.html => deductions.html} | 26 +++---- .../compensation/detail/eco_account/view.html | 2 +- compensation/views/eco_account_views.py | 34 ++++----- intervention/forms.py | 28 ++++---- .../{withdraws.html => deductions.html} | 22 +++--- .../templates/intervention/detail/view.html | 2 +- intervention/urls.py | 6 +- intervention/views.py | 12 ++-- konova/templates/konova/home.html | 2 +- locale/de/LC_MESSAGES/django.mo | Bin 19390 -> 19398 bytes locale/de/LC_MESSAGES/django.po | 66 +++++++++--------- 15 files changed, 117 insertions(+), 117 deletions(-) rename compensation/templates/compensation/detail/eco_account/includes/{withdraws.html => deductions.html} (64%) rename intervention/templates/intervention/detail/includes/{withdraws.html => deductions.html} (63%) diff --git a/compensation/account_urls.py b/compensation/account_urls.py index 222f2fc..5daa6c8 100644 --- a/compensation/account_urls.py +++ b/compensation/account_urls.py @@ -24,8 +24,8 @@ urlpatterns = [ # Document remove route can be found in konova/urls.py path('/document/new/', new_document_view, name='acc-new-doc'), - # Eco-account withdraws - path('/remove/', withdraw_remove_view, name='withdraw-remove'), - path('/withdraw/new', new_withdraw_view, name='acc-new-withdraw'), + # Eco-account deductions + path('/remove/', deduction_remove_view, name='deduction-remove'), + path('/deduct/new', new_deduction_view, name='acc-new-deduction'), ] \ No newline at end of file diff --git a/compensation/admin.py b/compensation/admin.py index e77450a..f4bfed2 100644 --- a/compensation/admin.py +++ b/compensation/admin.py @@ -47,7 +47,7 @@ class PaymentAdmin(admin.ModelAdmin): ] -class EcoAccountWithdrawAdmin(admin.ModelAdmin): +class EcoAccountDeductionAdmin(admin.ModelAdmin): list_display = [ "id", "account", @@ -61,4 +61,4 @@ admin.site.register(Payment, PaymentAdmin) admin.site.register(CompensationAction, CompensationActionAdmin) admin.site.register(CompensationState, CompensationStateAdmin) admin.site.register(EcoAccount, EcoAccountAdmin) -admin.site.register(EcoAccountWithdraw, EcoAccountWithdrawAdmin) +admin.site.register(EcoAccountWithdraw, EcoAccountDeductionAdmin) diff --git a/compensation/models.py b/compensation/models.py index c54d44f..6278c7b 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -201,7 +201,7 @@ class Compensation(AbstractCompensation): class EcoAccount(AbstractCompensation): """ An eco account is a kind of 'prepaid' compensation. It can be compared to an account that already has been filled - with some kind of currency. From this account one is able to 'withdraw' currency for current projects. + with some kind of currency. From this account one is able to deduct currency for current projects. """ # Users having access on this object # Not needed in regular Compensation since their access is defined by the linked intervention's access @@ -232,8 +232,8 @@ class EcoAccount(AbstractCompensation): self.identifier = new_id super().save(*args, **kwargs) - def get_surface_withdraws(self) -> float: - """ Calculates the compensation's/account's surface + def get_deductions_surface(self) -> float: + """ Calculates the account's deductions sum surface Returns: sum_surface (float) @@ -250,12 +250,12 @@ class EcoAccount(AbstractCompensation): """ ret_val = 0 - withdraws = self.withdraws.filter( + deductions = self.withdraws.filter( intervention__deleted=None, ) - withdraw_surfaces = withdraws.aggregate(Sum("surface"))["surface__sum"] or 0 - after_states_surfaces = self.after_states.all().aggregate(Sum("surface"))["surface__sum"] or withdraw_surfaces ## no division by zero - ret_val = after_states_surfaces - withdraw_surfaces + deductions_surfaces = deductions.aggregate(Sum("surface"))["surface__sum"] or 0 + after_states_surfaces = self.after_states.all().aggregate(Sum("surface"))["surface__sum"] or deductions_surfaces ## no division by zero + ret_val = after_states_surfaces - deductions_surfaces if as_percentage: if after_states_surfaces > 0: @@ -301,20 +301,20 @@ class EcoAccount(AbstractCompensation): class EcoAccountWithdraw(BaseResource): """ - A withdraw object for eco accounts + A deduction object for eco accounts """ account = models.ForeignKey( EcoAccount, on_delete=models.SET_NULL, null=True, blank=True, - help_text="Withdrawn from", + help_text="Deducted from", related_name="withdraws", ) surface = models.FloatField( null=True, blank=True, - help_text="Amount withdrawn (m²)", + help_text="Amount deducted (m²)", validators=[ MinValueValidator(limit_value=0.00), ] @@ -324,7 +324,7 @@ class EcoAccountWithdraw(BaseResource): on_delete=models.CASCADE, null=True, blank=True, - help_text="Withdrawn for", + help_text="Deducted for", related_name="withdraws", ) diff --git a/compensation/tables.py b/compensation/tables.py index db01f7c..c7487dc 100644 --- a/compensation/tables.py +++ b/compensation/tables.py @@ -252,7 +252,7 @@ class EcoAccountTable(BaseTable): """ html = "" checked = value is not None - tooltip = _("Not recorded yet. Can not be used for withdraws, yet.") + tooltip = _("Not recorded yet. Can not be used for deductions, yet.") if checked: value = value.timestamp value = localtime(value) diff --git a/compensation/templates/compensation/detail/eco_account/includes/withdraws.html b/compensation/templates/compensation/detail/eco_account/includes/deductions.html similarity index 64% rename from compensation/templates/compensation/detail/eco_account/includes/withdraws.html rename to compensation/templates/compensation/detail/eco_account/includes/deductions.html index 19fe679..5306193 100644 --- a/compensation/templates/compensation/detail/eco_account/includes/withdraws.html +++ b/compensation/templates/compensation/detail/eco_account/includes/deductions.html @@ -1,17 +1,17 @@ {% load i18n l10n fontawesome_5 humanize %} -
+
- {{withdraws.count}} - {% trans 'Eco Account Withdraws' %} + {{deductions.count}} + {% trans 'Eco Account Deductions' %}
{% if is_default_member and has_access %} - @@ -42,25 +42,25 @@ - {% for withdraw in withdraws %} + {% for deduction in deductions %} - - {{ withdraw.intervention.identifier }} + + {{ deduction.intervention.identifier }} - {% if withdraw.intervention.recorded %} - + {% if deduction.intervention.recorded %} + {% else %} - + {% endif %} - {{ withdraw.surface|floatformat:2|intcomma }} m² - {{ withdraw.created.timestamp|default_if_none:""|naturalday}} + {{ deduction.surface|floatformat:2|intcomma }} m² + {{ deduction.created.timestamp|default_if_none:""|naturalday}} {% if is_default_member and has_access %} - {% endif %} diff --git a/compensation/templates/compensation/detail/eco_account/view.html b/compensation/templates/compensation/detail/eco_account/view.html index 2c114e4..f591b2c 100644 --- a/compensation/templates/compensation/detail/eco_account/view.html +++ b/compensation/templates/compensation/detail/eco_account/view.html @@ -110,7 +110,7 @@ {% include 'compensation/detail/eco_account/includes/documents.html' %}
- {% include 'compensation/detail/eco_account/includes/withdraws.html' %} + {% include 'compensation/detail/eco_account/includes/deductions.html' %}
diff --git a/compensation/views/eco_account_views.py b/compensation/views/eco_account_views.py index 282717f..c73a8c5 100644 --- a/compensation/views/eco_account_views.py +++ b/compensation/views/eco_account_views.py @@ -16,7 +16,7 @@ from django.shortcuts import render, get_object_or_404 from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm from compensation.models import EcoAccount from compensation.tables import EcoAccountTable -from intervention.forms import NewWithdrawForm +from intervention.forms import NewDeductionForm from konova.contexts import BaseContext from konova.decorators import any_group_check, default_group_required, conservation_office_group_required from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm, RecordModalForm @@ -94,10 +94,10 @@ def open_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 withdraws + # Calculate rest of available surface for deductions available = acc.get_available_rest(as_percentage=True) - withdraws = acc.withdraws.filter( + deductions = acc.withdraws.filter( intervention__deleted=None, ) @@ -115,7 +115,7 @@ def open_view(request: HttpRequest, id: str): "is_zb_member": in_group(_user, ZB_GROUP), "is_ets_member": in_group(_user, ETS_GROUP), "LANIS_LINK": acc.get_LANIS_link(), - "withdraws": withdraws, + "deductions": deductions, } context = BaseContext(request, context).context return render(request, template, context) @@ -143,27 +143,27 @@ def remove_view(request: HttpRequest, id: str): @login_required @default_group_required -def withdraw_remove_view(request: HttpRequest, id: str, withdraw_id: str): - """ Renders a modal view for removing withdraws +def deduction_remove_view(request: HttpRequest, id: str, deduction_id: str): + """ Renders a modal view for removing deductions Args: request (HttpRequest): The incoming request id (str): The eco account's id - withdraw_id (str): The withdraw's id + deduction_id (str): The deduction's id Returns: """ acc = get_object_or_404(EcoAccount, id=id) try: - eco_withdraw = acc.withdraws.get(id=withdraw_id) + eco_deduction = acc.withdraws.get(id=deduction_id) except ObjectDoesNotExist: - raise Http404("Unknown withdraw") + raise Http404("Unknown deduction") - form = RemoveModalForm(request.POST or None, instance=eco_withdraw, user=request.user) + form = RemoveModalForm(request.POST or None, instance=eco_deduction, user=request.user) return form.process_request( request=request, - msg_success=_("Withdraw removed") + msg_success=_("Deduction removed") ) @@ -291,19 +291,19 @@ def new_document_view(request: HttpRequest, id: str): @login_required @default_group_required -def new_withdraw_view(request: HttpRequest, id: str): - """ Renders a modal form view for creating withdraws +def new_deduction_view(request: HttpRequest, id: str): + """ Renders a modal form view for creating deductions Args: - request (): - id (): + request (HttpRequest): THe incoming request + id (str): The eco account's id Returns: """ acc = get_object_or_404(EcoAccount, id=id) - form = NewWithdrawForm(request.POST or None, instance=acc, user=request.user) + form = NewDeductionForm(request.POST or None, instance=acc, user=request.user) return form.process_request( request, - msg_success=_("Withdraw added") + msg_success=_("Deduction added") ) diff --git a/intervention/forms.py b/intervention/forms.py index c7032f7..0c22ec5 100644 --- a/intervention/forms.py +++ b/intervention/forms.py @@ -451,8 +451,8 @@ class RunCheckForm(BaseModalForm): ) -class NewWithdrawForm(BaseModalForm): - """ Form for creating new withdraws +class NewDeductionForm(BaseModalForm): + """ Form for creating new deduction Can be used for Intervention view as well as for EcoAccount views. @@ -463,7 +463,7 @@ class NewWithdrawForm(BaseModalForm): account = forms.ModelChoiceField( label=_("Eco-account"), label_suffix="", - help_text=_("Only recorded accounts can be selected for withdraws"), + help_text=_("Only recorded accounts can be selected for deductions"), queryset=EcoAccount.objects.filter(deleted=None), widget=autocomplete.ModelSelect2( url="accounts-autocomplete", @@ -497,8 +497,8 @@ class NewWithdrawForm(BaseModalForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.form_title = _("New Withdraw") - self.form_caption = _("Enter the information for a new withdraw from a chosen eco-account") + self.form_title = _("New Deduction") + self.form_caption = _("Enter the information for a new deduction from a chosen eco-account") self.is_intervention_initially = False # Add a placeholder for field 'surface' without having to define the whole widget above @@ -520,7 +520,7 @@ class NewWithdrawForm(BaseModalForm): def is_valid(self): """ Custom validity check - Makes sure the withdraw can not contain more surface than the account still provides + Makes sure the deduction can not contain more surface than the account still provides Returns: is_valid (bool) @@ -534,20 +534,20 @@ class NewWithdrawForm(BaseModalForm): if not acc.recorded: self.add_error( "account", - _("Eco-account {} is not recorded yet. You can only withdraw from recorded accounts.").format(acc.identifier) + _("Eco-account {} is not recorded yet. You can only deduct from recorded accounts.").format(acc.identifier) ) return False # Calculate valid surface sum_surface = acc.get_surface() - sum_surface_withdraws = acc.get_surface_withdraws() - rest_surface = sum_surface - sum_surface_withdraws + sum_surface_deductions = acc.get_deductions_surface() + rest_surface = sum_surface - sum_surface_deductions form_surface = float(self.cleaned_data["surface"]) is_valid_surface = form_surface < rest_surface if not is_valid_surface: self.add_error( "surface", - _("The account {} has not enough surface for a withdraw of {} m². There are only {} m² left").format(acc.identifier, form_surface, rest_surface), + _("The account {} has not enough surface for a deduction of {} m². There are only {} m² left").format(acc.identifier, form_surface, rest_surface), ) return is_valid_surface and super_result @@ -566,19 +566,19 @@ class NewWithdrawForm(BaseModalForm): self.instance.modified = user_action_edit self.instance.save() - # Create withdraw depending on Intervention or EcoAccount as the initial instance + # Create deductions depending on Intervention or EcoAccount as the initial instance if self.is_intervention_initially: - withdraw = EcoAccountWithdraw.objects.create( + deduction = EcoAccountWithdraw.objects.create( intervention=self.instance, account=self.cleaned_data["account"], surface=self.cleaned_data["surface"], created=user_action_create, ) else: - withdraw = EcoAccountWithdraw.objects.create( + deduction = EcoAccountWithdraw.objects.create( intervention=self.cleaned_data["intervention"], account=self.instance, surface=self.cleaned_data["surface"], created=user_action_create, ) - return withdraw \ No newline at end of file + return deduction \ No newline at end of file diff --git a/intervention/templates/intervention/detail/includes/withdraws.html b/intervention/templates/intervention/detail/includes/deductions.html similarity index 63% rename from intervention/templates/intervention/detail/includes/withdraws.html rename to intervention/templates/intervention/detail/includes/deductions.html index be22e20..c9f1fba 100644 --- a/intervention/templates/intervention/detail/includes/withdraws.html +++ b/intervention/templates/intervention/detail/includes/deductions.html @@ -1,17 +1,17 @@ {% load i18n l10n fontawesome_5 humanize %} -
+
{{intervention.withdraws.count}} - {% trans 'Eco Account Withdraws' %} + {% trans 'Eco Account Deductions' %}
{% if is_default_member and has_access %} - @@ -39,21 +39,21 @@ - {% for withdraw in intervention.withdraws.all %} - + {% for deduction in intervention.withdraws.all %} + - - {% if withdraw.account.deleted or not withdraw.account.recorded %} + + {% if deduction.account.deleted or not deduction.account.recorded %} {% fa5_icon 'exclamation-triangle' %} {% endif %} - {{ withdraw.account.identifier }} + {{ deduction.account.identifier }} - {{ withdraw.surface|floatformat:2|intcomma }} m² - {{ withdraw.created.timestamp|default_if_none:""|naturalday}} + {{ deduction.surface|floatformat:2|intcomma }} m² + {{ deduction.created.timestamp|default_if_none:""|naturalday}} {% if is_default_member and has_access %} - {% endif %} diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index 8c6c095..ee0acc4 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -133,7 +133,7 @@
- {% include 'intervention/detail/includes/withdraws.html' %} + {% include 'intervention/detail/includes/deductions.html' %}
{% include 'intervention/detail/includes/revocation.html' %} diff --git a/intervention/urls.py b/intervention/urls.py index 97f8241..2172e16 100644 --- a/intervention/urls.py +++ b/intervention/urls.py @@ -8,7 +8,7 @@ Created on: 30.11.20 from django.urls import path from intervention.views import index_view, new_view, open_view, edit_view, remove_view, new_document_view, share_view, \ - create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_withdraw_view, \ + create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_deduction_view, \ record_view app_name = "intervention" @@ -25,8 +25,8 @@ urlpatterns = [ path('/check', run_check_view, name='run-check'), path('/record', record_view, name='record'), - # Withdraws - path('/withdraw/new', new_withdraw_view, name='acc-new-withdraw'), + # Deductions + path('/deduction/new', new_deduction_view, name='acc-new-deduction'), # Revocation routes path('/revocation/new', new_revocation_view, name='new-revocation'), diff --git a/intervention/views.py b/intervention/views.py index 7e1531a..e8893ce 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -5,7 +5,7 @@ from django.http import HttpRequest from django.shortcuts import render, get_object_or_404 from intervention.forms import NewInterventionForm, EditInterventionForm, ShareInterventionForm, NewRevocationForm, \ - RunCheckForm, NewWithdrawForm + RunCheckForm, NewDeductionForm from intervention.models import Intervention, Revocation from intervention.tables import InterventionTable from konova.contexts import BaseContext @@ -341,21 +341,21 @@ def log_view(request: HttpRequest, id: str): @login_required @default_group_required -def new_withdraw_view(request: HttpRequest, id: str): - """ Renders a modal form view for creating withdraws +def new_deduction_view(request: HttpRequest, id: str): + """ Renders a modal form view for creating deductions Args: request (HttpRequest): The incoming request - id (str): The intervention's id which shall get a new withdraw + id (str): The intervention's id which shall benefit from this deduction Returns: """ intervention = get_object_or_404(Intervention, id=id) - form = NewWithdrawForm(request.POST or None, instance=intervention, user=request.user) + form = NewDeductionForm(request.POST or None, instance=intervention, user=request.user) return form.process_request( request, - msg_success=_("Withdraw added") + msg_success=_("Deduction added") ) diff --git a/konova/templates/konova/home.html b/konova/templates/konova/home.html index 15fb65d..918eae5 100644 --- a/konova/templates/konova/home.html +++ b/konova/templates/konova/home.html @@ -127,7 +127,7 @@ diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 2118a3050e532bcb0c750af2f1cd7b6fe921fa4b..2ee53066cc1b83e60649f49b7f04d58883dd7e69 100644 GIT binary patch delta 6242 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