From b29508c4796bdf5fea36e9d55db02f4de94c65e4 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Thu, 25 Nov 2021 19:06:39 +0100 Subject: [PATCH] misc: factorize computation of income per year of contracts (#326) --- eo_gestion/eo_facture/models.py | 22 +++++++ .../eo_facture/templatetags/eo_facture.py | 20 ++----- tests/test_facture.py | 58 +++++++++++++++++++ 3 files changed, 85 insertions(+), 15 deletions(-) create mode 100644 tests/test_facture.py diff --git a/eo_gestion/eo_facture/models.py b/eo_gestion/eo_facture/models.py index bce7530..01c005a 100644 --- a/eo_gestion/eo_facture/models.py +++ b/eo_gestion/eo_facture/models.py @@ -164,6 +164,28 @@ class Contrat(models.Model): def solde(self): return self.montant() - self.montant_facture() + def montant_par_annee(self): + '''Calcul du revenu futur, en retranchant les + montants déjà facturés par rapport au + prévisionnel''' + today_year = datetime.date.today().year + montant_par_annee = defaultdict(Decimal) + adjust = 0 + for year, fraction in self.percentage_per_year: + amount = self.montant() * fraction + if year > today_year: + montant_par_annee[year] += amount + else: + adjust += amount + for f in self.factures.all(): + if f.proforma: + continue + if f.accounting_year <= today_year: + adjust -= f.montant - f.sous_traite + if adjust > 0: + montant_par_annee[today_year] += adjust + return montant_par_annee + def nom_client(self): """ Le nom du client qui a signé ce contrat avec EO. diff --git a/eo_gestion/eo_facture/templatetags/eo_facture.py b/eo_gestion/eo_facture/templatetags/eo_facture.py index c181a36..129c89f 100644 --- a/eo_gestion/eo_facture/templatetags/eo_facture.py +++ b/eo_gestion/eo_facture/templatetags/eo_facture.py @@ -84,7 +84,6 @@ def income(): .prefetch_related('lignes', 'payments') ) paid_by_year = AmountByYear() - today_year = date.today().year sous_traite_by_year = AmountByYear() for invoice in invoices: if invoice.paid: @@ -115,22 +114,13 @@ def income(): ) ) invoiced_clients_by_year[year] = clients + + # compute future income for each contract contracted_by_year = defaultdict(lambda: Decimal(0)) for contract in Contrat.objects.all().prefetch_related('factures', 'factures__lignes', 'prestations'): - adjust = 0 - for year, fraction in contract.percentage_per_year: - amount = contract.montant() * fraction - if year > today_year: - contracted_by_year[year] += amount - else: - adjust += amount - for f in contract.factures.all(): - if f.proforma: - continue - if f.accounting_year <= today_year: - adjust -= f.montant - f.sous_traite - if adjust > 0: - contracted_by_year[today_year] += adjust + for year, montant in contract.montant_par_annee().items(): + contracted_by_year[year] += montant + this_year = date.today().year income_by_year = [] for year in invoiced_by_year: diff --git a/tests/test_facture.py b/tests/test_facture.py new file mode 100644 index 0000000..38f8136 --- /dev/null +++ b/tests/test_facture.py @@ -0,0 +1,58 @@ +# barbacompta - invoicing for dummies +# Copyright (C) 2019-2020 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import uuid +from datetime import date +from decimal import Decimal + +from eo_gestion.eo_facture.models import Client, Contrat, Facture + + +def test_contrat_montant_par_annee_percentage_per_year(db, django_user_model, freezer): + freezer.move_to('2021-06-01') + client = Client.objects.create(nom=str(uuid.uuid4())) + user = django_user_model.objects.all()[0] + contrat = Contrat.objects.create( + client=client, + creator=user, + intitule=str(uuid.uuid4()), + percentage_per_year=[(2020, Decimal(0.5)), (2021, Decimal(0.25)), (2022, Decimal(0.25))], + ) + contrat.clean() + for i in range(10): + contrat.prestations.create(intitule=str(i), quantite=1, prix_unitaire_ht=1000) + + facture = Facture.objects.create( + proforma=False, + client=client, + contrat=contrat, + emission=date(2020, 1, 1), + echeance=date(2020, 1, 16), + creator=user, + ) + facture.lignes.create(prix_unitaire_ht=1000, quantite=1, order=1) + + facture = Facture.objects.create( + proforma=False, + client=client, + contrat=contrat, + emission=date(2021, 1, 1), + echeance=date(2021, 1, 16), + creator=user, + ) + facture.lignes.create(prix_unitaire_ht=1000, quantite=1, order=1) + + assert sorted(list(contrat.montant_par_annee().items())) == [(2021, Decimal(5500)), (2022, Decimal(2500))]