Merge branch 'delivery-balance' into 'master'

Basic "manage delivery balance" page

See merge request ybon/copanier!5
This commit is contained in:
Yohan 2019-04-14 17:43:15 +02:00
commit 22da3d771c
4 changed files with 91 additions and 13 deletions

View file

@ -5,7 +5,7 @@ import ujson as json
import minicli import minicli
from jinja2 import Environment, PackageLoader, select_autoescape from jinja2 import Environment, PackageLoader, select_autoescape
from roll import Roll, Response, HttpError from roll import Roll, Response, HttpError
from roll.extensions import cors, options, traceback, simple_server, static from roll.extensions import traceback, simple_server, static
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 from .models import Delivery, Order, Person, Product, ProductOrder
@ -75,6 +75,18 @@ app = Roll()
traceback(app) traceback(app)
def staff_only(view):
async def decorator(request, response, *args, **kwargs):
user = session.user.get(None)
if not user or not user.is_staff:
response.message("Désolé, c'est réservé au staff par ici", "warning")
response.redirect = request.headers.get("REFERRER", "/")
return
return await view(request, response, *args, **kwargs)
return decorator
@app.listen("request") @app.listen("request")
async def auth_required(request, response): async def auth_required(request, response):
# Should be handler Roll side? # Should be handler Roll side?
@ -171,6 +183,7 @@ async def new_delivery(request, response):
@app.route("/livraison", methods=["POST"]) @app.route("/livraison", methods=["POST"])
@staff_only
async def create_delivery(request, response): async def create_delivery(request, response):
form = request.form form = request.form
data = {} data = {}
@ -186,6 +199,7 @@ async def create_delivery(request, response):
@app.route("/livraison/{id}/importer/produits", methods=["POST"]) @app.route("/livraison/{id}/importer/produits", methods=["POST"])
@staff_only
async def import_products(request, response, id): async def import_products(request, response, id):
delivery = Delivery.load(id) delivery = Delivery.load(id)
delivery.products = [] delivery.products = []
@ -220,12 +234,14 @@ async def export_products(request, response, id):
@app.route("/livraison/{id}/edit", methods=["GET"]) @app.route("/livraison/{id}/edit", methods=["GET"])
@staff_only
async def edit_delivery(request, response, id): async def edit_delivery(request, response, id):
delivery = Delivery.load(id) delivery = Delivery.load(id)
response.html("edit_delivery.html", {"delivery": delivery}) response.html("edit_delivery.html", {"delivery": delivery})
@app.route("/livraison/{id}/edit", methods=["POST"]) @app.route("/livraison/{id}/edit", methods=["POST"])
@staff_only
async def post_delivery(request, response, id): async def post_delivery(request, response, id):
delivery = Delivery.load(id) delivery = Delivery.load(id)
form = request.form form = request.form
@ -325,6 +341,7 @@ async def signing_sheet(request, response, id):
@app.route("/livraison/{id}/importer/commande", methods=["POST"]) @app.route("/livraison/{id}/importer/commande", methods=["POST"])
@staff_only
async def import_commande(request, response, id): async def import_commande(request, response, id):
email = request.form.get("email") email = request.form.get("email")
order = Order() order = Order()
@ -355,14 +372,10 @@ async def xls_full_report(request, response, id):
@app.route("/livraison/{id}/ajuster/{ref}", methods=["GET", "POST"]) @app.route("/livraison/{id}/ajuster/{ref}", methods=["GET", "POST"])
@staff_only
async def adjust_product(request, response, id, ref): async def adjust_product(request, response, id, ref):
delivery = Delivery.load(id) delivery = Delivery.load(id)
delivery_url = f"/livraison/{delivery.id}" delivery_url = f"/livraison/{delivery.id}"
user = session.user.get(None)
if not user or not user.is_staff:
response.message("Désolé, c'est dangereux par ici", "warning")
response.redirect = delivery_url
return
for product in delivery.products: for product in delivery.products:
if product.ref == ref: if product.ref == ref:
break break
@ -383,6 +396,22 @@ 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}/soldes", methods=["GET", "POST"])
@staff_only
async def delivery_balance(request, response, id):
delivery = Delivery.load(id)
delivery_url = f"/livraison/{delivery.id}"
if request.method == "POST":
form = request.form
for email, order in delivery.orders.items():
order.paid = form.bool(email, False)
delivery.persist()
response.message(f"Les soldes ont bien été mis à jour!")
response.redirect = delivery_url
else:
response.html("delivery_balance.html", {"delivery": delivery})
def configure(): def configure():
config.init() config.init()

View file

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

View file

@ -0,0 +1,20 @@
{% extends "base.html" %}
{% block body %}
<article>
<h3><a href="/livraison/{{ delivery.id }}">{{ delivery.producer }}</a> — Gérer les soldes</h3>
<form method="post">
<table>
<tr><th>Personne</th><th>Montant</th><th>Soldée</th></tr>
{% for email, order in delivery.orders.items() %}
<tr>
<td>{{ email }}</td>
<td>{{ order.total(delivery.products) }} €</td>
<td class="with-input"><input type="checkbox" name="{{ email }}" {% if order.paid %}checked{% endif %}></td>
</tr>
{% endfor %}
</table>
<input type="submit" value="Mettre à jour les soldes">
</form>
</article>
{% endblock body %}

View file

@ -159,15 +159,13 @@ async def test_get_adjust_product(client, delivery):
resp = await client.get(f"/livraison/{delivery.id}/ajuster/123") resp = await client.get(f"/livraison/{delivery.id}/ajuster/123")
doc = pq(resp.body) doc = pq(resp.body)
assert doc('[name="foo@bar.org"]') assert doc('[name="foo@bar.org"]')
assert doc('[name="foo@bar.org"]').attr("value") == '1' assert doc('[name="foo@bar.org"]').attr("value") == "1"
async def test_post_adjust_product(client, delivery): async def test_post_adjust_product(client, delivery):
delivery.order_before = datetime.now() - timedelta(days=1) delivery.order_before = datetime.now() - timedelta(days=1)
delivery.products[0].packing = 6 delivery.products[0].packing = 6
delivery.orders["foo@bar.org"] = Order( delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=2)})
products={"123": ProductOrder(wanted=2)}
)
delivery.persist() delivery.persist()
assert delivery.status == delivery.ADJUSTMENT assert delivery.status == delivery.ADJUSTMENT
body = {"foo@bar.org": "1"} body = {"foo@bar.org": "1"}
@ -181,9 +179,7 @@ async def test_post_adjust_product(client, delivery):
async def test_only_staff_can_adjust_product(client, delivery, monkeypatch): async def test_only_staff_can_adjust_product(client, delivery, monkeypatch):
delivery.order_before = datetime.now() - timedelta(days=1) delivery.order_before = datetime.now() - timedelta(days=1)
delivery.products[0].packing = 6 delivery.products[0].packing = 6
delivery.orders["foo@bar.org"] = Order( delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=2)})
products={"123": ProductOrder(wanted=2)}
)
delivery.persist() delivery.persist()
monkeypatch.setattr("copanier.config.STAFF", ["someone@else.org"]) monkeypatch.setattr("copanier.config.STAFF", ["someone@else.org"])
resp = await client.get(f"/livraison/{delivery.id}/ajuster/123") resp = await client.get(f"/livraison/{delivery.id}/ajuster/123")
@ -196,6 +192,34 @@ async def test_only_staff_can_adjust_product(client, delivery, monkeypatch):
assert delivery.orders["foo@bar.org"].products["123"].adjustment == 0 assert delivery.orders["foo@bar.org"].products["123"].adjustment == 0
async def test_get_delivery_balance(client, delivery):
delivery.from_date = datetime.now() - timedelta(days=1)
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=2)})
delivery.persist()
resp = await client.get(f"/livraison/{delivery.id}/soldes")
doc = pq(resp.body)
assert doc('[name="foo@bar.org"]')
assert not doc('[name="foo@bar.org"]').attr("checked")
delivery.orders["foo@bar.org"] = Order(
products={"123": ProductOrder(wanted=2)}, paid=True
)
delivery.persist()
resp = await client.get(f"/livraison/{delivery.id}/soldes")
doc = pq(resp.body)
assert doc('[name="foo@bar.org"]').attr("checked")
async def test_post_delivery_balance(client, delivery):
delivery.order_before = datetime.now() - timedelta(days=1)
delivery.orders["foo@bar.org"] = Order(products={"123": ProductOrder(wanted=2)})
delivery.persist()
body = {"foo@bar.org": "on"}
resp = await client.post(f"/livraison/{delivery.id}/soldes", body=body)
assert resp.status == 302
delivery = Delivery.load(id=delivery.id)
assert delivery.orders["foo@bar.org"].paid is True
async def test_export_products(client, delivery): async def test_export_products(client, delivery):
delivery.persist() delivery.persist()
resp = await client.get(f"/livraison/{delivery.id}/exporter/produits") resp = await client.get(f"/livraison/{delivery.id}/exporter/produits")