Parcourir la source

Trying to clarify reconciliation algorithm

Alexandre Aubin il y a 7 ans
Parent
commit
d5165ea3d5
1 fichiers modifiés avec 54 ajouts et 46 suppressions
  1. 54 46
      coin/billing/models.py

+ 54 - 46
coin/billing/models.py

@@ -438,43 +438,44 @@ class Payment(models.Model):
         verbose_name = 'paiement'
         verbose_name = 'paiement'
 
 
 
 
+def get_active_payment_and_invoices(member):
+
+    # Fetch relevant and active payments / invoices
+    # and sort then by chronological order : olders first, newers last.
+
+    this_member_invoices = [i for i in member.invoices
+                                             .filter(validated=True)
+                                             .order_by("date")]
+    this_member_payments = [p for p in member.payments
+                                             .order_by("date")]
+
+    # TODO / FIXME ^^^ maybe also consider only 'opened' invoices (i.e. not
+    # conflict / trouble invoices)
+
+    active_payments = [p for p in this_member_payments if p.amount_not_allocated()    > 0]
+    active_invoices = [p for p in this_member_invoices if p.amount_remaining_to_pay() > 0]
+
+    return active_payments, active_invoices
+
+
 def update_accounting_for_member(member):
 def update_accounting_for_member(member):
     """
     """
     Met à jour le status des factures, des paiements et le solde du compte
     Met à jour le status des factures, des paiements et le solde du compte
     d'un utilisateur
     d'un utilisateur
     """
     """
 
 
-    accounting_log.info("Member %s current balance is %f ..."
-                        % (str(member), float(member.balance)))
     accounting_log.info("Updating accounting for member %s ..."
     accounting_log.info("Updating accounting for member %s ..."
                         % str(member))
                         % str(member))
+    accounting_log.info("Member %s current balance is %f ..."
+                        % (str(member), float(member.balance)))
 
 
-    # Fetch relevant and active payments / invoices
-    # and sort then by chronological order : olders first, newers last.
-
-    this_member_invoices = [i for i in member.invoices.filter(validated=True)
-                                                      .order_by("date")]
-    this_member_payments = [p for p in member.payments.order_by("date")]
-
-    # TODO / FIXME ^^^ maybe also consider only 'opened' invoices (i.e. not
-    # conflict / trouble invoices)
+    reconcile_invoices_and_payments(member)
 
 
-    number_of_active_payments = len([p for p in this_member_payments if p.amount_not_allocated()    > 0])
-    number_of_active_invoices = len([p for p in this_member_invoices if p.amount_remaining_to_pay() > 0])
-
-    if (number_of_active_payments == 0):
-        accounting_log.info("(No active payment for %s. No invoice/payment "
-                            "reconciliation needed for now.)."
-                            % str(member))
-    elif (number_of_active_invoices == 0):
-        accounting_log.info("(No active invoice for %s. No invoice/payment "
-                            "reconciliation needed for now.)."
-                            % str(member))
-    else:
-        accounting_log.info("Initiating reconciliation between "
-                            "invoice and payments for %s" % str(member))
-        reconcile_invoices_and_payments(this_member_invoices,
-                                        this_member_payments)
+    this_member_invoices = [i for i in member.invoices
+                                             .filter(validated=True)
+                                             .order_by("date")]
+    this_member_payments = [p for p in member.payments
+                                             .order_by("date")]
 
 
     member.balance = compute_balance(this_member_invoices,
     member.balance = compute_balance(this_member_invoices,
                                      this_member_payments)
                                      this_member_payments)
@@ -484,39 +485,46 @@ def update_accounting_for_member(member):
                         % (str(member),  float(member.balance)))
                         % (str(member),  float(member.balance)))
 
 
 
 
-def reconcile_invoices_and_payments(invoices, payments):
+def reconcile_invoices_and_payments(member):
     """
     """
     Rapproche des factures et des paiements qui sont actifs (paiement non alloué
     Rapproche des factures et des paiements qui sont actifs (paiement non alloué
     ou factures non entièrement payées) automatiquement.
     ou factures non entièrement payées) automatiquement.
-    Retourne la balance restante (positive si 'trop payé', négative si factures
-    restantes à payer)
     """
     """
 
 
-    active_payments = [p for p in payments if p.amount_not_allocated()    > 0]
-    active_invoices = [i for i in invoices if i.amount_remaining_to_pay() > 0]
+    active_payments, active_invoices = get_active_payment_and_invoices(member)
 
 
-    if (len(active_payments) == 0):
-        accounting_log.info("No more active payment. Nothing to reconcile "
-                            "anymore.")
+    if active_payments == []:
+        accounting_log.info("(No active payment for %s. No invoice/payment "
+                            "reconciliation needed.)."
+                            % str(member))
         return
         return
-    if (len(active_invoices) == 0):
-        accounting_log.info("No more active invoice. Nothing to reconcile "
-                            "anymore.")
+    elif active_invoices == []:
+        accounting_log.info("(No active invoice for %s. No invoice/payment "
+                            "reconciliation needed.)."
+                            % str(member))
         return
         return
 
 
-    # Only consider the oldest active payment and the oldest active invoice
+    accounting_log.info("Initiating reconciliation between "
+                        "invoice and payments for %s" % str(member))
+
+    while active_payments != [] and active_invoices != []:
 
 
-    p = active_payments[0]
-    i = active_invoices[0]
+        # Only consider the oldest active payment and the oldest active invoice
+        p = active_payments[0]
+        i = active_invoices[0]
 
 
-    # TODO : should add an assert that the ammount not allocated / remaining to
-    # pay is lower before and after calling the allocate_to_invoice
+        # TODO : should add an assert that the ammount not allocated / remaining to
+        # pay is lower before and after calling the allocate_to_invoice
 
 
-    p.allocate_to_invoice(i)
+        p.allocate_to_invoice(i)
 
 
-    # Reconcicle next payment / invoice
+        active_payments, active_invoices = get_active_payment_and_invoices(member)
 
 
-    reconcile_invoices_and_payments(invoices, payments)
+    if active_payments == []:
+        accounting_log.info("No more active payment. Nothing to reconcile anymore.")
+    elif active_invoices == []:
+        accounting_log.info("No more active invoice. Nothing to reconcile anymore.")
+    return
 
 
 
 
 def compute_balance(invoices, payments):
 def compute_balance(invoices, payments):