Handle multiple producers per delivery

This commit is contained in:
Alexis Métaireau 2019-04-14 02:18:51 +02:00
parent 04d5fca259
commit 6abe77de05
9 changed files with 80 additions and 16 deletions

View file

@ -37,7 +37,7 @@ def send_order(request, env, person, delivery, order):
env,
"order_summary",
person.email,
f"{config.SITE_NAME} : résumé de la commande {delivery.producer}",
f"{config.SITE_NAME} : résumé de la commande {delivery.name}",
order=order,
delivery=delivery,
request=request

View file

@ -24,7 +24,10 @@ def products_from_xlsx(delivery, data):
delivery.products = []
for row in rows[1:]:
raw = {k: v for k, v in dict(zip(headers, row)).items() if v}
delivery.products.append(Product(**raw))
try:
delivery.products.append(Product(**raw))
except TypeError as e:
raise ValueError(f"Erreur durant l'importation de {raw['ref']}")
delivery.persist()

View file

@ -96,6 +96,7 @@ class Product(Base):
url: str = ""
img: str = ""
packing: int = None
producer: str = ""
def __str__(self):
out = self.name
@ -133,9 +134,13 @@ class Order(Base):
yield from self.products.items()
def total(self, products):
def _get_price(ref):
product = products.get(ref)
return product.price if product else 0
products = {p.ref: p for p in products}
return round(
sum(p.quantity * products[ref].price for ref, p in self.products.items()), 2
sum(p.quantity * _get_price(ref) for ref, p in self.products.items()), 2
)
@property
@ -153,7 +158,7 @@ class Delivery(Base):
ADJUSTMENT = 2
ARCHIVED = 3
producer: str
name: str
from_date: datetime_field
to_date: datetime_field
order_before: datetime_field
@ -183,6 +188,10 @@ class Delivery(Base):
def total(self):
return round(sum(o.total(self.products) for o in self.orders.values()), 2)
@property
def has_multiple_producers(self):
return len(set([p.producer for p in self.products])) > 1
@property
def is_open(self):
return datetime.now().date() <= self.order_before.date()
@ -288,3 +297,12 @@ class Delivery(Base):
def has_order(self, person):
return person.email in self.orders
def get_products_by(self, producer):
return [p for p in self.products if p.producer == producer]
def total_for_producer(self, producer, person=None):
producer_products = [p for p in self.products if p.producer == producer]
if person:
return self.orders.get(person).total(producer_products)
return round(sum(o.total(producer_products) for o in self.orders.values()), 2)

View file

@ -41,10 +41,10 @@ def full(delivery):
wb = Workbook()
ws = wb.active
ws.title = f"{delivery.producer} {delivery.from_date.date()}"
headers = ["ref", "produit", "prix"] + [e for e in delivery.orders] + ["total"]
headers = ["ref", "produit", "prix", "producer"] + [e for e in delivery.orders] + ["total"]
ws.append(headers)
for product in delivery.products:
row = [product.ref, str(product), product.price]
row = [product.ref, str(product), product.price, product.producer]
for order in delivery.orders.values():
wanted = order.products.get(product.ref)
row.append(wanted.quantity if wanted else 0)

View file

@ -350,6 +350,7 @@ td.total,
th.total {
background-color: #bbb;
}
tr:nth-child(even) {
background-color: #ddd;
}
@ -362,6 +363,15 @@ thead tr * {
thead th + th {
border-left: 1px solid white;
}
tr .producer {
border-bottom: 1px solid #aaa;
}
tr.subtotal {
background-color: #bbb;
}
article.order {
max-width: 1200px;
margin-left: auto;

View file

@ -7,6 +7,9 @@
<table class="delivery">
<thead>
<tr>
{% if delivery.has_multiple_producers %}
<th class="producer">Producteur</th>
{% endif %}
<th class="product">Produit</th>
<th class="price">Prix</th>
{% if delivery.has_packing %}
@ -27,6 +30,9 @@
<tbody>
{% for product in delivery.products %}
<tr>
{% if delivery.has_multiple_producers and (loop.first or loop.previtem.producer != product.producer) %}
<th class="producer" rowspan="{{ delivery.get_products_by(product.producer) | length }}">{{ product.producer }}</th>
{% endif %}
<th class="product">{{ product }}</th>
<td>{{ product.price | round(2) }} €</td>
{% if delivery.has_packing %}
@ -35,22 +41,39 @@
<th{% if delivery.status == delivery.ADJUSTMENT and delivery.product_missing(product) %} class="missing" title="Les commandes individuelles ne correspondent pas aux conditionnements"{% endif %}>
{{ delivery.product_wanted(product) }}
{% if delivery.status == delivery.ADJUSTMENT and delivery.product_missing(product) %} ({{ delivery.product_missing(product) }})
{% if request.user.is_staff %}<a href="/livraison/{{ delivery.id }}/ajuster/{{ product.ref }}" class="button" title="ajuster le produit">ajuster</a>{% endif %}
{% if request.user.is_staff %}<a href="/livraison/{{ delivery.id }}/ajuster/{{ product.ref }}" class="button" title="ajuster le produit">ajuster</a>{% endif %}
{% endif %}
</th>
{% for email, order in delivery.orders.items() %}
<td title="Commandé: {{ order[product.ref].wanted }} — Ajusté: {{ "%+d"|format(order[product.ref].adjustment) }}">{{ order[product.ref].quantity or "—" }}</td>
{% endfor %}
</tr>
{% if delivery.has_multiple_producers and (loop.last or loop.nextitem.producer != product.producer) %}
<tr class="subtotal">
<td></td>
<th>Sous Total {{ product.producer }}</th>
<td></td>
{% if delivery.has_packing %}
<td></td>
{% endif %}
<th>{{ delivery.total_for_producer(product.producer) }} €</th>
{% for email in delivery.orders.keys() %}
<th>{{ delivery.total_for_producer(product.producer, email) }} €</th>
{% endfor %}
</tr>
{% endif %}
{% endfor %}
<tr>
<th class="total"><i class="icon-pricetags"></i> Total</th><td></td>
{% if delivery.has_multiple_producers %}
<td></td>
{% endif %}
{% if delivery.has_packing %}
<td></td>
{% endif %}
<th class="total">{{ delivery.total }} €</th>
{% for email, order in delivery.orders.items() %}
<td>{{ order.total(delivery.products) }} €</td>
<td class="total">{{ order.total(delivery.products) }} €</td>
{% endfor %}
</tr>
</tbody>

View file

@ -8,11 +8,11 @@
{% endif %}
<form method="post">
<label>
<p>Producteur</p>
<input type="text" name="producer" value="{{ delivery.producer or '' }}" required>
<p>Nom</p>
<input type="text" name="name" value="{{ delivery.name or '' }}">
</label>
<label>
<p>Description des produits</p>
<h5>Description des produits</h5>
<input type="text" name="description" value="{{ delivery.description or '' }}">
</label>
<label>

View file

@ -15,6 +15,8 @@
<dd>Prix d'une unité, en euros.</dd>
<dt>unit</dt>
<dd>Conditionnement d'une unité: 1kg, 33cl…</dd>
<dt>producer</dt>
<dd>Le nom du producteur</dd>
<dt>description</dt>
<dd>Plus de détails sur le produit.</dd>
<dt>packing</dt>

View file

@ -2,38 +2,46 @@
{% block body %}
<article class="order">
<h3><a href="/livraison/{{ delivery.id }}">{{ delivery.producer }}</a> — Commande de «{{ person.email }}»</h3>
<h3>{% if delivery.producer %}<a href="/livraison/{{ delivery.id }}">{{ delivery.producer }}</a>{% endif %}Commande de « {{ person.email }} »</h3>
{% include "includes/delivery_head.html" %}
<form method="post">
<table class="order">
<thead>
<tr>
{% if delivery.has_multiple_producers %}
<th class="producer">Producteur</th>
{% endif %}
<th class="product">Produit</th>
<th class="price">Prix</th>
{% if delivery.has_packing %}
<th class="packing">Conditionnement</th>
{% endif %}
<th class="amount">Commande</th>
{% if delivery.status == delivery.ADJUSTMENT or order.has_adjustments %}<th class="amount">Ajustement +/</th>{% endif %}
{% if delivery.status == delivery.ADJUSTMENT or order.has_adjustments %}
<th class="amount">Ajustement +/</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for product in delivery.products %}
<tr>
{% if delivery.has_multiple_producers and (loop.first or loop.previtem.producer != product.producer) %}
<th class="producer" rowspan="{{ delivery.get_products_by(product.producer) | length }}">{{ product.producer }}</th>
{% endif %}
<th class="product">{{ product }}
{% if product.description or product.img %}
{% with unique_id=loop.index %}
{% include "includes/modal_product.html" %}
{% endwith %}
{% endif %}</p>
{% endif %}
</th>
<td>{{ product.price | round(2) }} €</td>
{% if delivery.has_packing %}
<td{% if delivery.status == delivery.ADJUSTMENT and delivery.product_missing(product) %} class="missing" title="Les commandes individuelles ne correspondent pas aux conditionnements"{% endif %}>{{ product.packing or "—" }}{% if delivery.status == delivery.ADJUSTMENT and delivery.product_missing(product) %} ({{ delivery.product_missing(product) }}){% endif %}</td>
<td {% if delivery.status == delivery.ADJUSTMENT and delivery.product_missing(product) %} class="missing" title="Les commandes individuelles ne correspondent pas aux conditionnements"{% endif %}>{{ product.packing or "—" }}{% if delivery.status == delivery.ADJUSTMENT and delivery.product_missing(product) %} ({{ delivery.product_missing(product) }}){% endif %}</td>
{% endif %}
<td class="with-input"><input {% if delivery.status != delivery.OPEN %}type="text" readonly{% else%}type="number"{% endif%} min=0 name="wanted:{{ product.ref }}" value="{{ order[product].wanted }}"></td>
{% if delivery.status == delivery.ADJUSTMENT or order.has_adjustments %}
<td class="with-input"><input type="number" name="adjustment:{{ product.ref }}" value="{{ order[product].adjustment }}" {% if not delivery.product_missing(product) %}readonly{% endif %}></td>
<td class="with-input"><input type="number" name="adjustment:{{ product.ref }}" value="{{ order[product].adjustment }}" {% if not delivery.product_missing(product) %}readonly{% endif %}></td>
{% endif %}
</tr>
{% endfor %}