mirror of
https://github.com/almet/copanier.git
synced 2025-04-28 11:32:38 +02:00
Handle multiple producers per delivery
This commit is contained in:
parent
04d5fca259
commit
6abe77de05
9 changed files with 80 additions and 16 deletions
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
||||
|
|
Loading…
Reference in a new issue