possibilité de commander 1 produit

This commit is contained in:
Laetitia Getti 2023-03-17 16:04:09 +01:00
parent 2610e6fe2e
commit 1c4ea1a3fa
20 changed files with 521 additions and 4 deletions

View file

View file

@ -0,0 +1,7 @@
from django.contrib import admin
from .models import Grouped_order, Order, Item
admin.site.register(Grouped_order)
admin.site.register(Order)
admin.site.register(Item)

View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class OrderConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'la_chariotte.order'

View file

@ -0,0 +1,31 @@
# Generated by Django 4.1.7 on 2023-03-14 15:33
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Grouped_order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('orga', models.CharField(max_length=100)),
('date', models.DateField(verbose_name='Date de livraison')),
],
),
migrations.CreateModel(
name='Order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('author', models.CharField(max_length=100, verbose_name='Personne qui passe la commande')),
('grouped_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='order.grouped_order')),
],
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.1.7 on 2023-03-14 16:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('order', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='grouped_order',
name='name',
field=models.CharField(max_length=100, null=True),
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 4.1.7 on 2023-03-15 15:24
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('order', '0002_grouped_order_name'),
]
operations = [
migrations.CreateModel(
name='Item',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('grouped_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='order.grouped_order')),
],
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.1.7 on 2023-03-15 16:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('order', '0003_item'),
]
operations = [
migrations.AddField(
model_name='item',
name='ordered_nb',
field=models.IntegerField(default=0),
),
]

View file

@ -0,0 +1,32 @@
# Generated by Django 4.1.7 on 2023-03-17 14:25
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('order', '0004_item_ordered_nb'),
]
operations = [
migrations.RemoveField(
model_name='item',
name='ordered_nb',
),
migrations.AlterField(
model_name='order',
name='grouped_order',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='order_set', to='order.grouped_order'),
),
migrations.CreateModel(
name='OrderedItem',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nb', models.PositiveSmallIntegerField(default=0)),
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ordered_items', to='order.item')),
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='order.order')),
],
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.1.7 on 2023-03-17 14:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('order', '0005_remove_item_ordered_nb_alter_order_grouped_order_and_more'),
]
operations = [
migrations.AddField(
model_name='item',
name='ordered_nb',
field=models.IntegerField(default=0),
),
]

View file

@ -0,0 +1,28 @@
from django.db import models
class Grouped_order(models.Model):
name = models.CharField(max_length=100, null=True) # optionnal
orga = models.CharField(max_length=100) # a changer, utiliser ForeignKey de user
date = models.DateField('Date de livraison')
def __str__(self):
return self.name if self.name else f"Commande groupée {self.pk} du {self.date} organisée par {self.orga}"
class Order(models.Model):
grouped_order = models.ForeignKey(Grouped_order, on_delete=models.CASCADE,related_name="order_set")
author = models.CharField(max_length=100, verbose_name='Personne qui passe la commande') # a changer, utiliser ForeignKey de user
def __str__(self):
return f"Commande de {self.author} pour la commande groupée {self.grouped_order.pk}"
class Item(models.Model):
name = models.CharField(max_length=100)
grouped_order = models.ForeignKey(Grouped_order, on_delete=models.CASCADE) # à transformer en manytomany quand il y aura un catalogue
ordered_nb = models.IntegerField(default=0)
def __str__(self):
return f"{self.name} dans la commande groupée {self.grouped_order.pk}"
class OrderedItem(models.Model):
"""Item in one specific Order, and its number"""
nb = models.PositiveSmallIntegerField(default=0) # works up to 32767
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="ordered_items")
item = models.ForeignKey(Item, on_delete=models.CASCADE, related_name="orders")

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Commandes groupées {{ grouped_order.id }}</title>
</head>
<body>
<p>Détail de la commande groupée {{ grouped_order.id }}, avec la liste des produits associés</p>
<br>
<p>{{ grouped_order }}
<p>Organisateur·ice : {{ grouped_order.orga }}</p>
<p>Date de livraison : {{ grouped_order.date }}</p>
les produits disponibles pour cette commande groupée :
<ul>
{% for item in grouped_order.item_set.all %}
<li>
{{ item }}
</li>
{% endfor %}
</ul>
<form action="{% url 'order:order' grouped_order.id %}" method="post">
{% csrf_token %}
<fieldset>
<legend><h1>{{ grouped_order }}</h1></legend>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% for item in grouped_order.item_set.all %}
<input type="radio" name="item" id="item{{ forloop.counter }}" value="{{ item.id }}">
<label for="item{{ forloop.counter }}">{{ item.name }}</label><br>
{% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>
</body>
</html>

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Commandes groupées {{ grouped_order.id }}</title>
</head>
<body>
<p>Vue d'organisation de la commande groupée {{ grouped_order.id }}, avec les produits commandés et les commandes individuelles</p>
<br>
<p>{{ grouped_order }}
<p>Organisateur·ice : {{ grouped_order.orga }}</p>
<p>Date de livraison : {{ grouped_order.date }}</p>
les produits commandés pour cette commande groupée :
<ul>
{% for item in grouped_order.item_set.all %}
<li>
{{ item }}, avec {{ item.ordered_nb }} commande{{ item.ordered_nb|pluralize }}
</li>
{% endfor %}
</ul>
les commandes passées pour cette commande groupée :
<ul>
{% for order in grouped_order.order_set.all %}
<li>
{{ order }} : {{ order.ordered_items.count }} produits commandés
</li>
{% endfor %}
</ul>
<a href={% url 'order:order' grouped_order.id %}>Retour à la page de commande</a>
</body>
</html>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<title>Commandes groupées - index</title>
</head>
<body>
<p>Index des commandes que l'utilisateur·ice connecté·e organise</p>
<p>Pour l'instant, index de toutes les commandes groupées qui existent</p>
{% if grouped_order_list %}
<ul>
{% for gr_order in grouped_order_list %}
<li>
<a href="{% url 'order:grouped_order_detail' gr_order.id %}"
>Commande groupée {{ gr_order.id }} organisée par {{ gr_order.orga }}</a
>
</li>
{% endfor %}
</ul>
{% else %}
<p>Pas de commande groupée pour l'instant</p>
{% endif %}
</body>
</html>

View file

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

View file

@ -0,0 +1,11 @@
from django.urls import path
from . import views
app_name = 'order'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.GroupedOrderDetailView.as_view(), name='grouped_order_detail'),
path('<int:pk>/orga', views.GroupedOrderOrgaView.as_view(), name='grouped_order_orga'),
path('<int:grouped_order_id>/commander/', views.order, name='order'),
]

View file

@ -0,0 +1,56 @@
from django.shortcuts import render, get_object_or_404, get_list_or_404
from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from .models import Grouped_order, Item, Order, OrderedItem
class IndexView(generic.ListView):
"""Vue de toutes les commandes groupées existantes - plus tard, de toutes les commandes groupées de l'utilisateur connecté"""
template_name = 'order/index.html'
context_object_name = 'grouped_order_list'
def get_queryset(self):
"""Return some 10 grouped orders.""" # changer envoyer les plus proches d'aujourd'hui dans le futur
return Grouped_order.objects.order_by('-date')[:10]
class GroupedOrderDetailView(generic.DetailView):
"""Vue de détail d'une commande groupée - possibilité de commander si elle est en cours"""
model = Grouped_order
template_name = 'order/grouped_order_detail.html'
class GroupedOrderOrgaView(generic.DetailView):
"""Vue de supervision d'une commande groupée"""
model = Grouped_order
template_name = 'order/grouped_order_orga.html'
def order(request, grouped_order_id): # crée une commande (order) pour cette commande groupée, avec l'item selectionné dedans
grouped_order = get_object_or_404(Grouped_order, pk=grouped_order_id)
try:
selected_item = grouped_order.item_set.get(pk=request.POST['item'])
except (KeyError, Item.DoesNotExist):
# Redisplay the order form for this grouped order.
return render(request, 'order/grouped_order_detail.html', {
'grouped_order': grouped_order,
'error_message': "You didn't select an item.",
})
else:
order = Order.objects.create(author="Auteur teur",grouped_order=grouped_order)
OrderedItem.objects.create(nb=1,order=order,item=selected_item)
compute_ordered_nb(selected_item)
# Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a
# user hits the Back button.
return HttpResponseRedirect(reverse('order:grouped_order_orga', args=(grouped_order.pk,)))
def compute_ordered_nb(item):
"""Calcule le nombre de produits de ce produit commandés (pour cette commande groupée)"""
ordered_nb = 0
for order in item.orders.all():
ordered_nb += order.nb
item.ordered_nb = ordered_nb
item.save()

166
la_chariotte/readMe.md Normal file
View file

@ -0,0 +1,166 @@
Exemple de MCD en markdown avec mermaid :
```mermaid
erDiagram
CourseSubmission{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField title
DateField date
FSMField state
}
CourseSubmissionProduct{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
PositiveSmallIntegerField quantity
}
Pricing{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField name
}
Product{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField name
CharField code
BooleanField submission_enabled
}
ProductPrice{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
PositiveSmallIntegerField year
CharField price_type
DecimalField price_flat
PositiveSmallIntegerField price_percent
DecimalField price_percent_minimum
CharField unit
}
ProductPriceRange{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
PositiveSmallIntegerField range_start
PositiveSmallIntegerField range_end
DecimalField unit_price
DecimalField minimum
}
ProductPricePackLine_included_products{
AutoField id
}
ProductPricePackLine{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField quantity_type
PositiveSmallIntegerField quantity
}
Contract{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
DateField start
DateField end
FileField file
}
Transaction_products{
AutoField id
}
Transaction{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
PositiveIntegerField debit
PositiveIntegerField credit
BooleanField unlimited_credit
}
Quote{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField external_ref
FSMField state
}
QuoteLine{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
TextField label
DecimalField unit_price
DecimalField quantity
}
Invoice{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField external_ref
FSMField state
}
InvoiceLine{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
TextField label
DecimalField unit_price
DecimalField quantity
}
User{
CharField password
DateTimeField last_login
BooleanField is_superuser
CharField username
CharField first_name
CharField last_name
EmailField email
BooleanField is_staff
BooleanField is_active
DateTimeField date_joined
UUIDField id
DateTimeField created_on
DateTimeField updated_on
ManyToManyField groups
ManyToManyField user_permissions
}
Organization{
UUIDField id
DateTimeField created_on
DateTimeField updated_on
CharField code
CharField representative
FileField signature
FileField logo
}
CourseSubmission||--|{User : user
CourseSubmission||--|{Organization : organization
CourseSubmissionProduct||--|{CourseSubmission : course_submission
CourseSubmissionProduct||--|{Product : product
ProductPrice||--|{Pricing : pricing
ProductPrice||--|{Product : product
ProductPriceRange||--|{ProductPrice : product_price
ProductPricePackLine_included_products||--|{ProductPricePackLine : productpricepackline
ProductPricePackLine_included_products||--|{Product : product
ProductPricePackLine||--|{ProductPrice : product_price
ProductPricePackLine}|--|{Product : included_products
Contract||--|{Organization : organization
Contract||--|{Pricing : pricing
Transaction_products||--|{Transaction : transaction
Transaction_products||--|{Product : product
Transaction||--|{Invoice : invoice
Transaction||--|{CourseSubmission : course_submission
Transaction}|--|{Product : products
Quote||--|{Organization : organization
QuoteLine||--|{Quote : quote
QuoteLine||--|{Product : product
Invoice||--|{Organization : organization
InvoiceLine||--|{Invoice : invoice
InvoiceLine||--|{Product : product
Organization||--|{User : representative_user
Organization||--|{Organization : parent
```

View file

@ -31,6 +31,7 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'la_chariotte.order',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@ -75,8 +76,12 @@ WSGI_APPLICATION = 'la_chariotte.wsgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'chariotte-db',
'USER': 'laetitia',
'PASSWORD': 'toto',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
@ -105,7 +110,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
TIME_ZONE = 'Europe/Paris'
USE_I18N = True

View file

@ -14,8 +14,9 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('commande/', include('la_chariotte.order.urls')),
]