diff --git a/la_chariotte/lieu/__init__.py b/la_chariotte/lieu/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/la_chariotte/lieu/apps.py b/la_chariotte/lieu/apps.py
new file mode 100644
index 0000000..717814c
--- /dev/null
+++ b/la_chariotte/lieu/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class LieuConfig(AppConfig):
+ default_auto_field = "django.db.models.BigAutoField"
+ name = "la_chariotte.lieu"
diff --git a/la_chariotte/lieu/forms.py b/la_chariotte/lieu/forms.py
new file mode 100644
index 0000000..f84cd32
--- /dev/null
+++ b/la_chariotte/lieu/forms.py
@@ -0,0 +1,35 @@
+import datetime
+
+from django import forms
+from django.contrib.auth import get_user_model
+from django.forms.utils import to_current_timezone
+from django.utils import timezone
+
+from la_chariotte.lieu.models import Lieu
+
+
+class LieuForm(forms.ModelForm):
+ class Meta:
+ model = Lieu
+ fields = [
+ "name",
+ "description",
+ "url",
+ ]
+ widgets = {
+ "name": forms.TextInput(
+ attrs={"placeholder": "ex : Centre social Kropotkine"}
+ ),
+ "description": forms.Textarea(
+ attrs={"placeholder": "Plus d'infos sur le lieu ? (facultatif)"}
+ ),
+ "url": forms.TextInput(attrs={"placeholder": "raccourci"}),
+ }
+
+ def __init__(self, *args, **kwargs):
+ self.user = kwargs.pop("user")
+ super().__init__(*args, **kwargs)
+
+ def save(self, commit=True):
+ self.instance.orga = get_user_model().objects.get(id=self.user.pk)
+ return super().save(commit=commit)
diff --git a/la_chariotte/lieu/migrations/0001_initial.py b/la_chariotte/lieu/migrations/0001_initial.py
new file mode 100644
index 0000000..efabf0f
--- /dev/null
+++ b/la_chariotte/lieu/migrations/0001_initial.py
@@ -0,0 +1,28 @@
+from django.conf import settings
+from django.db import migrations, models
+
+class Migration(migrations.Migration):
+ initial = True
+
+ dependencies = []
+
+ operations = [
+ migrations.CreateModel(
+ name="Lieu",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("name", models.CharField(max_length=100, verbose_name="Nom du lieu de distribution")),
+ ("url", models.CharField(max_length=20, verbose_name='Portion du lien pour le lieu', unique=True)),
+ ("orga", models.ForeignKey(on_delete=models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Organisateur·ice')),
+ ("description", models.TextField(blank=True, null=True, verbose_name="Description")),
+ ],
+ ),
+ ]
diff --git a/la_chariotte/lieu/migrations/__init__.py b/la_chariotte/lieu/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/la_chariotte/lieu/models.py b/la_chariotte/lieu/models.py
new file mode 100644
index 0000000..173a3f8
--- /dev/null
+++ b/la_chariotte/lieu/models.py
@@ -0,0 +1,27 @@
+import random
+
+import base36
+from django.core.exceptions import ValidationError
+from django.db import models
+from django.urls import reverse
+from django.utils import timezone
+
+from la_chariotte.order.models import GroupedOrder
+from la_chariotte.settings import AUTH_USER_MODEL
+
+
+class Lieu(models.Model):
+ name = models.CharField(max_length=100, verbose_name="Nom du lieu de distribution")
+ orga = models.ForeignKey(
+ AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name="Organisateur·ice"
+ )
+ url = models.CharField(
+ max_length=20, verbose_name="Portion du lien pour le lieu", unique=True
+ )
+ description = models.TextField("Description", null=True, blank=True)
+
+ def __str__(self): # pragma: no cover
+ return self.name
+
+ def get_absolute_url(self):
+ return reverse("lieu:lieu_update", kwargs={"url": self.url})
diff --git a/la_chariotte/lieu/templates/lieu/index.html b/la_chariotte/lieu/templates/lieu/index.html
new file mode 100644
index 0000000..e07c72c
--- /dev/null
+++ b/la_chariotte/lieu/templates/lieu/index.html
@@ -0,0 +1,62 @@
+{% extends 'base.html' %}
+
+{% block title %}Mes lieux de livraison{% endblock %}
+
+{% block content %}
+
+ {% block content_title %}Lieux de distribution que vous organisez{% endblock %}
+
+
+ {% if lieu_context.lieu_liste %}
+
+
+
+ Lieu |
+ Commandes |
+ Description |
+ URL |
+ |
+
+
+
+ {% for lieu in lieu_context.lieu_liste %}
+
+
+ {{ lieu }}
+ |
+
+ {% if lieu.url in lieu_context.commandes.keys %}
+ {% for lieu_url, lieu_commandes in lieu_context.commandes.items %}
+ {% if lieu_url == lieu.url %}
+ {% for commande in lieu_commandes %}
+ {% url 'order:grouped_order_detail' code=commande.code as order_url %}
+ {% if order_url %}
+ {{commande.name}}
+ {% else %}
+ {{ commande.name }}
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ Aucune
+ {% endif %}
+ |
+
+ {{ lieu.description }}
+ |
+
+ {{ lieu.url }}
+ |
+
+ {% endfor %}
+
+
+ {% else %}
+ Pas de lieux de distribution pour l'instant
+ {% endif %}
+{% endblock %}
diff --git a/la_chariotte/lieu/templates/lieu/lieu_create.html b/la_chariotte/lieu/templates/lieu/lieu_create.html
new file mode 100644
index 0000000..9c64130
--- /dev/null
+++ b/la_chariotte/lieu/templates/lieu/lieu_create.html
@@ -0,0 +1,26 @@
+{% extends 'base.html' %}
+
+{% load crispy_forms_tags %}
+
+{% block title %}Nouveau lieu de distribution{% endblock %}
+
+{% block content %}
+
+ {% block content_title %}Créer un lieu de distribution{% endblock %}
+
+
+{% endblock %}
diff --git a/la_chariotte/lieu/templates/lieu/lieu_detail.html b/la_chariotte/lieu/templates/lieu/lieu_detail.html
new file mode 100644
index 0000000..e0ffa2a
--- /dev/null
+++ b/la_chariotte/lieu/templates/lieu/lieu_detail.html
@@ -0,0 +1,22 @@
+{% extends 'base.html' %}
+{% load crispy_forms_tags %}
+
+{% block title %}{{ lieu }}{% endblock %}
+
+{% block content %}
+
+ {% block content_title %}Modifier le lieu de livraison{% endblock %}
+
+
+
{{ lieu.name }} - modifier
+
+
+
+{% endblock %}
+
diff --git a/la_chariotte/lieu/templates/lieu/lieu_update.html b/la_chariotte/lieu/templates/lieu/lieu_update.html
new file mode 100644
index 0000000..41f1ec2
--- /dev/null
+++ b/la_chariotte/lieu/templates/lieu/lieu_update.html
@@ -0,0 +1,22 @@
+{% extends 'base.html' %}
+
+{% load crispy_forms_tags %}
+
+{% block title %}Modifier le lieu de livraison {% endblock %}
+
+{% block content %}
+
+ {% block content_title %}Modifier le lieu de livraison{% endblock %}
+
+
+
{{ lieu.name }} - modifier
+
+
+
+{% endblock %}
diff --git a/la_chariotte/lieu/urls.py b/la_chariotte/lieu/urls.py
new file mode 100644
index 0000000..e359279
--- /dev/null
+++ b/la_chariotte/lieu/urls.py
@@ -0,0 +1,14 @@
+from django.urls import path
+
+from . import views
+
+app_name = "lieu"
+urlpatterns = [
+ path("", views.IndexView.as_view(), name="index"),
+ path(
+ "/",
+ views.LieuUpdateView.as_view(),
+ name="lieu_update",
+ ),
+ path("creer", views.LieuCreateView.as_view(), name="create_lieu"),
+]
diff --git a/la_chariotte/lieu/views/__init__.py b/la_chariotte/lieu/views/__init__.py
new file mode 100644
index 0000000..c5c9e15
--- /dev/null
+++ b/la_chariotte/lieu/views/__init__.py
@@ -0,0 +1,6 @@
+from .lieu import (
+ IndexView,
+ LieuCreateView,
+ LieuDetailView,
+ LieuUpdateView,
+)
diff --git a/la_chariotte/lieu/views/lieu.py b/la_chariotte/lieu/views/lieu.py
new file mode 100644
index 0000000..57acc96
--- /dev/null
+++ b/la_chariotte/lieu/views/lieu.py
@@ -0,0 +1,87 @@
+import csv
+import json
+
+from django import http
+from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
+from django.core.serializers.json import DjangoJSONEncoder
+from django.shortcuts import get_object_or_404, redirect
+from django.urls import reverse, reverse_lazy
+from django.utils import timezone
+from django.views import generic
+from django_weasyprint import WeasyTemplateResponseMixin
+from icalendar import Calendar, Event, vCalAddress, vText
+
+from la_chariotte.order.models import GroupedOrder
+from la_chariotte.order.views.mixins import UserIsOrgaMixin
+
+from ..forms import LieuForm
+from ..models import Lieu
+
+
+class IndexView(LoginRequiredMixin, generic.ListView):
+ """View showing all the grouped orders managed by the authenticated user"""
+
+ template_name = "lieu/index.html"
+ context_object_name = "lieu_context"
+
+ def get_queryset(self):
+ lieux = Lieu.objects.filter(orga=self.request.user)
+ commandes_par_lieu = dict()
+ for lieu in lieux:
+ orders = GroupedOrder.objects.all().filter(placekey=lieu)
+ if orders:
+ commandes_par_lieu[lieu.url] = orders
+
+ return {
+ "lieu_liste": lieux,
+ "commandes": commandes_par_lieu,
+ }
+
+
+class LieuDetailView(generic.DetailView):
+ model = Lieu
+ template_name = "lieu/lieu_detail.html"
+ context_object_name = "lieu_context"
+ form_class = LieuForm
+
+ def get_object(self, queryset=None):
+ return get_object_or_404(Lieu, url=self.kwargs.get("url"))
+
+ def get_context_data(self, **kwargs):
+ lieu = self.get_object()
+
+ context = super().get_context_data(**kwargs)
+ return context
+
+
+class LieuUpdateView(UserIsOrgaMixin, generic.UpdateView):
+ model = Lieu
+ template_name = "lieu/lieu_update.html"
+ context_object_name = "lieu"
+ form_class = LieuForm
+ # Can't change URL after creation
+ form_class.base_fields["url"].disabled = True
+
+ def get_object(self, queryset=None):
+ return get_object_or_404(Lieu, url=self.kwargs.get("url"))
+
+ def get_form_kwargs(self):
+ kwargs = super().get_form_kwargs()
+ kwargs["user"] = self.request.user
+
+ return kwargs
+
+
+class LieuCreateView(LoginRequiredMixin, generic.CreateView):
+ model = Lieu
+ form_class = LieuForm
+ template_name = "lieu/lieu_create.html"
+
+ def get_form_kwargs(self):
+ kwargs = super().get_form_kwargs()
+ kwargs["user"] = self.request.user
+ return kwargs
+
+ def form_valid(self, form):
+ self.object = form.save()
+ return super().form_valid(form)
diff --git a/la_chariotte/order/forms.py b/la_chariotte/order/forms.py
index 2cf2817..2b4335d 100644
--- a/la_chariotte/order/forms.py
+++ b/la_chariotte/order/forms.py
@@ -1,10 +1,12 @@
import datetime
from django import forms
+from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.auth import get_user_model
from django.forms.utils import to_current_timezone
from django.utils import timezone
+from la_chariotte.lieu.models import Lieu
from la_chariotte.order.models import GroupedOrder, Item
@@ -22,6 +24,12 @@ class GroupedOrderForm(forms.ModelForm):
label="Numéro de téléphone obligatoire pour les participants",
required=False,
)
+ placekey = forms.ModelMultipleChoiceField(
+ label="Lieux de distribution",
+ queryset=Lieu.objects.all(),
+ widget=forms.CheckboxSelectMultiple,
+ required=False,
+ )
class Meta:
model = GroupedOrder
@@ -34,6 +42,7 @@ class GroupedOrderForm(forms.ModelForm):
"place",
"description",
"is_phone_mandatory",
+ "placekey",
]
widgets = {
"name": forms.TextInput(
diff --git a/la_chariotte/order/migrations/0030_add_lieu.py b/la_chariotte/order/migrations/0030_add_lieu.py
new file mode 100644
index 0000000..7464e5b
--- /dev/null
+++ b/la_chariotte/order/migrations/0030_add_lieu.py
@@ -0,0 +1,23 @@
+from django.db import migrations, models
+
+class Migration(migrations.Migration):
+ dependencies = [
+ ("order", "0029_set_phone_mandatory_for_existing_orders"),
+ ("lieu", "0001_initial"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="groupedorder",
+ name="placekey",
+ field=models.ManyToManyField(
+ verbose_name="Lieu de distribution",
+ to="lieu.lieu",
+ ),
+ ),
+ migrations.AddField(
+ model_name="order",
+ name="placekey",
+ field=models.ForeignKey(blank=True, null=True, on_delete=models.deletion.CASCADE, to='lieu.lieu'),
+ ),
+ ]
diff --git a/la_chariotte/order/models.py b/la_chariotte/order/models.py
index 5450f72..03d060c 100644
--- a/la_chariotte/order/models.py
+++ b/la_chariotte/order/models.py
@@ -21,9 +21,17 @@ class GroupedOrder(models.Model):
max_length=50, null=True, blank=True, verbose_name="Créneau de distribution"
)
deadline = models.DateTimeField("Date limite de commande")
+
+ # Try to associate with a saved distribution place in DB
+ placekey = models.ManyToManyField(
+ "lieu.Lieu",
+ verbose_name="Lieu de distribution",
+ )
+ # Alternatively, propose a free-text distribution place field
place = models.CharField(
max_length=100, null=True, blank=True, verbose_name="Lieu de livraison"
)
+
description = models.TextField("Description", null=True, blank=True)
code = models.CharField(auto_created=True)
is_phone_mandatory = models.BooleanField(
@@ -123,6 +131,9 @@ class Order(models.Model):
author = models.ForeignKey(OrderAuthor, on_delete=models.CASCADE)
created_date = models.DateTimeField("Date et heure de commande", auto_now_add=True)
note = models.TextField(max_length=200, null=True, blank=True)
+ placekey = models.ForeignKey(
+ "lieu.lieu", on_delete=models.CASCADE, null=True, blank=True
+ )
@property
def articles_nb(self):
diff --git a/la_chariotte/order/templates/order/grouped_order_detail.html b/la_chariotte/order/templates/order/grouped_order_detail.html
index b73d467..96fb8fa 100644
--- a/la_chariotte/order/templates/order/grouped_order_detail.html
+++ b/la_chariotte/order/templates/order/grouped_order_detail.html
@@ -171,6 +171,17 @@
+ {% if placekey %}
+
+
+ {% endif %}
+
+
+