|
@@ -438,43 +438,44 @@ class Payment(models.Model):
|
|
|
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):
|
|
|
"""
|
|
|
Met à jour le status des factures, des paiements et le solde du compte
|
|
|
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 ..."
|
|
|
% 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,
|
|
|
this_member_payments)
|
|
@@ -484,39 +485,46 @@ def update_accounting_for_member(member):
|
|
|
% (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é
|
|
|
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
|
|
|
- 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
|
|
|
|
|
|
- # 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):
|