Use debts to compute and solve the balances

This commit is contained in:
Alexis M 2019-09-24 21:09:43 +02:00
parent bca36da70c
commit 2e524c92c1
4 changed files with 87 additions and 35 deletions

View file

@ -9,6 +9,9 @@ from roll import Roll, Response, HttpError
from roll.extensions import traceback, simple_server, static from roll.extensions import traceback, simple_server, static
from slugify import slugify from slugify import slugify
from debts.solver import order_balance, check_balance, reduce_balance
from collections import defaultdict
from functools import partial
from . import config, reports, session, utils, emails, loggers, imports from . import config, reports, session, utils, emails, loggers, imports
from .models import Delivery, Order, Person, Product, ProductOrder, Groups, Group from .models import Delivery, Order, Person, Product, ProductOrder, Groups, Group
@ -492,6 +495,7 @@ async def import_commande(request, response, id):
response.message(f"Yallah! La commande de {email} a bien été importée !") response.message(f"Yallah! La commande de {email} a bien été importée !")
response.redirect = f"/livraison/{delivery.id}" response.redirect = f"/livraison/{delivery.id}"
@app.route("/livraison/{id}/importer/commandes", methods=["POST"]) @app.route("/livraison/{id}/importer/commandes", methods=["POST"])
@staff_only @staff_only
async def import_multiple_commands(request, response, id): async def import_multiple_commands(request, response, id):
@ -556,20 +560,42 @@ async def adjust_product(request, response, id, ref):
response.html("adjust_product.html", {"delivery": delivery, "product": product}) response.html("adjust_product.html", {"delivery": delivery, "product": product})
@app.route("/livraison/{id}/solde", methods=["GET", "POST"]) @app.route("/livraison/{id}/solde", methods=["GET"])
@staff_only @staff_only
async def delivery_balance(request, response, id): async def delivery_balance(request, response, id):
delivery = Delivery.load(id) delivery = Delivery.load(id)
groups = request['groups']
delivery_url = f"/livraison/{delivery.id}" delivery_url = f"/livraison/{delivery.id}"
if request.method == "POST":
form = request.form balance = []
for email, order in delivery.orders.items(): for group_id, order in delivery.orders.items():
order.paid = form.bool(email, False) balance.append((group_id, order.total(delivery.products) * -1))
delivery.persist()
response.message(f"Les soldes ont bien été mis à jour!") for producer in delivery.producers.values():
response.redirect = delivery_url group = groups.get_user_group(producer.referent)
else: group_id = group.id if group else producer.referent
response.html("delivery_balance.html", {"delivery": delivery}) amount = delivery.total_for_producer(producer.id)
if amount:
balance.append((group_id, amount))
debiters, crediters = order_balance(balance)
check_balance(debiters, crediters)
results = reduce_balance(debiters[:], crediters[:])
results_dict = defaultdict(partial(defaultdict, float))
for debiter, amount, crediter in results:
results_dict[debiter][crediter] = amount
# from pdb import set_trace; set_trace()
response.html("delivery_balance.html", {
"delivery": delivery,
"debiters": debiters,
"crediters": crediters,
"results": results_dict,
"groups": groups.groups,
})
@app.route("/livraison/{id}/solde.xlsx", methods=["GET"]) @app.route("/livraison/{id}/solde.xlsx", methods=["GET"])

View file

@ -48,11 +48,9 @@
{% include "includes/modal_copy_emails.html" %} {% include "includes/modal_copy_emails.html" %}
{% endwith %} {% endwith %}
</li> </li>
{% if delivery.is_passed %}
<li> <li>
<a href="/livraison/{{ delivery.id }}/solde"><i class="icon-wallet"></i> Gérer les soldes</a> <a href="/livraison/{{ delivery.id }}/solde"><i class="icon-wallet"></i> Répartition des paiements</a>
</li> </li>
{% endif %} {% endif %}
{% endif %}
</ul> </ul>
{% endblock body %} {% endblock body %}

View file

@ -1,25 +1,52 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block head %}
<style media="screen">
table {
font-family:Arial, Helvetica, sans-serif;
color:#666;
font-size:12px;
text-shadow: 1px 1px 0px #fff;
background:#eaebec;
box-shadow: 0 1px 2px #d1d1d1;
}
table tr {
text-align: center;
padding-left:20px;
}
table td:first-child {
text-align: left;
padding-left:20px;
border-left: 0;
}
table td {
padding:5px;
border-top: 1px solid #ffffff;
border-bottom:1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
background: #fafafa;
}
table tr:hover td {
background: #f2f2f2;
}
</style>
{% endblock head %}
{% block body %} {% block body %}
<article> <h1><i class="icon-lightbulb"></i> Répartition des paiements</h1>
<h3><a href="/livraison/{{ delivery.id }}">{{ delivery.producer }}</a> — Gérer les soldes</h3> <table>
<form method="post"> <tr>
<table> <td></td>
<thead> {% for crediter in crediters %}<td>{% if crediter[0] in groups %} {{ groups[crediter[0]].name }}{% else %}{{ crediter[0] }}{% endif %} (+{{ crediter[1] | round(2) }})</td>{% endfor %}
<tr><th>Personne</th><th>Montant</th><th>Soldée</th></tr> </tr>
</thead> {% for debiter in debiters %}
<tbody> <tr>
{% for email, order in delivery.orders.items() %} <td>{% if debiter[0] in groups %} {{ groups[debiter[0]].name }}{% else %}{{ debiter[0] }}{% endif %} ({{ debiter[1] | round(2) }})</td>
<tr> {% for crediter in crediters %}
<td>{{ email }}</td> {% set due_amount = results[debiter[0]][crediter[0]] | round(2) %}
<td>{{ order.total(delivery.products) }} €</td>
<td class="with-input"><input type="checkbox" name="{{ email }}" {% if order.paid %}checked{% endif %}></td> <td>{% if due_amount != 0.00 %}{{due_amount}}{% endif %}</td>
</tr> {% endfor %}
{% endfor %} </tr>
</tbody> {% endfor %}
</table> </table>
<input type="submit" value="Enregistrer" class="primary">
<a href="/livraison/{{ delivery.id }}/solde.xlsx" class="button"><i class="icon-download"></i>&nbsp;Exporter</a>
</form>
</article>
{% endblock body %} {% endblock body %}

View file

@ -14,6 +14,7 @@ install_requires =
ujson==1.35 ujson==1.35
minicli==0.4.4 minicli==0.4.4
python-slugify==3.0.2 python-slugify==3.0.2
debts==0.4
[options.extras_require] [options.extras_require]
dev = dev =