mirror of
https://github.com/almet/copanier.git
synced 2025-04-28 11:32:38 +02:00
Basic messages, config and XLSX export
This commit is contained in:
parent
4623adb41c
commit
cd12223d6d
6 changed files with 93 additions and 32 deletions
|
@ -1,13 +1,17 @@
|
|||
import csv
|
||||
from pathlib import Path
|
||||
from time import perf_counter
|
||||
|
||||
import ujson as json
|
||||
import hupper
|
||||
import minicli
|
||||
from jinja2 import Environment, PackageLoader, select_autoescape
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.writer.excel import save_virtual_workbook
|
||||
from roll import Roll, Response
|
||||
from roll.extensions import cors, options, traceback, simple_server
|
||||
from roll.extensions import cors, options, traceback, simple_server, static
|
||||
|
||||
from . import config
|
||||
from .models import Delivery, Order, Person, Product, ProductOrder
|
||||
|
||||
|
||||
|
@ -28,6 +32,9 @@ class Response(Response):
|
|||
|
||||
redirect = property(None, redirect)
|
||||
|
||||
def message(self, text, status="success"):
|
||||
self.cookies.set("message", json.dumps((text, status)))
|
||||
|
||||
|
||||
class Roll(Roll):
|
||||
Response = Response
|
||||
|
@ -61,7 +68,7 @@ async def attach_request(request, response):
|
|||
|
||||
@app.listen("startup")
|
||||
async def on_startup():
|
||||
connect()
|
||||
configure()
|
||||
|
||||
|
||||
@app.route("/", methods=["GET"])
|
||||
|
@ -83,8 +90,8 @@ async def create_delivery(request, response):
|
|||
data[name] = form.get(name)
|
||||
delivery = Delivery(**data)
|
||||
delivery.persist()
|
||||
response.status = 302
|
||||
response.headers["Location"] = f"/livraison/{delivery.id}"
|
||||
response.message("La livraison a bien été créée!")
|
||||
response.redirect = f"/livraison/{delivery.id}"
|
||||
|
||||
|
||||
@app.route("/livraison/{id}/importer/produits", methods=["POST"])
|
||||
|
@ -97,6 +104,7 @@ async def import_products(request, response, id):
|
|||
for row in reader:
|
||||
delivery.products.append(Product(**row))
|
||||
delivery.persist()
|
||||
response.message("Les produits de la livraison ont bien été mis à jour!")
|
||||
response.redirect = f"/livraison/{delivery.id}"
|
||||
|
||||
|
||||
|
@ -114,8 +122,8 @@ async def post_delivery(request, response, id):
|
|||
if name in form:
|
||||
setattr(delivery, name, form.get(name))
|
||||
delivery.persist()
|
||||
response.status = 302
|
||||
response.headers["Location"] = f"/livraison/{delivery.id}"
|
||||
response.message("La livraison a bien été mise à jour!")
|
||||
response.redirect = f"/livraison/{delivery.id}"
|
||||
|
||||
|
||||
@app.route("/livraison/{id}", methods=["GET"])
|
||||
|
@ -128,7 +136,7 @@ async def view_delivery(request, response, id):
|
|||
async def order_form(request, response, id):
|
||||
delivery = Delivery.load(id)
|
||||
email = request.query.get("email")
|
||||
order = delivery.orders.get(email)
|
||||
order = delivery.orders.get(email) or Order()
|
||||
response.html(
|
||||
"place_order.html", {"delivery": delivery, "person": email, "order": order}
|
||||
)
|
||||
|
@ -148,6 +156,7 @@ async def place_order(request, response, id):
|
|||
delivery.orders = {}
|
||||
delivery.orders[email] = order
|
||||
delivery.persist()
|
||||
response.message("Jour de fête! Votre commande a bien été prise en compte!")
|
||||
response.redirect = request.url.decode()
|
||||
|
||||
|
||||
|
@ -165,22 +174,42 @@ async def import_commande(request, response, id):
|
|||
delivery = Delivery.load(id)
|
||||
delivery.orders[email] = order
|
||||
delivery.persist()
|
||||
response.message(f"Yallah! La commande de {email} a bien été importée!")
|
||||
response.redirect = f"/livraison/{delivery.id}"
|
||||
|
||||
|
||||
def connect():
|
||||
# db = os.environ.get("KABA_DB", "mongodb://localhost/kaba")
|
||||
# client = MongoClient(db)
|
||||
# db = client.get_database()
|
||||
# Person.bind(db)
|
||||
# Delivery.bind(db)
|
||||
# return client
|
||||
pass
|
||||
@app.route("/livraison/{id}/rapport.xlsx", methods=["GET"])
|
||||
async def xls_report(request, response, id):
|
||||
delivery = Delivery.load(id)
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = f"Commande Epinamap - {delivery.producer} - {delivery.when.date()}"
|
||||
ws.append(["ref", "produit", "prix", "unités", "total"])
|
||||
for product in delivery.products:
|
||||
wanted = delivery.product_wanted(product)
|
||||
ws.append(
|
||||
[
|
||||
product.ref,
|
||||
product.name,
|
||||
product.price,
|
||||
wanted,
|
||||
round(product.price * wanted, 2),
|
||||
]
|
||||
)
|
||||
ws.append(["", "", "", "Total", delivery.total])
|
||||
response.body = save_virtual_workbook(wb)
|
||||
mimetype = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
response.headers["Content-Disposition"] = f'attachment; filename="export.xlsx"'
|
||||
response.headers["Content-Type"] = f"{mimetype}; charset=utf-8"
|
||||
|
||||
|
||||
def configure():
|
||||
config.init()
|
||||
|
||||
|
||||
@minicli.cli()
|
||||
def shell():
|
||||
"""Run an ipython already connected to Mongo."""
|
||||
"""Run an ipython in app context."""
|
||||
try:
|
||||
from IPython import start_ipython
|
||||
except ImportError:
|
||||
|
@ -200,7 +229,7 @@ def shell():
|
|||
|
||||
@minicli.wrap
|
||||
def cli_wrapper():
|
||||
connect()
|
||||
configure()
|
||||
start = perf_counter()
|
||||
yield
|
||||
elapsed = perf_counter() - start
|
||||
|
@ -213,6 +242,7 @@ def serve(reload=False):
|
|||
if reload:
|
||||
hupper.start_reloader("kaba.serve")
|
||||
traceback(app)
|
||||
static(app, root=Path(__file__).parent / "static")
|
||||
simple_server(app, port=2244)
|
||||
|
||||
|
||||
|
|
|
@ -4,13 +4,18 @@
|
|||
<title>{% if title %}{{ title }} - {% endif %}Commandes Epinamap</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" type="text/css">
|
||||
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.1/css/bulma.css">
|
||||
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" type="text/css"> -->
|
||||
<link rel="stylesheet" type="text/css" href="/static/app.css">
|
||||
{% block head %}
|
||||
{% endblock head %}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
{% if message %}
|
||||
<div class="notification {{ message[1] }}">{{ message[0] }}</div>
|
||||
{% endif %}
|
||||
</header>
|
||||
{% block body %}
|
||||
{% endblock body %}
|
||||
</body>
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
<p>Date: {{ delivery.when }}</p>
|
||||
<form action="/livraison/{{ delivery.id }}/commander">
|
||||
<label for="email">Commander</label>
|
||||
<input type="email" name="email">
|
||||
<input type="email" name="email" placeholder="Mon courriel">
|
||||
<input type="submit" value="Commander">
|
||||
</form>
|
||||
<a href="/livraison/{{ delivery.id }}">Résumé de la livraison</a>
|
||||
<hr>
|
||||
{% endfor %}
|
||||
<a href="/livraison/new">Nouvelle livraison</a>
|
||||
{% endblock body %}
|
||||
|
|
|
@ -2,15 +2,27 @@
|
|||
|
||||
{% block body %}
|
||||
<p><a href="/">< Commandes</a></p>
|
||||
<p>Producteur: {{ delivery.producer }}</p>
|
||||
<p>Lieu: {{ delivery.where }}</p>
|
||||
<p>Date: {{ delivery.when }}</p>
|
||||
<p>Producteur: {{ delivery.producer }} — Lieu: {{ delivery.where }} — Date: {{ delivery.when }} — Date limite de commande: {{ delivery.order_before }}</p>
|
||||
<p>Commande de «{{ person }}»</p>
|
||||
<form method="post">
|
||||
<table>
|
||||
<tr><th>Produit</th><th>Prix</th><th>Quantité</th></tr>
|
||||
{% for product in delivery.products %}
|
||||
<tr><th>{{ product.name }}</th><td>{{ product.price }} €</td><td><input type="number" name="{{ product.ref }}" value="{{ order.get_quantity(product) if order else 0 }}"></td></tr>
|
||||
<tr>
|
||||
<th>{{ product.name }}
|
||||
<label for="toggleControl{{ loop.index }}" class="toggle-label">(Détails)</label>
|
||||
<input type="checkbox" id="toggleControl{{ loop.index }}" class="toggle">
|
||||
<div class="toggle-container">
|
||||
<p>{{ product.description }}</p>
|
||||
<p>{% if product.img %}
|
||||
<img src="{{ product.img }}">
|
||||
{% else %}
|
||||
<img src="/static/img/default_product.svg">
|
||||
{% endif %}</p>
|
||||
<label for="toggleControl{{ loop.index }}" class="toggle-label">Fermer</label>
|
||||
</div>
|
||||
</th>
|
||||
<td>{{ product.price }} €</td><td><input type="number" name="{{ product.ref }}" value="{{ order.get_quantity(product) }}"></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<p>Total: {{ order.total(delivery.products) if order else 0 }} €</p>
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import os
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
from roll.extensions import traceback
|
||||
|
||||
from kaba import app as kaba_app
|
||||
from kaba import config as kconfig
|
||||
from kaba import utils
|
||||
from kaba.models import Delivery, Person
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
from kaba import models
|
||||
models.Base.ROOT = "tmp/db"
|
||||
os.environ["KABA_DATA_ROOT"] = "tmp/db"
|
||||
kconfig.init()
|
||||
assert str(kconfig.DATA_ROOT) == "tmp/db"
|
||||
|
||||
|
||||
# def pytest_runtest_setup(item):
|
||||
# # assert get_db().name == "test_eurordis"
|
||||
# for cls in [Delivery]:
|
||||
# collection = cls.collection
|
||||
# collection.drop()
|
||||
def pytest_runtest_setup(item):
|
||||
for path in Delivery.get_root().glob("*.yml"):
|
||||
path.unlink()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -29,7 +30,9 @@ def app(): # Requested by Roll testing utilities.
|
|||
@pytest.fixture
|
||||
def delivery():
|
||||
return Delivery(
|
||||
producer="Andines", when=utils.utcnow(), order_before=utils.utcnow()
|
||||
producer="Andines",
|
||||
when=utils.utcnow() + timedelta(days=10),
|
||||
order_before=utils.utcnow() + timedelta(days=7),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from kaba import utils
|
||||
|
@ -19,6 +21,13 @@ def test_wrong_datetime_raise_valueerror():
|
|||
Delivery(producer="Andines", order_before=utils.utcnow(), when="pouet")
|
||||
|
||||
|
||||
def test_delivery_is_open_when_order_before_is_in_the_future(delivery):
|
||||
delivery.order_before = utils.utcnow() + timedelta(hours=1)
|
||||
assert delivery.is_open
|
||||
delivery.order_before = utils.utcnow() - timedelta(hours=1)
|
||||
assert not delivery.is_open
|
||||
|
||||
|
||||
def test_can_create_product():
|
||||
product = Product(name="Lait 1.5L", ref="123", price=1.5)
|
||||
assert product.ref == "123"
|
||||
|
|
Loading…
Reference in a new issue