mirror of
https://github.com/almet/copanier.git
synced 2025-04-28 19:42:37 +02:00
Use debts to compute and solve the balances
This commit is contained in:
parent
bca36da70c
commit
2e524c92c1
4 changed files with 87 additions and 35 deletions
|
@ -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"])
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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">
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr><th>Personne</th><th>Montant</th><th>Soldée</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for email, order in delivery.orders.items() %}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ email }}</td>
|
<td></td>
|
||||||
<td>{{ order.total(delivery.products) }} €</td>
|
{% for crediter in crediters %}<td>{% if crediter[0] in groups %} {{ groups[crediter[0]].name }}{% else %}{{ crediter[0] }}{% endif %} (+{{ crediter[1] | round(2) }})</td>{% endfor %}
|
||||||
<td class="with-input"><input type="checkbox" name="{{ email }}" {% if order.paid %}checked{% endif %}></td>
|
</tr>
|
||||||
|
{% for debiter in debiters %}
|
||||||
|
<tr>
|
||||||
|
<td>{% if debiter[0] in groups %} {{ groups[debiter[0]].name }}{% else %}{{ debiter[0] }}{% endif %} ({{ debiter[1] | round(2) }})</td>
|
||||||
|
{% for crediter in crediters %}
|
||||||
|
{% set due_amount = results[debiter[0]][crediter[0]] | round(2) %}
|
||||||
|
|
||||||
|
<td>{% if due_amount != 0.00 %}{{due_amount}}{% endif %}</td>
|
||||||
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</table>
|
||||||
</table>
|
|
||||||
<input type="submit" value="Enregistrer" class="primary">
|
|
||||||
<a href="/livraison/{{ delivery.id }}/solde.xlsx" class="button"><i class="icon-download"></i> Exporter</a>
|
|
||||||
</form>
|
|
||||||
</article>
|
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
Loading…
Reference in a new issue