Commit 29515baf authored by HEVELINE Thomas's avatar HEVELINE Thomas Committed by HEVELINE Thomas
Browse files

(44): delivery popup

parent d4a491da
......@@ -72,9 +72,9 @@ class Item(models.Model):
@property
def customizable(self) -> bool:
return (
(self.customization is True)
or (self.option != "")
or (self.second_option != "")
(self.customization is True)
or (self.option != "")
or (self.second_option != "")
)
@property
......@@ -159,12 +159,12 @@ class Item(models.Model):
return static("images/default_product.png")
def add_to_order(
self,
order: "Order",
quantity: int = 1,
customization: str = "",
option: str = "",
second_option: str = "",
self,
order: "Order",
quantity: int = 1,
customization: str = "",
option: str = "",
second_option: str = "",
) -> "OrderItem":
oi, created = None, False
if self.customizable:
......@@ -196,7 +196,7 @@ class Item(models.Model):
if not oi.is_pack_item:
break
if (
oi is None or oi.is_pack_item
oi is None or oi.is_pack_item
): # The preceding queries in the try-except block were empty or they
# ended on a pack_item
oi = OrderItem.objects.create(
......@@ -218,12 +218,12 @@ class Item(models.Model):
return oi
def add_to_user(
self,
user,
quantity: int = 1,
customization: str = "",
option: str = "",
second_option: str = "",
self,
user,
quantity: int = 1,
customization: str = "",
option: str = "",
second_option: str = "",
) -> "OrderItem":
if self.hidden or self.end_date < timezone.now():
raise ValidationError(
......@@ -262,6 +262,13 @@ class Order(models.Model):
except Payment.DoesNotExist:
return False
@property
def mean(self) -> str:
try:
return self.payment.mean
except Payment.DoesNotExist:
return None
@property
def contains_cotiz(self) -> bool:
return any(i.item.is_cotiz for i in self.items.all())
......@@ -315,10 +322,10 @@ class OrderItemManager(models.Manager):
def get_ordered_quantity(self, item: "Item", user) -> int:
"""Get the total quantity ever ordered/in order by that user"""
return (
self.filter(item=item, order__user=user, order__rejected=False).aggregate(
quantity=Sum("quantity")
)["quantity"]
or 0
self.filter(item=item, order__user=user, order__rejected=False).aggregate(
quantity=Sum("quantity")
)["quantity"]
or 0
)
......@@ -446,7 +453,7 @@ class OrderItem(models.Model):
)
def delete(
self, *args, override_pack=False, **kwargs
self, *args, override_pack=False, **kwargs
) -> Tuple[int, Dict[str, int]]:
deleted = 0
which: typing.Counter[str] = Counter()
......@@ -476,7 +483,7 @@ class OrderItem(models.Model):
@receiver(pre_save, sender=OrderItem)
@receiver(pre_delete, sender=OrderItem)
def orderitem_price_computing(
sender: Type[OrderItem], instance: OrderItem, **kwargs
sender: Type[OrderItem], instance: OrderItem, **kwargs
) -> None:
if kwargs.get("raw", False):
return
......@@ -488,9 +495,9 @@ def orderitem_price_computing(
@receiver(pre_delete, sender=OrderItem)
@receiver(pre_delete, sender=Order)
def no_delete_for_ordered(
sender: Union[Type[Order], Type[OrderItem]],
instance: Union[Order, OrderItem],
**kwargs,
sender: Union[Type[Order], Type[OrderItem]],
instance: Union[Order, OrderItem],
**kwargs,
) -> None:
if instance.ordered:
raise ValueError("Deletion of ordered instances is not allowed")
......@@ -498,7 +505,7 @@ def no_delete_for_ordered(
@receiver(pre_save, sender=lydiaRequest)
def mark_payment_as_paid(
sender: Type[lydiaRequest], instance: lydiaRequest, **kwargs
sender: Type[lydiaRequest], instance: lydiaRequest, **kwargs
) -> None:
if kwargs.get("raw", False):
return
......
......@@ -24,41 +24,97 @@
}
</script>
<form>
<form onchange="generateTable()">
<label for="delivered">Déjà remis</label>
<input type="checkbox" id="delivered">
<label for="delivery_in_progress">Distribution en cours</label>
<input type="checkbox" id="delivery_in_progress">
<select id="delivered"
onchange="generateTable()">
<option value="both">Tous</option>
<option value="true">Oui</option>
<option value="false">Non</option>
</select>
<label for="beeing_delivered">Distribution en cours</label>
<select id="beeing_delivered"
onchange="generateTable()">
<option value="true">Oui</option>
<option value="false">Non</option>
<option value="both">Tous</option>
</select>
<label for="hidden">Produits cachés</label>
<select id="hidden"
onchange="generateTable()">
<option value="true">Oui</option>
<option value="false">Non</option>
<option value="both">Tous</option>
</select>
<label for="paid">Payé</label>
<select id="paid"
onchange="generateTable()">
<option value="true">Oui</option>
<option value="false">Non</option>
<option value="both">Tous</option>
</select>
<label for="sort">Tri</label>
<select id="sort">
<option value="true"> --</option>
<option value="false">Personalisation</option>
<option value="both">Acheteur</option>
<option value="both">Date de commande</option>
<option value="both">Option 1</option>
<option value="both">Option 2</option>
</select>
</form>
<button onclick="applyFilter()">Appliquer</button>
<form onblur="generateTable()"
onkeypress="onEnter(event)">
<input placeholder="Email"
type="search"
id="emailContains">
<input placeholder="Produit"
type="search"
id="productContains">
<input placeholder="Option (valeur exacte)"
type="search"
id="optionContains">
<input placeholder="Personalisation"
type="search"
id="customizationContains">
</form>
<div id="deliveries"></div>
<script>
window.addEventListener('load', function () {
window.addEventListener('load', generateTable);
function onEnter(event) {
if (event.keyCode === 13) {
blur(event.target)
generateTable()
}
}
function generateTable() {
var params = new URLSearchParams();
params.append('delivered', document.getElementById('delivered').checked);
params.append('delivery_in_progress', document.getElementById('delivery_in_progress').checked);
var orderedItemList = new OrderedItemList('deliveries', '/boutique/ordered_items?'+params.toString(), function() {
function sendMail() {
console.log(1)
};
function viewProfile() {
console.log(2)
};
return [
new OrderedItemList.ItemAction('Remettre', sendMail),
];
});
});
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>
{% endblock %}
{% block scripts %}
<script src="{% static 'boutique/js/deliver.js' %}"></script>
<script src="{% static 'js/json_request.js' %}"></script>
<script src="{% static 'js/table_list.js' %}"></script>
<script src="{% static 'js/ordered_items.js' %}"></script>
<script src="{% static 'js/popup.js' %}"></script>
{% endblock %}
......@@ -3,7 +3,6 @@
{% load static %}
{% block styles %}
<link rel="stylesheet" href="{% static 'boutique/css/item_manage.css' %}"/>
{% endblock %}
{% block header %}
......
......@@ -49,7 +49,5 @@ urlpatterns = [
),
),
path("delivery", views.DeliveryView.as_view(), name="delivery"),
path("ordered_items", views.orderedItems, name="ordered_items"),
]
import json
import csv
import json
from typing import Any
from typing import Dict
from typing import Type
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import AnonymousUser
......@@ -23,7 +22,6 @@ from django.forms import inlineformset_factory
from django.http import HttpRequest
from django.http import HttpResponse
from django.http import JsonResponse
from django.shortcuts import render
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils import timezone
......@@ -38,6 +36,10 @@ from django.views.generic.edit import FormMixin
from django.views.generic.edit import ModelFormMixin
import bde.models
from lydia import APIError
from lydia import RequestState
from lydia.models import Request
from notifications.shortcuts import notify
from .forms import CategoryForm
from .forms import ItemForm
from .forms import OrderItemForm
......@@ -47,10 +49,6 @@ from .models import Item
from .models import Order
from .models import OrderItem
from .models import Payment
from lydia import APIError
from lydia import RequestState
from lydia.models import Request
from notifications.shortcuts import notify
class ItemListView(ListView):
......@@ -121,7 +119,7 @@ class ItemDetailView(LoginRequiredMixin, DetailView, FormMixin):
)
kwargs["is_special"] = self.object.special
kwargs["already_ordered"] = (
OrderItem.objects.get_ordered_quantity(self.object, self.request.user) >= 1
OrderItem.objects.get_ordered_quantity(self.object, self.request.user) >= 1
)
return kwargs
......@@ -385,8 +383,8 @@ class OrderEditView(LoginRequiredMixin, UpdateView):
self.object.compute_price()
kwargs["total_price"] = self.object.price
kwargs["is_contributor"] = (
bde.models.Contributor.is_contributor(self.request.user)
or self.object.contains_cotiz
bde.models.Contributor.is_contributor(self.request.user)
or self.object.contains_cotiz
)
return kwargs
......@@ -509,11 +507,63 @@ class DeliveryView(PermissionRequiredMixin, ListView):
def get_queryset(self) -> "QuerySet[OrderItem]":
return OrderItem.objects.filter(
beeing_delivered=True,
quantity_delivered__lt=F("quantity"),
order__payment__paid=True,
).select_related("order__user__profile", "order__user", "item")
def boolQueryParam(self, param):
if param == 'true': return True
if param == 'false':
return False
else:
return None
def options(self, request: HttpRequest, *args: Any, **kwargs: Any) -> JsonResponse:
itemList = OrderItem.objects
delivered = self.boolQueryParam(request.GET["delivered"])
if delivered is False:
itemList = itemList.filter(quantity_delivered__lt=F("quantity"))
elif delivered is True:
itemList = itemList.filter(quantity_delivered__gte=F("quantity"))
beeing_delivered = self.boolQueryParam(request.GET["beeing_delivered"])
if beeing_delivered is not None:
itemList = itemList.filter(beeing_delivered=beeing_delivered)
paid = self.boolQueryParam(request.GET["paid"])
if paid is not None: itemList = itemList.filter(order__payment__paid=paid)
itemList = itemList.filter(Q(item__name__icontains=request.GET["productContains"])
& Q(customization__icontains=request.GET["customizationContains"]))
optionContains = request.GET["optionContains"]
print(optionContains)
if optionContains != "":
itemList = itemList.filter(Q(option__iexact=optionContains) | Q(second_option__iexact=optionContains))
orderedItems = [
{"id": orderItem.id,
"item": str(orderItem.item),
"image": str(orderItem.item.image),
"display_name": str(orderItem.order.user.profile),
"email": str(orderItem.order.user.email),
"quantity": orderItem.quantity,
"quantity_delivered": orderItem.quantity_delivered,
"option_label": orderItem.item.option_label,
"option": orderItem.option,
"second_option_label": orderItem.item.second_option_label,
"second_option": orderItem.second_option,
"customization": orderItem.customization,
"paid": orderItem.order.paid,
"ordered_date": orderItem.order.ordered_date,
"mean": orderItem.order.mean,
}
for orderItem in itemList.select_related("order__user__profile", "order__user", "item").all()
]
return JsonResponse({"orderedItems": orderedItems})
def post(self, request: HttpRequest, *args, **kwargs) -> JsonResponse:
"""
Request content should be json
......@@ -543,13 +593,23 @@ class DeliveryView(PermissionRequiredMixin, ListView):
orderitem = queryset.get()
except OrderItem.DoesNotExist:
return JsonResponse(
{"status": "error", "code": 404, "message": "Commande introuvable"},
status_code=404,
{"status": "error", "code": 404, "message": "Commande introuvable ou impayée"},
status=404,
)
message = req.get("message")
if message == "deliver":
quantity = req.get("quantity")
if not orderitem.order.payment.paid:
return JsonResponse(
{
"status": "error",
"code": 400,
"message": "Cet article n'a pas été payé",
},
status=400,
)
if not isinstance(quantity, int):
return JsonResponse(
{
......@@ -557,31 +617,41 @@ class DeliveryView(PermissionRequiredMixin, ListView):
"code": 400,
"message": "La quantité doit être un nombre",
},
status_code=400,
status=400,
)
if quantity <= 0:
if quantity == 0:
return JsonResponse(
{
"status": "info",
"code": 202,
"message": "Quantité nulle",
},
status=202,
)
if quantity > (orderitem.quantity - orderitem.quantity_delivered):
return JsonResponse(
{
"status": "error",
"code": 400,
"message": "La quantité doit être strictement positive",
"message": "La quantité remise doit être inférieure ou égale à la quantité commandée",
},
status_code=400,
status=400,
)
if quantity > (orderitem.quantity - orderitem.quantity_delivered):
if -quantity > orderitem.quantity_delivered:
return JsonResponse(
{
"status": "error",
"code": 400,
"message": "La quantité livrée doit être inférieure ou égale à la quantité commandée",
"message": "La quantité reprise doit être inférieure à la quantité déjà remise",
},
status_code=400,
status=400,
)
orderitem.quantity_delivered += quantity
orderitem.save()
notify(
"Le {} vous à été livré".format(orderitem.item),
"Le {} vous à été remis".format(orderitem.item),
"boutique:index",
users=User.objects.filter(username=orderitem.order.user),
)
......@@ -589,37 +659,13 @@ class DeliveryView(PermissionRequiredMixin, ListView):
{
"status": "success",
"code": 200,
"message": f"{quantity} {orderitem.item} livrés à {orderitem.order.user.profile}",
"message": f"{quantity} {orderitem.item} remis à {orderitem.order.user.profile} " +
f"({orderitem.quantity_delivered}/{orderitem.quantity} remis au total)",
"quantity_delivered": orderitem.quantity_delivered,
}
)
return JsonResponse(
{"status": "error", "code": 400, "message": "Erreur inconnue"},
status_code=400,
status=400,
)
@permission_required("permissions.default_rights")
def orderedItems(request: HttpRequest) -> HttpResponse:
if request.method == "OPTIONS":
orderedItems = [
{"id": orderItem.id,
"item": str(orderItem.item),
"image": str(orderItem.item.image),
"display_name": str(orderItem.order.user.profile),
"quantity": orderItem.quantity,
"quantity_delivered": orderItem.quantity_delivered,
"option_label": orderItem.item.option_label,
"option": orderItem.option,
"second_option_label": orderItem.item.second_option_label,
"second_option": orderItem.second_option,
"customization": orderItem.customization,
}
for orderItem in OrderItem.objects.filter(
beeing_delivered=True,
quantity_delivered__lt=F("quantity"),
order__payment__paid=True,
).select_related("order__user__profile", "order__user", "item").all()
]
return JsonResponse({"orderedItems": orderedItems})
return render(request, "", {} )
\ No newline at end of file
......@@ -26,9 +26,9 @@ SECRET_KEY = "&d3ykoj75pkdv_q^4%ens@047+qi^_^379rg#!o%zg1j=pmwi&"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
INTERNAL_IPS = ["127.0.0.1"]
INTERNAL_IPS = ["192.168.0.181"]
ALLOWED_HOSTS: List[str] = []
ALLOWED_HOSTS: List[str] = ["192.168.0.181"]
# Application definition
......@@ -101,8 +101,8 @@ DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "sde",
"USER": "root",
"PASSWORD": "",
"USER": "fenwick",
"PASSWORD": "fenwick",
"HOST": "127.0.0.1",
"PORT": 3306,
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -2,20 +2,23 @@
(function () {
var OrderedItemList = function (containerId, listProvider, buildCallback) {
TableList.call(this, containerId, buildCallback);
var OrderedItemList = function (containerId, listProvider) {
TableList.call(this, containerId);
queryJson(listProvider, {}, this.populate.bind(this));
};
OrderedItemList.prototype = Object.create(TableList.prototype, {
populate: {
value: function (json) {
this.searchInput.setAttribute('placeholder', 'Acheteur')
this.elems = json['orderedItems']
var header = document.createElement('tr');
header.appendChild(document.createElement('th'));
header.appendChild(document.createElement('th')).appendChild(document.createTextNode('Produit'));
header.appendChild(document.createElement('th')).appendChild(document.createTextNode('Client'));
header.appendChild(document.createElement('th')).appendChild(document.createTextNode('Acheteur'));
header.appendChild(document.createElement('th')).appendChild(document.createTextNode('Personalisation'));
header.appendChild(document.createElement('th')).appendChild(document.createTextNode('Payement'));
header.appendChild(document.createElement('th')).appendChild(document.createTextNode('Remis'));
header.appendChild(document.createElement('th'));
this.header.appendChild(header);
......@@ -26,17 +29,18 @@
var pictureContainer = document.createElement('div');
pictureContainer.setAttribute('class', 'picture_container');
pictureContainer.setAttribute('style', 'background-color: ' + item['color']);
pictureContainer.appendChild(document.createElement('img'))
.setAttribute('src', '/medias/' + item['image']);
var actionContainer = document.createElement('div');
actionContainer.setAttribute('class', 'action_container');
var customization = document.createElement('td');
let customization = document.createElement('td');
if (item['customization'] !== '') customization.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(item['customization']));
.appendChild(document.createTextNode('Personalisation : ' + item['customization']));
if (item['option_label'] !== '') customization.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(item['option_label'] + ' : ' + item['option']));
if (item['seccon_option_label'] !== '') customization.appendChild(document.createElement('div'))
.appendChild(document.createTextNode( item['second_option_label'] + ' : ' + item['second_option']));
if (item['second_option_label'] !== '') customization.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(item['second_option_label'] + ' : ' + item['second_option']));
if (this.onElemBuild) {
......@@ -45,17 +49,57 @@
actionContainer.appendChild(actions[i].element);
}
}
let button = document.createElement('button');
button.addEventListener('click', deliver);
button.disabled= !item['paid'];
if(item['quantity_delivered'] >= item['quantity']) {
button.innerHTML = 'Reprendre';
button.setAttribute('class', 'red_button');
}
else{
button.innerHTML = 'Remettre';
}
actionContainer.appendChild(button);
let payement = document.createElement('td');
if (!item['paid']) {
payement.innerHTML = 'Non payé';
payement.setAttribute('style', 'color: red');
} else {
const mean = {"card": "Carte", "online": "Lydia", "cash": "Espèces", "check": "Chèque"};
const date = new Date(item['ordered_date']);