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

(44): delivery popup

parent d4a491da
......@@ -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())
......
......@@ -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):
......@@ -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 source diff could not be displayed because it is too large. You can view the blob instead.
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']);
function pad(s) {
return (s < 10) ? '0' + s : s;
}
payement.innerHTML = (mean[item['mean']] ? mean[item['mean']] : item['mean'])
+ '<br>'
+ [pad(date.getDate()), pad(date.getMonth() + 1), date.getFullYear()].join('/');
}
let buyer = document.createElement('td');
buyer.innerHTML = (item['display_name'] === item['email'] ? item['display_name'] : item['display_name'] + '<br>' + item['email'])
item.element = document.createElement('tr');
pictureContainer.appendChild(document.createElement('td')).appendChild(document.createElement('img'))
.setAttribute('src', '/medias/' + item['image']);
item.element.appendChild(pictureContainer);
item.element.appendChild(document.createElement('td')).appendChild(document.createTextNode(item['item']));
item.element.appendChild(document.createElement('td')).appendChild(document.createTextNode(item['display_name']));
item.element.appendChild(document.createElement('td')).appendChild(customization);
item.element.appendChild(document.createElement('td')).appendChild(document.createTextNode(item['quantity_delivered'] + ' / ' + item['quantity']));
item.element.setAttribute('data-id', item['id']);
item.element.setAttribute('data-item', item['item']);
item.element.setAttribute('data-quantity_ordered', item['quantity']);
item.element.setAttribute('data-quantity_delivered', item['quantity_delivered']);
item.element.setAttribute('data-quantity_delivered', item['quantity_delivered']);
item.element.setAttribute('data-display_name', item['display_name']);
item.element.setAttribute('data-paid', item['paid']);
item.element.appendChild(document.createElement('td')).appendChild(pictureContainer);
item.element.appendChild(document.createElement('td')).innerHTML = item['item'];
item.element.appendChild(buyer);
item.element.appendChild(customization);
item.element.appendChild(payement);
item.element.appendChild(document.createElement('td')).innerHTML = item['quantity_delivered'] + ' / ' + item['quantity'];
item.element.appendChild(document.createElement('td')).appendChild(actionContainer);
this.body.appendChild(item.element);
}
......@@ -87,3 +131,29 @@
window.OrderedItemList.ItemAction = Action;
})();
function deliver(event) {
let tr = event.target.closest('tr')
let item = {
"id": tr.dataset.id,
"item": tr.dataset.item,
"quantity_ordered": tr.dataset.quantity_ordered,
"quantity_delivered": tr.dataset.quantity_delivered,
"display_name": tr.dataset.display_name
}
let deliverPopup = new DeliverPopup(item, function (id, quantity) {
queryJson(document.location, {
"message": "deliver",
"id": id,
"quantity": parseInt(quantity)
}, function (data) {
add_message(data.status, data.message);
if (data.code === 200) {
generateTable();
}
}, "POST");
})
deliverPopup.pop();
}
\ No newline at end of file
......@@ -89,6 +89,78 @@ SelectionPopup.prototype = Object.create(Popup.prototype, {});
SelectionPopup.prototype.constructor = SelectionPopup;
/*
* Selection popup
*
* Open a pupop with the given choices and call the callback with the selected
* one as it's first argument. choises is an array with a key as the choice
* name and the value as the choice displayed
*/
function DeliverPopup(item, callback) {
Popup.call(this, 'Remettre un article');
this.baseClass = 'selection_popup';
this.callback = callback;
let max = parseInt(item['quantity_ordered']) - parseInt(item["quantity_delivered"]);
let body = document.createElement("div")
body.innerHTML =
"<h4> Article : <i>" + item['item'] + "</i><br> Acheteur : <i>" + item["display_name"] + " </i></h4>" +
"<span> Quantité commandée : " + item["quantity_ordered"] +
"<br>Déjà remis : " + item["quantity_delivered"] +
"<br>Reste à remettre : " + max +
"<br><br></span>" +
"<label for='quantity_to_deliver'>Quantité à remettre :</label> "
let form = document.createElement('form')
let quantityInput = document.createElement('input')
quantityInput.setAttribute('id', 'quantity_to_deliver')
quantityInput.setAttribute('type', 'number');
quantityInput.setAttribute('max', max);
quantityInput.value = max;
quantityInput.setAttribute('min', parseInt(-item['quantity_delivered']));
quantityInput.setAttribute('step', 1);
quantityInput.setAttribute('style', 'font-size: larger');
quantityInput.addEventListener('change', is_valid)
quantityInput = body.appendChild(quantityInput);
this.main.appendChild(body);
let button = document.createElement('button');
button.setAttribute('type', 'button');
let warning = document.createElement('h4');
warning.innerHTML='Quantité négative : vous reprenez l\'article'
warning.setAttribute('style', 'color: red');
this.main.appendChild(warning);
this.main.appendChild(button);
is_valid();
function is_valid() {
let quantity = quantityInput.value;
button.disabled = (parseInt(quantity) === 0 |
quantity > item['quantity_ordered'] - item['quantity_delivered'] |
-quantity > item['quantity_delivered']);
quantityInput.value < 0 ? button.innerHTML= 'Reprendre' : button.innerHTML = 'Remettre';
quantityInput.value < 0 ? warning.hidden= false: warning.hidden= true;
}
button.addEventListener('click', function (event) {
this.callback(item['id'], quantityInput.value);
this.close();
}.bind(this));
}
DeliverPopup.prototype = Object.create(Popup.prototype, {});
DeliverPopup.prototype.constructor = DeliverPopup;