Commit cd2cb866 authored by HEVELINE Thomas's avatar HEVELINE Thomas Committed by HEVELINE Thomas

(44): delivery refactor

parent 107327be
This diff is collapsed.
...@@ -11,103 +11,104 @@ ...@@ -11,103 +11,104 @@
{% endblock %} {% endblock %}
{% block main %} {% block main %}
<h1>Livraison</h1> <div class="delivery">
<script> <h1>Livraison</h1>
var url = new URL(window.location.href); <script>
console.log(url.searchParams) var url = new URL(window.location.href);
function applyFilter() { function applyFilter() {
url.searchParams.set('delivered', document.getElementById('delivered').checked); url.searchParams.set('delivered', document.getElementById('delivered').checked);
url.searchParams.set('delivery_in_progress', document.getElementById('delivery_in_progress').checked); url.searchParams.set('delivery_in_progress', document.getElementById('delivery_in_progress').checked);
window.location.href = url window.location.href = url
} }
</script> </script>
<form onchange="generateTable()"> <form onchange="generateTable()">
<label for="delivered">Déjà remis</label> <label for="delivered">Déjà remis :</label>
<select id="delivered" <select id="delivered"
onchange="generateTable()"> onchange="generateTable()">
<option value="both">Tous</option> <option value="both">Tous</option>
<option value="true">Oui</option> <option value="true">Oui</option>
<option value="false">Non</option> <option value="false">Non</option>
</select> </select>
<label for="beeing_delivered">Distribution en cours</label> <label for="beeing_delivered">Distribution en cours :</label>
<select id="beeing_delivered" <select id="beeing_delivered"
onchange="generateTable()"> onchange="generateTable()">
<option value="true">Oui</option> <option value="true">Oui</option>
<option value="false">Non</option> <option value="false">Non</option>
<option value="both">Tous</option> <option value="both">Tous</option>
</select> </select>
<label for="hidden">Produits cachés</label> <label for="hidden">Produits cachés :</label>
<select id="hidden" <select id="hidden"
onchange="generateTable()"> onchange="generateTable()">
<option value="true">Oui</option> <option value="true">Oui</option>
<option value="false">Non</option> <option selected value="false">Non</option>
<option value="both">Tous</option> <option value="both">Tous</option>
</select> </select>
<label for="paid">Payé</label> <label for="paid">Payé :</label>
<select id="paid" <select id="paid"
onchange="generateTable()"> onchange="generateTable()">
<option value="true">Oui</option> <option value="true">Oui</option>
<option value="false">Non</option> <option value="false">Non</option>
<option value="both">Tous</option> <option value="both">Tous</option>
</select> </select>
<label for="sort">Tri</label> <label for="sort">Tri :</label>
<select id="sort"> <select id="sort">
<option value="true"> --</option> <option value="none"> --</option>
<option value="false">Personalisation</option> <option value="false">Personalisation</option>
<option value="both">Acheteur</option> <option value="both">Acheteur</option>
<option value="both">Date de commande</option> <option value="date">Date de commande</option>
<option value="both">Option 1</option> <option value="option">Option 1</option>
<option value="both">Option 2</option> <option value="second_option">Option 2</option>
</select> </select>
</form> </form>
<form onblur="generateTable()" <form onblur="generateTable()"
onkeypress="onEnter(event)"> onkeypress="onEnter(event)">
<input placeholder="Produit"
<input placeholder="Email" type="search"
type="search" id="productContains">
id="emailContains"> <input placeholder="Email"
<input placeholder="Produit" type="search"
type="search" id="emailContains">
id="productContains">
<input placeholder="Option (valeur exacte)" <input placeholder="Option (valeur exacte)"
type="search" type="search"
id="optionContains"> id="optionContains">
<input placeholder="Personalisation" <input placeholder="Personalisation"
type="search" type="search"
id="customizationContains"> id="customizationContains">
</form> </form>
<div id="deliveries"></div> <div id="deliveries"></div>
<script> <script>
window.addEventListener('load', generateTable); window.addEventListener('load', generateTable);
function onEnter(event) { function onEnter(event) {
if (event.keyCode === 13) { if (event.keyCode === 13) {
blur(event.target) blur(event.target)
generateTable() generateTable()
}
}
function generateTable() {
var params = new URLSearchParams();
params.set('delivered', document.getElementById('delivered').value);
params.set('beeing_delivered', document.getElementById('beeing_delivered').value);
params.set('hidden', document.getElementById('hidden').value);
params.set('paid', document.getElementById('paid').value);
params.set('customizationContains', document.getElementById('customizationContains').value);
params.set('optionContains', document.getElementById('optionContains').value);
params.set('productContains', document.getElementById('productContains').value);
params.set('emailContains', document.getElementById('emailContains').value);
var orderedItemList = new OrderedItemList('deliveries', '/boutique/delivery?' + params.toString());
} }
} </script>
function generateTable() {
var params = new URLSearchParams();
params.set('delivered', document.getElementById('delivered').value);
params.set('beeing_delivered', document.getElementById('beeing_delivered').value);
params.set('hidden', document.getElementById('hidden').value);
params.set('paid', document.getElementById('paid').value);
params.set('customizationContains', document.getElementById('customizationContains').value);
params.set('optionContains', document.getElementById('optionContains').value);
params.set('productContains', document.getElementById('productContains').value);
params.set('emailContains', document.getElementById('emailContains').value);
var orderedItemList = new OrderedItemList('deliveries', '/boutique/delivery?' + params.toString());
}
</script>
</div>
{% endblock %} {% endblock %}
......
...@@ -15,35 +15,66 @@ ...@@ -15,35 +15,66 @@
{% block main %} {% block main %}
<h1>Gestion des Produits</h1> <h1>Gestion des Produits</h1>
<a href="{% url 'boutique:item_create' %}"><button>Ajouter un produit</button></a> <a href="{% url 'boutique:item_create' %}">
<a href="{% url 'boutique:delivery' %}" ><button>Livraison</button></a> <button>Ajouter un produit</button>
<a href="{% url 'boutique:item_sell' %}"><button>Vente pour autrui</button></a> </a>
<a href="{% url 'boutique:manage_category' %}"><button>Ajouter une catégorie</button></a> <a href="{% url 'boutique:delivery' %}">
<button>Distribution</button>
</a>
<a href="{% url 'boutique:item_sell' %}">
<button>Vente en directe</button>
</a>
<a href="{% url 'boutique:manage_category' %}">
<button>Ajouter une catégorie</button>
</a>
<br/> <br/>
<section class="item-manage-list"> <section class="item-manage-list">
{% for item in object_list %} {% for item in object_list %}
{% if item.hidden %} <article data-id="{{ item.id }}"
<article data-id="{{ item.id }}" class="hidden"> data-pk="{{ item.pk }}"
{% else %} data-customization="{{ item.customization }}"
<article data-id="{{ item.id }}"> data-optionLabel="{{ item.option_label }}"
{% endif %} data-optionChoices="{{ item.option }}"
<img class="image" src="{{ item.get_image_url }}" alt=""> data-secondOptionLabel="{{ item.second_option_label }}"
<h2>{{ item.name }}</h2> data-secondOptionChoices="{{ item.second_option }}"
<p class="numcommands">{{ item.order_items.count }} commandes</p> data-customizable="{{ item.customizable }}"
<div> data-special="{{ item.special }}"
<a href="{% url 'boutique:item_edit' pk=item.pk %}" class="delivery_list button tooltip"> {% if item.hidden %}
<i class="fas fa-edit"><span class="tooltiptext">Modifier</span></i> class="hidden"
</a> {% endif %}
<button class="delivery_list tooltip begin-delivery"><i class="fas fa-paper-plane"></i> <span >
class="tooltiptext">Commencer la livraison</span>
</button> <img class="image" src="{{ item.get_image_url }}" alt="">
<button class="delivery_list tooltip see-orders"><i class="fas fa-eye"></i> <span class="tooltiptext">Voir les commandes</span> <h2>{{ item.name }}</h2>
</button> <p class="numcommands">Total commandé: {{ item.total_quantity }} </p>
<button class="delivery_list tooltip dl-orders" onclick="window.location.href = '{% url 'boutique:csvexport' pk=item.id %}'"><i class="fas fa-download"></i> <span class="tooltiptext">Voir les commandes</span> <p class="numcommands">[{{ item.quantity_delivered }}/{{ item.quantity_to_deliver }} distribué(s)]</p>
</button>
</div> <div>
<a href="{% url 'boutique:item_edit' pk=item.pk %}" class="delivery_list button tooltip">
</article> <i class="fas fa-edit"><span class="tooltiptext">Modifier</span></i>
</a>
<button class="delivery_list tooltip begin-delivery"><i class="fas fa-paper-plane"></i> <span
class="tooltiptext">Commencer la distribution des articles commandés</span>
</button>
<button class="delivery_list tooltip stop-delivery"><i class="fas fa-ban"></i> <span
class="tooltiptext">Arrêter la distribution des articles</span>
</button>
<button class="delivery_list tooltip see-orders"><i class="fas fa-eye"></i> <span
class="tooltiptext">Voir les commandes</span>
</button>
<button class="delivery_list tooltip dl-orders"
onclick="window.location.href = '{% url 'boutique:csvexport' pk=item.id %}'"><i
class="fas fa-download"></i> <span class="tooltiptext">Exporter les commandes</span>
</button>
{% if perms.boutique.sell %}
<button class="delivery_list tooltip" onclick="sell(event)"><i class="fas fa-hand-holding-usd"></i> <span
class="tooltiptext">Vente en direct</span>
</button>
{% endif %}
</div>
</article>
{% endfor %} {% endfor %}
</section> </section>
...@@ -52,5 +83,6 @@ ...@@ -52,5 +83,6 @@
{% block scripts %} {% block scripts %}
<script src="{% static 'js/json_request.js' %}"></script> <script src="{% static 'js/json_request.js' %}"></script>
<script src="{% static 'js/popup.js' %}"></script> <script src="{% static 'js/popup.js' %}"></script>
<script src="{% static 'js/table_list.js' %}"></script>
<script src="{% static 'boutique/js/item_manage.js' %}"></script> <script src="{% static 'boutique/js/item_manage.js' %}"></script>
{% endblock %} {% endblock %}
...@@ -12,9 +12,11 @@ from django.contrib.auth.models import AnonymousUser ...@@ -12,9 +12,11 @@ from django.contrib.auth.models import AnonymousUser
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import F from django.db.models import F, Value
from django.db.models import Q from django.db.models import Q
from django.db.models import QuerySet from django.db.models import QuerySet
from django.db.models.aggregates import Sum
from django.db.models.functions import Coalesce
from django.forms import BaseForm from django.forms import BaseForm
from django.forms import BaseInlineFormSet from django.forms import BaseInlineFormSet
from django.forms import BaseModelForm from django.forms import BaseModelForm
...@@ -210,7 +212,7 @@ class ItemManageView(PermissionRequiredMixin, ListView): ...@@ -210,7 +212,7 @@ class ItemManageView(PermissionRequiredMixin, ListView):
template_name = "boutique/item_manage.html" template_name = "boutique/item_manage.html"
permission_required = "boutique.management" permission_required = "boutique.management"
def post(self, request: HttpRequest, *args, **kwargs) -> JsonResponse: def options(self, request: HttpRequest, *args, **kwargs) -> JsonResponse:
req = json.loads(request.read().decode()) req = json.loads(request.read().decode())
pk = req.get("id") pk = req.get("id")
...@@ -221,8 +223,12 @@ class ItemManageView(PermissionRequiredMixin, ListView): ...@@ -221,8 +223,12 @@ class ItemManageView(PermissionRequiredMixin, ListView):
message = req.get("message") message = req.get("message")
if message == "begin-delivery": if message == "begin-delivery":
item_qs.get().order_items.update(beeing_delivered=True) item_qs.get().order_items.filter(order__payment__paid=True).update(beeing_delivered=True)
return JsonResponse({"status": "success", "data": "Bien reçu"}) return JsonResponse({"status": "success", "data": "Début des livraisons des articles déjà commandé"})
if message == "stop-delivery":
item_qs.get().order_items.update(beeing_delivered=False)
return JsonResponse({"status": "success", "data": "Arrêt des livraisons des articles"})
elif message == "see-orders": elif message == "see-orders":
item = item_qs.prefetch_related( item = item_qs.prefetch_related(
...@@ -233,15 +239,22 @@ class ItemManageView(PermissionRequiredMixin, ListView): ...@@ -233,15 +239,22 @@ class ItemManageView(PermissionRequiredMixin, ListView):
"status": "success", "status": "success",
"data": [ "data": [
{ {
"user": str(oi.order.user.profile),
"display_name": str(oi.order.user.profile),
"email": str(oi.order.user.email),
"quantity": oi.quantity, "quantity": oi.quantity,
"paid": oi.order.paid, "quantity_delivered": oi.quantity_delivered,
"customization": oi.customization, "option_label": oi.item.option_label,
"option": oi.option, "option": oi.option,
"second_option_label": oi.item.second_option_label,
"second_option": oi.second_option, "second_option": oi.second_option,
"quantity_delivered": oi.quantity_delivered, "customization": oi.customization,
"paid": oi.order.paid,
"ordered_date": oi.order.ordered_date,
"mean": oi.order.mean,
} }
for oi in item.order_items.all() for oi in item.order_items.all().order_by("-order__ordered_date")
], ],
} }
) )
...@@ -249,7 +262,13 @@ class ItemManageView(PermissionRequiredMixin, ListView): ...@@ -249,7 +262,13 @@ class ItemManageView(PermissionRequiredMixin, ListView):
raise SuspiciousOperation() raise SuspiciousOperation()
def get_queryset(self) -> "QuerySet[Item]": def get_queryset(self) -> "QuerySet[Item]":
return Item.objects.order_by("hidden").prefetch_related("order_items") return Item.objects.annotate(
total_quantity=Coalesce(Sum('order_items__quantity', filter=Q(order_items__order__payment__paid=True)),
Value(0)),
quantity_delivered=Coalesce(Sum('order_items__quantity_delivered'), Value(0)),
quantity_to_deliver=Coalesce(Sum('order_items__quantity', filter=Q(order_items__beeing_delivered=True)),
Value(0))) \
.order_by("hidden").prefetch_related("order_items")
class ItemSellView(PermissionRequiredMixin, CreateView): class ItemSellView(PermissionRequiredMixin, CreateView):
...@@ -511,7 +530,8 @@ class DeliveryView(PermissionRequiredMixin, ListView): ...@@ -511,7 +530,8 @@ class DeliveryView(PermissionRequiredMixin, ListView):
).select_related("order__user__profile", "order__user", "item") ).select_related("order__user__profile", "order__user", "item")
def boolQueryParam(self, param): def boolQueryParam(self, param):
if param == 'true': return True if param == 'true':
return True
if param == 'false': if param == 'false':
return False return False
else: else:
...@@ -531,6 +551,10 @@ class DeliveryView(PermissionRequiredMixin, ListView): ...@@ -531,6 +551,10 @@ class DeliveryView(PermissionRequiredMixin, ListView):
if beeing_delivered is not None: if beeing_delivered is not None:
itemList = itemList.filter(beeing_delivered=beeing_delivered) itemList = itemList.filter(beeing_delivered=beeing_delivered)
hidden = self.boolQueryParam(request.GET["hidden"])
if hidden is not None:
itemList = itemList.filter(item__hidden=hidden)
paid = self.boolQueryParam(request.GET["paid"]) paid = self.boolQueryParam(request.GET["paid"])
if paid is True: if paid is True:
itemList = itemList.filter(order__payment__paid=True) itemList = itemList.filter(order__payment__paid=True)
...@@ -538,8 +562,8 @@ class DeliveryView(PermissionRequiredMixin, ListView): ...@@ -538,8 +562,8 @@ class DeliveryView(PermissionRequiredMixin, ListView):
itemList = itemList.filter(Q(order__payment__isnull=True) | Q(order__payment__paid=False)) itemList = itemList.filter(Q(order__payment__isnull=True) | Q(order__payment__paid=False))
itemList = itemList.filter(Q(item__name__icontains=request.GET["productContains"]) itemList = itemList.filter(Q(item__name__icontains=request.GET["productContains"])
& Q(customization__icontains=request.GET["customizationContains"]) & Q(customization__icontains=request.GET["customizationContains"])
& Q(order__user__email__icontains=request.GET["emailContains"])) & Q(order__user__email__icontains=request.GET["emailContains"]))
optionContains = request.GET["optionContains"] optionContains = request.GET["optionContains"]
if optionContains != "": if optionContains != "":
...@@ -548,7 +572,7 @@ class DeliveryView(PermissionRequiredMixin, ListView): ...@@ -548,7 +572,7 @@ class DeliveryView(PermissionRequiredMixin, ListView):
orderedItems = [ orderedItems = [
{"id": orderItem.id, {"id": orderItem.id,
"item": str(orderItem.item), "item": str(orderItem.item),
"image": str(orderItem.item.image), "image": orderItem.item.get_image_url(),
"display_name": str(orderItem.order.user.profile), "display_name": str(orderItem.order.user.profile),
"email": str(orderItem.order.user.email), "email": str(orderItem.order.user.email),
"quantity": orderItem.quantity, "quantity": orderItem.quantity,
......
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
<section id="main_container"> <section id="main_container">
<div id='messages'></div> <div id='messages'></div>
{% block messages %} {% endblock messages %} {% block messages %} {% endblock messages %}
{% if request.user.is_active and not request.user.profile.is_valid %} {% if request.user.is_active and not request.user.profile.is_valid %}
<script> <script>
add_message("error", "Veuillez remplir les informations de votre profil svp. (Nom, prénom et/ou surnom)", 0); add_message("error", "Veuillez remplir les informations de votre profil svp. (Nom, prénom et/ou surnom)", 0);
......
This diff is collapsed.
This diff is collapsed.
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
var pictureContainer = document.createElement('div'); var pictureContainer = document.createElement('div');
pictureContainer.setAttribute('class', 'picture_container'); pictureContainer.setAttribute('class', 'picture_container');
pictureContainer.appendChild(document.createElement('img')) pictureContainer.appendChild(document.createElement('img'))
.setAttribute('src', '/medias/' + item['image']); .setAttribute('src', item['image']);
var actionContainer = document.createElement('div'); var actionContainer = document.createElement('div');
actionContainer.setAttribute('class', 'action_container'); actionContainer.setAttribute('class', 'action_container');
......
...@@ -123,6 +123,7 @@ function DeliverPopup(item, callback) { ...@@ -123,6 +123,7 @@ function DeliverPopup(item, callback) {
quantityInput.setAttribute('style', 'font-size: larger'); quantityInput.setAttribute('style', 'font-size: larger');
quantityInput.addEventListener('change', is_valid) quantityInput.addEventListener('change', is_valid)
quantityInput = body.appendChild(quantityInput); quantityInput = body.appendChild(quantityInput);
this.main.appendChild(body); this.main.appendChild(body);
let button = document.createElement('button'); let button = document.createElement('button');
...@@ -169,7 +170,7 @@ DeliverPopup.prototype.constructor = DeliverPopup; ...@@ -169,7 +170,7 @@ DeliverPopup.prototype.constructor = DeliverPopup;
function CustomizationPopup(title, item, callback) { function CustomizationPopup(title, item, callback) {
Popup.call(this, title); Popup.call(this, title);
this.baseClass = 'selection_popup'; this.baseClass = 'customization_popup';
this.callback = callback; this.callback = callback;
let button = document.createElement('button'); let button = document.createElement('button');
......
...@@ -111,11 +111,33 @@ ...@@ -111,11 +111,33 @@
color: $orange color: $orange
align-content: center align-content: center
padding: 8px padding: 8px
margin: 0 5px margin: 5px
&:hover &:hover
background-color: $orange background-color: $orange
.delivery
form
align-items: center
display: flex
flex-wrap: wrap
flex-direction: row
margin-bottom: 5px
label
margin-right: 5px
select
margin-right: 15px
input
width: 24%
margin-right: 1%
&:last-child
marginright: 0
.basket_table .basket_table
display: block display: block
...@@ -218,10 +240,7 @@ ...@@ -218,10 +240,7 @@
@supports (grid-template-columns: subgrid) @supports (grid-template-columns: subgrid)
grid-template-columns: subgrid grid-template-columns: subgrid
align-items: center align-items: center
border-bottom: solid 1px transparent
&:hover, &:focus-within
border-bottom-color: black
@media screen and (max-width: $mobile-view_treshold) @media screen and (max-width: $mobile-view_treshold)
grid-row: 1/-1 grid-row: 1/-1
......
...@@ -15,7 +15,11 @@ button, .button ...@@ -15,7 +15,11 @@ button, .button
margin: 5px 2px margin: 5px 2px
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1) box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1)
min-height: 40px !important min-height: 40px !important
border-radius: 20px
&:disabled
background: #ddd !important
pointer-events: none
cursor: not-allowed
i i
......
@keyframes slideDown
from
height: 0
to
height: auto
#messages
position: sticky
top: 0
z-index: 2
height: auto
@media screen and (max-width: $mobile_view_treshold)
#messages
top: 70px
.message .message
padding: 1em 2em padding: 1em 2em
font-weight: bold font-weight: bold
color: white color: white
animation-delay: 0.2s
animation-timing-function: ease-out
animation-duration: 5s