Update the demo mode

This commit is contained in:
Alexis Métaireau 2023-01-31 01:08:37 +01:00
parent 5e1e88545f
commit ff262418c3
16 changed files with 789 additions and 711 deletions

View file

@ -12,6 +12,10 @@ import yaml
from . import config
def demo_mode_enabled():
return getattr(config, "DEMO_MODE", False)
class DoesNotExist(ValueError):
pass
@ -78,11 +82,10 @@ class Base:
@dataclass
class PersistedBase(Base):
@classmethod
def get_root(cls):
root = Path(config.DATA_ROOT)
if getattr(config, 'DEMO_MODE', False):
if demo_mode_enabled():
root = root / "demo"
return root / cls.__root__
@ -111,6 +114,7 @@ class SavedConfiguration(PersistedBase):
data = {}
return cls(**data)
@dataclass
class Person(Base):
email: str
@ -168,13 +172,12 @@ class Groups(PersistedBase):
groups = cls.load()
return len(groups.groups) > 0
def persist(self):
with self.__lock__:
self.get_path().write_text(self.dump())
def add_group(self, group):
assert group.id not in self.groups, "Un groupe avec ce nom existe déjà."
assert group.id not in self.groups, "Un foyer avec ce nom existe déjà."
self.groups[group.id] = group
def add_user(self, email, group_id):
@ -294,7 +297,9 @@ class Order(Base):
p.quantity * _get_price(ref) for ref, p in self.products.items()
)
shipping = self.compute_shipping(delivery, producers, email) if include_shipping else 0
shipping = (
self.compute_shipping(delivery, producers, email) if include_shipping else 0
)
return round(total_products + shipping, 2)
@ -360,9 +365,13 @@ class Delivery(PersistedBase):
def products_need_price_update(self, products=None):
products = products or self.products
max_age = self.from_date.date() - timedelta(days=60)
return any([product.last_update.date() < max_age
for product in products
if product.producer in self.producers])
return any(
[
product.last_update.date() < max_age
for product in products
if product.producer in self.producers
]
)
@property
def dates(self):
@ -373,7 +382,7 @@ class Delivery(PersistedBase):
"price_update_deadline": self.order_before - timedelta(weeks=2),
"order_before": self.order_before,
"adjustment_deadline": self.order_before + timedelta(days=4),
"delivery_date": delivery_date
"delivery_date": delivery_date,
}
@property
@ -392,11 +401,9 @@ class Delivery(PersistedBase):
def is_waiting_products(self):
return (
datetime.now().date() >= self.order_before.date()
and
datetime.now().date() <= self.from_date.date()
and datetime.now().date() <= self.from_date.date()
)
@property
def is_foreseen(self):
return datetime.now().date() <= self.from_date.date()
@ -429,20 +436,20 @@ class Delivery(PersistedBase):
def _dedupe_products(raw_data):
"""On some rare occasions, different products get
the same identifier (ref).
the same identifier (ref).
This function finds them and appends "-dedupe" to it.
This is not ideal but fixes the problem before it causes more
trouble (such as https://github.com/spiral-project/copanier/issues/136)
This function finds them and appends "-dedupe" to it.
This is not ideal but fixes the problem before it causes more
trouble (such as https://github.com/spiral-project/copanier/issues/136)
This function returns True if dupes have been found.
This function returns True if dupes have been found.
"""
if ('products' not in raw_data) or len(raw_data['products']) < 1:
if ("products" not in raw_data) or len(raw_data["products"]) < 1:
return False
products = raw_data['products']
products = raw_data["products"]
counter = Counter([p['ref'] for p in products])
counter = Counter([p["ref"] for p in products])
most_common = counter.most_common(1)[0]
number_of_dupes = most_common[1]
@ -454,24 +461,33 @@ class Delivery(PersistedBase):
counter = 0
new_products = []
for product in products:
ref = product['ref']
ref = product["ref"]
if ref == dupe_id:
counter = counter + 1
if counter == number_of_dupes: # Only change the last occurence.
product['ref'] = f'{ref}-dedupe'
if counter == number_of_dupes: # Only change the last occurence.
product["ref"] = f"{ref}-dedupe"
new_products.append(product)
raw_data['products'] = new_products
raw_data["products"] = new_products
return True
data = yaml.safe_load(path.read_text())
dupe_found = _dedupe_products(data)
# Tolerate extra fields (but we'll lose them if instance is persisted)
data = {k: v for k, v in data.items() if k in cls.__dataclass_fields__}
delivery = cls(**data)
delivery.id = id
if demo_mode_enabled():
delivery.from_date = datetime.now()
delivery.to_date = datetime.now() + timedelta(days=10)
delivery.order_before = datetime.now() + timedelta(days=5)
delivery.validate_all_prices()
delivery.persist()
if dupe_found:
delivery.persist()
return delivery
@classmethod
@ -591,3 +607,7 @@ class Delivery(PersistedBase):
percentage_person = person_amount / producer_total
shipping = percentage_person * producer_shipping
return shipping
def validate_all_prices(self):
for product in self.products:
product.last_update = datetime.now()

View file

@ -52,7 +52,7 @@
{% if request.user and (request.user.is_staff or not config.HIDE_GROUPS_LINK) %}
<li class="pure-menu-item">
<a class="pure-menu-link" class="pure-menu-link" href="{{ url_for('groups') }}"><i
class="icon-globe"></i>&nbsp;Gérer les groupes</a>
class="icon-globe"></i>&nbsp;Gérer les foyers</a>
</li>
{% endif %}
<li class="pure-menu-item">

View file

@ -9,11 +9,13 @@
<table class="paiements">
<tr>
<td></td>
{% for crediter in crediters %}<td>{% if crediter[0] in crediters_groups %} {{ crediters_groups[crediter[0]] }}*{% else %}{{ crediter[0] }}{% endif %} (+{{ crediter[1] | round(2) }})</td>{% endfor %}
{% for crediter in crediters %}<td>{% if crediter[0] in crediters_groups %} {{ crediters_groups[crediter[0]]
}}*{% else %}{{ crediter[0] }}{% endif %} (+{{ crediter[1] | round(2) }})</td>{% endfor %}
</tr>
{% for debiter in debiters %}
<tr>
<td>{% if debiter[0] in debiters_groups %} {{ debiters_groups[debiter[0]].name }}{% else %}{{ debiter[0] }}{% endif %} ({{ debiter[1] | round(2) }})</td>
<td>{% if debiter[0] in debiters_groups %} {{ debiters_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) %}
@ -23,7 +25,10 @@
{% endfor %}
</table>
<p class="info"><i class="icon-lightbulb"></i>&nbsp; <strong>Mais, comment ça marche ?</strong> La répartition des chèques se fait automatiquement, en soustrayant ce que les personnes doivent (au nom de leur coloc / groupe) à ce qui leur est du (dans le cas où elles sont référentes pour certains produits).</p>
<p class="info">Les personnes indiquées avec un <code>*</code> à côté de leur nom sont celles qui ont payé cette commande pour leur groupe.</p>
<p class="info"><i class="icon-lightbulb"></i>&nbsp; <strong>Mais, comment ça marche ?</strong> La répartition des
chèques se fait automatiquement, en soustrayant ce que les personnes doivent (au nom de leur foyer) à ce
qui leur est du (dans le cas où elles sont référentes pour certains produits).</p>
<p class="info">Les personnes indiquées avec un <code>*</code> à côté de leur nom sont celles qui ont payé cette
commande pour leur foyer.</p>
{% endblock body %}

View file

@ -3,20 +3,26 @@
{% block additional_menu %}
<div class="pure-menu">
<ul class="pure-menu-list">
<li class="pure-menu-item"><a href="{{ url_for('list_products', id=delivery.id) }}/produits.pdf" class="pure-menu-link"><i class="icon-ribbon"></i>&nbsp;Bons de commande</a></li>
<li class="pure-menu-item"><a href="{{ url_for('show_orders_summary', id=delivery.id) }}" class="pure-menu-link"><i class="icon-grid"></i>&nbsp;Commandes groupes</a></li>
<li class="pure-menu-item"><a href="{{ url_for('compute_payments', id=delivery.id) }}" class="pure-menu-link"><i class="icon-wallet"></i>&nbsp;Paiements</a></li>
<li class="pure-menu-item"><a href="{{ url_for('list_products', id=delivery.id) }}/produits.pdf"
class="pure-menu-link"><i class="icon-ribbon"></i>&nbsp;Bons de commande</a></li>
<li class="pure-menu-item"><a href="{{ url_for('show_orders_summary', id=delivery.id) }}"
class="pure-menu-link"><i class="icon-grid"></i>&nbsp;Commandes foyers</a></li>
<li class="pure-menu-item"><a href="{{ url_for('compute_payments', id=delivery.id) }}" class="pure-menu-link"><i
class="icon-wallet"></i>&nbsp;Paiements</a></li>
{% if request['user'].email == delivery.contact and delivery.status > delivery.EMPTY %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="{{ url_for('show_delivery_toolbox', id=delivery.id) }}"><i class="icon-tools"></i>&nbsp;Boîte à outils</a>
<a class="pure-menu-link" href="{{ url_for('show_delivery_toolbox', id=delivery.id) }}"><i
class="icon-tools"></i>&nbsp;Boîte à outils</a>
</li>
{% endif %}
{% if request.user and request.user.is_staff %}
<li class="pure-menu-item">
<a class="pure-menu-link" href="{{ url_for('edit_delivery', id=delivery.id) }}"><i class="icon-adjustments"></i>&nbsp;Modifier la distrib</a>
<a class="pure-menu-link" href="{{ url_for('edit_delivery', id=delivery.id) }}"><i
class="icon-adjustments"></i>&nbsp;Modifier la distrib</a>
</li>
<li class="pure-menu-item">
<a class="pure-menu-link" href="{{ url_for('list_products', id=delivery.id) }}"><i class="icon-pricetags"></i>&nbsp;Éditer produits</a>
<a class="pure-menu-link" href="{{ url_for('list_products', id=delivery.id) }}"><i
class="icon-pricetags"></i>&nbsp;Éditer produits</a>
</li>
{% endif %}
</ul>
@ -25,14 +31,16 @@
{% block body %}
{% if delivery.status == delivery.CLOSED %}
<div class="important-message">Une fois la distribution terminée, reviens ici pour <a class="button" href="{{ url_for('hand_over_delivery', id=delivery.id) }}">passer le relai !</a></div>
<div class="important-message">Une fois la distribution terminée, reviens ici pour <a class="button"
href="{{ url_for('hand_over_delivery', id=delivery.id) }}">passer le relai !</a></div>
{% endif %}
<div class="header">
<h1>{{ delivery.name }}</h1>
<h2>
Distribution le <i class="icon-clock"></i> {{ delivery.from_date|date }}, {{ delivery.from_date|time }} - {{ delivery.to_date|time }}, à <i class="icon-streetsign"></i> {{ delivery.where }}.
Distribution le <i class="icon-clock"></i> {{ delivery.from_date|date }}, {{ delivery.from_date|time }} - {{
delivery.to_date|time }}, à <i class="icon-streetsign"></i> {{ delivery.where }}.
</h2>
<h3>{% if delivery.products %}
@ -45,13 +53,13 @@
</div>
<article class="delivery">
{% if request['user'].email == delivery.contact %}
<div class="placeholder center">
Hey, jettes un coup d'oeil à
<a href="{{ url_for('show_delivery_toolbox', id=delivery.id) }}">&nbsp;la boîte à outils</a> !
</div>
{% endif %}
{% if delivery.has_products %}
{% if request['user'].email == delivery.contact %}
<div class="placeholder center">
Hey, jettes un coup d'oeil à
<a href="{{ url_for('show_delivery_toolbox', id=delivery.id) }}">&nbsp;la boîte à outils</a> !
</div>
{% endif %}
{% if delivery.has_products %}
{% for (id, producer) in delivery.get_producers_for_referent(request.user.email).items() %}
{% if producer.needs_price_update(delivery) %}
{% set modal_body %}
@ -60,25 +68,29 @@ Hey, jettes un coup d'oeil à
Certains produits dont tu est référent⋅e ont besoin d'être mis à jour.<br /><br />
Est-ce que tu veux t'en occuper maintenant ?<br />
<a class="button" href="{{ url_for('edit_producer', delivery_id=delivery.id, producer_id=producer.id) }}#products">Oui, mettre à jour les prix pour {{ producer.name }}</a>
<a class="button"
href="{{ url_for('edit_producer', delivery_id=delivery.id, producer_id=producer.id) }}#products">Oui, mettre à
jour les prix pour {{ producer.name }}</a>
{%- endset %}
{{ macros.modal(id="update-price", body=modal_body, checked=True) }}
{% break %}
{% endif %}
{% endfor %}
{% include "includes/delivery_table.html" %}
{% else %}
<div class="placeholder">
<h2>😔 Pour le moment, cette distribution est bien vide…</h2>
{% if request.user and request.user.is_staff %}
{% else %}
<div class="placeholder">
<h2>😔 Pour le moment, cette distribution est bien vide…</h2>
{% if request.user and request.user.is_staff %}
Occupons-nous donc de ça ! Deux options :
<ol>
<li><a href="{{ url_for('create_producer', delivery_id=delivery.id) }}">Ajouter les product⋅eurs⋅rices</a> à la main ;</li>
<li>Ou bien <a href="{{ url_for('copy_products', id=delivery.id) }}">copier les produits d'une autre distribution</a>.</li>
<li><a href="{{ url_for('create_producer', delivery_id=delivery.id) }}">Ajouter les product⋅eurs⋅rices</a> à
la main ;</li>
<li>Ou bien <a href="{{ url_for('copy_products', id=delivery.id) }}">copier les produits d'une autre
distribution</a>.</li>
</ol>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
</article>
<hr>
<ul class="toolbox">

View file

@ -1,6 +1,7 @@
{% extends "base.html" %}
{% block toplink %}<a href="{{ url_for('show_delivery', id=delivery.id) }}">↶ Retourner à la distribution</a>{% endblock %}
{% block toplink %}<a href="{{ url_for('show_delivery', id=delivery.id) }}">↶ Retourner à la distribution</a>{% endblock
%}
{% block body %}
@ -8,7 +9,9 @@
<h1>{{ delivery.name }}</h1>
</div>
<i class="icon-lightbulb"></i> <strong>{{ delivery.orders|length }}</strong> groupes, <strong>{{ delivery.products|length }}</strong> produits et <strong>{{ delivery.producers | length}}</strong> fournisseurs. <br /> Total de la commande : <strong>{{ delivery.total }}€</strong></li>
<i class="icon-lightbulb"></i> <strong>{{ delivery.orders|length }}</strong> foyers, <strong>{{ delivery.products|length
}}</strong> produits et <strong>{{ delivery.producers | length}}</strong> fournisseurs. <br /> Total de la commande
: <strong>{{ delivery.total }}€</strong></li>
<h2>Rappel des dates</h2>
{% include "includes/delivery_dates_table.html" %}
@ -21,23 +24,31 @@
Avant et pendant la distribution :
<ul>
<li><a href="{{ url_for('groups', id=delivery.id) }}"><i class="icon-globe"></i>&nbsp; Gérer les groupes / colocs</a></li>
<li><a href="{{ url_for('edit_delivery', id=delivery.id) }}"><i class="icon-pencil"></i>&nbsp; Modifier la commande (dates, lieu, référent⋅e, etc)</a></li>
<li><a href="{{ url_for('list_products', id=delivery.id) }}"><i class="icon-pencil"></i>&nbsp; Gérer les produits</a></li>
<li><a href="{{ url_for('groups', id=delivery.id) }}"><i class="icon-globe"></i>&nbsp; Gérer les foyers /
colocs</a></li>
<li><a href="{{ url_for('edit_delivery', id=delivery.id) }}"><i class="icon-pencil"></i>&nbsp; Modifier la commande
(dates, lieu, référent⋅e, etc)</a></li>
<li><a href="{{ url_for('list_products', id=delivery.id) }}"><i class="icon-pencil"></i>&nbsp; Gérer les
produits</a></li>
</ul>
Une fois les commandes passées :
<ul>
<li><a href="{{ url_for('list_products', id=delivery.id) }}/produits.pdf"><i class="icon-download"></i>&nbsp; Télécharger la liste des produits commandés</a></li>
<li><a href="{{ url_for('generate_report', id=delivery.id) }}"><i class="icon-download"></i>&nbsp; Télécharger le tableau des commandes</a></li>
<li><a href="{{ url_for('send_referent_emails', id=delivery.id) }}"><i class="icon-envelope"></i>&nbsp; Envoyer les infos de commande aux référent⋅e⋅s</a></li>
<li><a href="{{ url_for('list_products', id=delivery.id) }}/produits.pdf"><i class="icon-download"></i>&nbsp;
Télécharger la liste des produits commandés</a></li>
<li><a href="{{ url_for('generate_report', id=delivery.id) }}"><i class="icon-download"></i>&nbsp; Télécharger le
tableau des commandes</a></li>
<li><a href="{{ url_for('send_referent_emails', id=delivery.id) }}"><i class="icon-envelope"></i>&nbsp; Envoyer les
infos de commande aux référent⋅e⋅s</a></li>
</ul>
Pour préparer la distribution :
<ul>
<li><a href="{{ url_for('show_orders_summary', id=delivery.id) }}"><i class="icon-document"></i>&nbsp; Fiches de commandes par groupe</a></li>
<li><a href="{{ url_for('compute_payments', id=delivery.id) }}"><i class="icon-gears"></i>&nbsp; Faire la répartition des paiements</a></li>
<li><a href="{{ url_for('show_orders_summary', id=delivery.id) }}"><i class="icon-document"></i>&nbsp; Fiches de
commandes par foyer</a></li>
<li><a href="{{ url_for('compute_payments', id=delivery.id) }}"><i class="icon-gears"></i>&nbsp; Faire la
répartition des paiements</a></li>
</ul>
{% endblock %}

View file

@ -3,11 +3,11 @@
{% block body %}
<div class="header">
{% if group.id %}
<h1>Modifier le groupe</h1>
<h1>Modifier le foyer</h1>
{% else %}
<h1>Créer un nouveau groupe</h1>
<h1>Créer un nouveau foyer</h1>
{% endif %}
<h4>Les groupes permettent de gérer les commandes pour d'autres personnes (colocs, familles, etc)</h4>
<h4>Les foyers permettent de gérer les commandes pour d'autres personnes (colocs, familles, etc)</h4>
</div>
<form method="post">
@ -16,7 +16,7 @@
<input type="text" name="name" value="{{ group.name or '' }}" required>
</label>
<label>
<p>Membres du groupe (emails, séparés par des virgules)</p>
<p>Membres du foyer (emails, séparés par des virgules)</p>
<input type="text" name="members" value="{{ ', '.join(group.members) if group.members else '' }}">
</label>
<div>
@ -27,7 +27,8 @@
{% if group.id %}
<ul class="toolbox">
<li>
<a href="{{ url_for('delete_group', id=group.id) }}" class="button danger"><i class="icon-hazardous"></i>&nbsp;Supprimer ce groupe</a>
<a href="{{ url_for('delete_group', id=group.id) }}" class="button danger"><i
class="icon-hazardous"></i>&nbsp;Supprimer ce foyer</a>
</li>
</ul>
{% endif %}

View file

@ -2,28 +2,31 @@
{% block body %}
<div class="header">
<h1>Groupes</h1>
<h1>Foyers</h1>
<div class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
<li class="pure-menu-item">
<a class="pure-menu-link" href="{{ url_for('create_group') }}"><i class="icon-globe"></i>&nbsp;Créer un nouveau groupe</a>
<a class="pure-menu-link" href="{{ url_for('create_group') }}"><i class="icon-globe"></i>&nbsp;Créer un
nouveau foyer</a>
</li>
</ul>
</div>
</div>
{% if not request['user'].group_id %}
<p>Bienvenue ! Avant de pouvoir commander, peux-tu nous indiquer pour quelle coloc / famille tu vas passer commande ? </p>
<p>Bienvenue ! Avant de pouvoir commander, peux-tu nous indiquer pour quel foyer tu vas passer commande ?
</p>
{% endif %}
{% if not groups.groups %}
<p>On dirait que tu arrive parmis les premier⋅es ! <a class="button" href="{{ url_for('create_group') }}"><i class="icon-globe"></i>&nbsp;Créé un nouveau groupe.</a></p>
<p>On dirait que tu arrive parmis les premier⋅es ! <a class="button" href="{{ url_for('create_group') }}"><i
class="icon-globe"></i>&nbsp;Créé un nouveau foyer.</a></p>
{% else %}
<table id="groups" class="pure-table">
<thead>
<tr>
<th>Groupe</th>
<th>Foyer</th>
<th>Membres</th>
<th>Actions</th>
</tr>
@ -39,13 +42,16 @@
{% endfor %}
</ul>
</td>
<td>{% if group.id != request['user'].group_id %}<a class="pure-button" href="{{ url_for('join_group', id=group.id) }}">rejoindre</a>{% endif %} <a class="pure-button" href="{{ url_for('edit_group', id=group.id) }}">éditer</a></td>
<td>{% if group.id != request['user'].group_id %}<a class="pure-button"
href="{{ url_for('join_group', id=group.id) }}">rejoindre</a>{% endif %} <a class="pure-button"
href="{{ url_for('edit_group', id=group.id) }}">éditer</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<p>Tu ne fais partie d'aucun des groupes listés ici ? Tu peux <a class="button" href="{{ url_for('create_group') }}"><i class="icon-globe"></i>&nbsp;en créer un nouveau</a></p>
<p>Tu ne fais partie d'aucun des foyers listés ici ? Tu peux <a class="button" href="{{ url_for('create_group') }}"><i
class="icon-globe"></i>&nbsp;en créer un nouveau</a></p>
{% endif %}
{% endblock %}

View file

@ -1,26 +1,31 @@
<table class="pure-table fixed-table">
<thead>
<tr>
<th></th><th>Dates</th><th>Coord</th><th>Référent⋅e⋅s</th>
<th></th>
<th>Dates</th>
<th>Coord</th>
<th>Référent⋅e⋅s</th>
</tr>
</thead>
<tbody>
<tr>
<th>Création de la distribution</th>
<td>{{ delivery.dates.creation_date | date}}</td>
<td>Rappeler aux référent⋅e⋅s produit de mettre leurs prix à jour, vérifier que tous les produits sont bien présentes, en ajouter si besoin</td>
<td>Rappeler aux référent⋅e⋅s produit de mettre leurs prix à jour, vérifier que tous les produits sont bien
présentes, en ajouter si besoin</td>
<td>-</td>
</tr>
<tr>
<th>Mise à jour des prix</th>
<td>Du {{ delivery.dates.price_update_start | date }} au {{ delivery.dates.price_update_deadline | date}}</td>
<td>Du {{ delivery.dates.price_update_start | date }} au {{ delivery.dates.price_update_deadline | date}}
</td>
<td></td>
<td>Les référent⋅e⋅s produit mettent les prix à jour.</td>
</tr>
<tr>
<th>Commandes</th>
<td>Du {{ delivery.dates.price_update_deadline | date }} au {{ delivery.dates.order_before | date }}</td>
<td>Envoyer le lien de commande aux groupes</td>
<td>Envoyer le lien de commande aux foyers</td>
<td></td>
</tr>
<tr>
@ -32,25 +37,29 @@
<tr>
<th>Récup des produits</th>
<td>Du {{ delivery.dates.adjustment_deadline | date }} au {{ delivery.dates.delivery_date | date }}</td>
<td><a href="{{ url_for('send_referent_emails', id=delivery.id) }}">Envoyer les infos de commande aux référent⋅e⋅s</a></td>
<td><a href="{{ url_for('send_referent_emails', id=delivery.id) }}">Envoyer les infos de commande aux
référent⋅e⋅s</a></td>
<td>Transmettre les commandes, <strong>récupérer les produits</strong></td>
</tr>
<tr>
<th>Préparation de la distribution</th>
<td>La veille du {{ delivery.dates.delivery_date | date }}</td>
<td><a href="{{ url_for('show_orders_summary', id=delivery.id) }}">Imprimer les bons de commandes par groupe</a></td>
<td><a href="{{ url_for('show_orders_summary', id=delivery.id) }}">Imprimer les bons de commandes par
foyer</a></td>
<td></td>
</tr>
<tr>
<th>Distribution</th>
<td>{{ delivery.dates.delivery_date | date }}</td>
<td>Coordonner la distribution, <a href="{{ url_for('compute_payments', id=delivery.id) }}">faire la répartition des chèques</a></td>
<td>Coordonner la distribution, <a href="{{ url_for('compute_payments', id=delivery.id) }}">faire la
répartition des chèques</a></td>
<td>Arriver 30mn avant le début de la distribution, répartir les produits par coloc</td>
</tr>
<tr>
<th>Transmission</th>
<td>Après la distribution</td>
<td><a href="{{ url_for('hand_over_delivery', id=delivery.id) }}">Passer le relai à la nouvelle personne référente</a></a></td>
<td><a href="{{ url_for('hand_over_delivery', id=delivery.id) }}">Passer le relai à la nouvelle personne
référente</a></a></td>
<td></td>
</tr>
</tbody>

View file

@ -1,13 +1,16 @@
{% if deliveries %}
<ul class="delivery">
{% for delivery in deliveries %}
<li>
<h3><a href="{{ url_for('show_delivery', id=delivery.id) }}"><i class="icon-hotairballoon"></i> {{ delivery.name }}</a> {% include "includes/order_button.html" %} <a class="button" href="{{ url_for('show_delivery', id=delivery.id) }}">Voir les commandes</a></h3>
{% include "includes/delivery_head.html" %}
</li>
<hr>
{% endfor %}
{% for delivery in deliveries %}
<li>
<h3><a href="{{ url_for('show_delivery', id=delivery.id) }}"><i class="icon-hotairballoon"></i> {{ delivery.name
}}</a> {% include "includes/order_button.html" %} <a class="button"
href="{{ url_for('show_delivery', id=delivery.id) }}">Voir les commandes</a></h3>
{% include "includes/delivery_head.html" %}
</li>
<hr>
{% endfor %}
</ul>
{% else %}
<p>Il n'y a aucune distribution à venir. Vous pouvez <a href="{{ url_for('new_delivery') }}">en lancer une nouvelle</a> !
{% endif %}
<p>🤔 Il n'y a aucune distribution à venir. Vous pouvez <a href="{{ url_for('new_delivery') }}">en lancer une
nouvelle</a> !
{% endif %}

View file

@ -4,9 +4,13 @@
<p>On dirait que vous venez de lancer ce logiciel pour la première fois, bienvenue ici 😀.</p>
<p>Pour commencer, deux options :</p>
<ul>
<li><a href=" {{ url_for('activate_demo') }}">Activer le mode de démonstration</a>, cela va charger des données de démonstration pour que vous puissiez aller jeter un coup d'oeil au fonctionnement du logiciel ;</li>
<li>Ou alors si vous avez envie de commencer à utiliser le logiciel, vous devez commencer par <a href="{{ url_for('groups') }}">rejoindre un groupe</a> et commencer une distribution.</p></li>
<li><a class="button" href=" {{ url_for('activate_demo') }}">Activer le mode de démonstration</a> pour jeter un coup
d'œil rapidement aux fonctionalités.</li>
<li>Sinon, vous pouvez commencer par <a class="button" href="{{ url_for('groups') }}">rejoindre un foyer</a> et
commencer une distribution.</p>
</li>
</ul>
<p>Bon voyage 🙏 !</p>
<p>La peinture est encore fraiche, alors si vous avez besoin d'un coup de main, n'hésitez pas à <a
href="mailto:alexis@notmyidea.org">m'envoyer un mail</a> ! 🙏</p>
{% endblock body %}

View file

@ -20,7 +20,7 @@ async def join_group(request, response, id):
request["groups"].persist()
redirect = "/" if not request["user"].group_id else "/groupes"
response.message(f"Vous avez bien rejoint le groupe « {group.name} »")
response.message(f"Vous avez bien rejoint le foyer « {group.name} »")
response.redirect = redirect
@ -41,14 +41,14 @@ async def create_group(request, response):
)
request["groups"].add_group(group)
request["groups"].persist()
response.message(f"Le groupe {group.name} à bien été créé")
response.message(f"Le foyer {group.name} à bien été créé")
response.redirect = "/"
response.html("groups/edit_group.html", group=group)
@app.route("/groupes/{id}/éditer", methods=["GET", "POST"])
async def edit_group(request, response, id):
assert id in request["groups"].groups, "Impossible de trouver le groupe"
assert id in request["groups"].groups, "Impossible de trouver le foyer"
group = request["groups"].groups[id]
if request.method == "POST":
form = request.form
@ -65,8 +65,8 @@ async def edit_group(request, response, id):
@app.route("/groupes/{id}/supprimer", methods=["GET"])
async def delete_group(request, response, id):
assert id in request["groups"].groups, "Impossible de trouver le groupe"
assert id in request["groups"].groups, "Impossible de trouver le foyer"
deleted = request["groups"].groups.pop(id)
request["groups"].persist()
response.message(f"Le groupe {deleted.name} à bien été supprimé")
response.message(f"Le foyer {deleted.name} à bien été supprimé")
response.redirect = "/groupes"

View file

@ -1,6 +1,6 @@
from .core import app, session, env, url
from ..models import Groups, Person, SavedConfiguration
from ..models import Groups, Person, SavedConfiguration, Delivery
from .. import utils, emails, config
@ -14,9 +14,9 @@ async def auth_required(request, response):
saved_config = SavedConfiguration.load()
if saved_config.demo_mode_enabled:
setattr(config, 'DEMO_MODE', True)
setattr(config, "DEMO_MODE", True)
else:
setattr(config, 'DEMO_MODE', False)
setattr(config, "DEMO_MODE", False)
if request.route.payload and not request.route.payload.get("unprotected"):
token = request.cookies.get("token")
@ -96,13 +96,16 @@ async def logout(request, response):
async def onboarding(request, response):
response.html("onboarding.html")
@app.route("/premier-lancement/demo", methods=["GET"])
async def activate_demo(request, response):
saved_config = SavedConfiguration.load()
saved_config.demo_mode_enabled = True
saved_config.persist()
response.redirect = "/"
@app.route("/premier-lancement/demo/désactiver", methods=["GET"])
async def desactivate_demo(request, response):
saved_config = SavedConfiguration.load()

View file

@ -134,9 +134,7 @@ async def validate_producer_prices(request, response, delivery_id, producer_id):
@app.route("/produits/{delivery_id}/valider-prix", methods=["GET"])
async def mark_all_prices_as_ok(request, response, delivery_id):
delivery = Delivery.load(delivery_id)
for product in delivery.products:
product.last_update = datetime.now()
delivery.validate_all_prices()
delivery.persist()
response.message(f"Les prix ont été marqués comme OK pour toute la distribution !")
@ -156,8 +154,12 @@ async def create_product(request, response, delivery_id, producer_id):
product.producer = producer_id
form = request.form
product.update_from_form(form)
random_string = "".join(random.choices(string.ascii_lowercase + string.digits, k=8))
product.ref = slugify(f"{producer_id}-{product.name}-{product.unit}-{random_string}")
random_string = "".join(
random.choices(string.ascii_lowercase + string.digits, k=8)
)
product.ref = slugify(
f"{producer_id}-{product.name}-{product.unit}-{random_string}"
)
delivery.products.append(product)
delivery.persist()

File diff suppressed because it is too large Load diff

View file

@ -5,64 +5,38 @@ groups:
- gilki@tenhe.ls
- mohu@zab.tj
- nazhap@opolarti.ly
- youpi@notmyidea.org
name: Permuflard
john:
id: john
members:
- voige@sida.li
name: John
pre-du-fond:
id: pre-du-fond
members:
- sakzace@cetbageg.ne
- es@worru.cx
name: Pré du fond
chez-louise:
id: chez-louise
members:
- suznala@iflavra.ch
- sihvo@vo.gn
name: Chez Louise
les-filles-du-bout:
id: les-filles-du-bout
members:
- tecuhmiz@ilmifhaf.edu
- pi@hozep.sj
name: Les filles du bout
chaton:
id: chaton
members:
- puet@helzet.ax
- bi@noto.fm
name: Châton
chez-louise:
id: chez-louise
members:
- suznala@iflavra.ch
- sihvo@vo.gn
name: Chez Louise
chez-pascale:
id: chez-pascale
members:
- gawumnud@izkep.bb
name: Chez Pascale
laxe:
id: laxe
john:
id: john
members:
- couv@rujli.lr
- casceci@ziceda.mv
name: Laxe
mouin:
id: mouin
- voige@sida.li
name: John
la-bas-au-loin:
id: la-bas-au-loin
members:
- rop@uznofkoz.za
- ga@ma.gb
- fuatogi@bip.sb
- te@itiorapa.gn
name: Mouin
le-chauffage:
id: le-chauffage
members:
- jaigo@hevef.gl
- du@nozcoze.lt
- em@ca.fk
- ifegomcic@pi.lt
- zow@hanheh.tn
name: Le chauffage
- uwuvenfo@dunam.na
- va@nowuk.th
- ohu@vukuk.vu
- ewmu@migo.hm
name: La Bas au loin
la-lointaine:
id: la-lointaine
members:
@ -72,14 +46,6 @@ groups:
- viw@iwfifbe.ua
- enji@ladbaped.lt
name: La lointaine
la-bas-au-loin:
id: la-bas-au-loin
members:
- uwuvenfo@dunam.na
- va@nowuk.th
- ohu@vukuk.vu
- ewmu@migo.hm
name: La Bas au loin
la-lumiere:
id: la-lumiere
members:
@ -88,6 +54,12 @@ groups:
- uveruopo@gic.org
- zimpok@gogav.sy
name: La lumière
la-moins:
id: la-moins
members:
- cuud@cof.sc
- gavciawu@huzip.ga
name: La Moins
la-reclue:
id: la-reclue
members:
@ -100,12 +72,21 @@ groups:
- pej@je.pk
- fotopesu@sumfu.sm
name: la Ville Z
la-moins:
id: la-moins
laxe:
id: laxe
members:
- cuud@cof.sc
- gavciawu@huzip.ga
name: La Moins
- couv@rujli.lr
- casceci@ziceda.mv
name: Laxe
le-chauffage:
id: le-chauffage
members:
- jaigo@hevef.gl
- du@nozcoze.lt
- em@ca.fk
- ifegomcic@pi.lt
- zow@hanheh.tn
name: Le chauffage
le-foin:
id: le-foin
members:
@ -126,12 +107,20 @@ groups:
- rocvibuv@nosmijij.tz
- it@za.rs
name: Le grand champ
ttre:
id: ttre
les-filles-du-bout:
id: les-filles-du-bout
members:
- hutfiro@aje.gov
- ce@bowzodda.in
name: TTRE
- tecuhmiz@ilmifhaf.edu
- pi@hozep.sj
name: Les filles du bout
mouin:
id: mouin
members:
- rop@uznofkoz.za
- ga@ma.gb
- fuatogi@bip.sb
- te@itiorapa.gn
name: Mouin
passage-creuse:
id: passage-creuse
members:
@ -153,12 +142,6 @@ groups:
- budavwa@ciwun.mt
- jisafu@huvogu.jm
name: Pataudes
rs:
id: rs
members:
- bok@rebu.de
- beko@noza.bz
name: R&S
peug:
id: peug
members:
@ -169,3 +152,21 @@ groups:
- zahpepez@toteppe.hu
- fiodvif@fafij.cm
name: Peug'
pre-du-fond:
id: pre-du-fond
members:
- sakzace@cetbageg.ne
- es@worru.cx
name: Pré du fond
rs:
id: rs
members:
- bok@rebu.de
- beko@noza.bz
name: R&S
ttre:
id: ttre
members:
- hutfiro@aje.gov
- ce@bowzodda.in
name: TTRE

View file

@ -40,7 +40,7 @@ Avant et pendant la distrib :
Modifier la commande (dates, lieu, référent⋅e, etc)
Modifier les produits, les product⋅rices⋅eurs
Gérer les groupes / colocs
Gérer les foyers
Une fois les commandes passées (après le dimanche 26 janvier)
Télécharger les bons de distribution