mirror of
https://framagit.org/la-chariotte/la-chariotte.git
synced 2025-05-03 12:21:52 +02:00
delete an item when it's not ordered yet
This commit is contained in:
parent
c1026c78d1
commit
7ab2db66e2
5 changed files with 205 additions and 39 deletions
|
@ -6,14 +6,18 @@
|
||||||
<p class="desktop-hidden mobile-content-title">
|
<p class="desktop-hidden mobile-content-title">
|
||||||
{% block content_title %}Ajouter des produits à votre commande groupée{% endblock %}
|
{% block content_title %}Ajouter des produits à votre commande groupée{% endblock %}
|
||||||
</p>
|
</p>
|
||||||
|
<div class="buttons">
|
||||||
|
<a class="button is-light" href={% url 'order:grouped_order_overview' grouped_order.id %}>Retour</a>
|
||||||
|
<a class="button is-primary" href="{% url 'order:index' %}">Mes commandes</a>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
|
||||||
<p>Commande groupée "{{ grouped_order.name }}", le {{ grouped_order.delivery_date }}<p>
|
<p class="title">Gestion des produits - {{ grouped_order.name }}</p>
|
||||||
<p>Limite de commande : {{ grouped_order.deadline }}</p>
|
<p>Sur cette page, vous pouvez voir et modifier les produits qui sont inscrits à votre commande groupée.</p>
|
||||||
<p>Sur cette page, vous pouvez voir et modifier les produits qui sont inscrits à votre commande groupée.</p>
|
|
||||||
|
|
||||||
{% url 'order:item_create' pk=grouped_order.pk as create_item_url %}
|
{% url 'order:item_create' pk=grouped_order.pk as create_item_url %}
|
||||||
|
|
||||||
<table class="table">
|
<table class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Nom</th>
|
<th>Nom</th>
|
||||||
|
@ -30,19 +34,96 @@
|
||||||
<td><input name="price" size="2" placeholder="5,40" required></input> €</td>
|
<td><input name="price" size="2" placeholder="5,40" required></input> €</td>
|
||||||
<td><input name="max_limit" size="2" placeholder="42"></input></td>
|
<td><input name="max_limit" size="2" placeholder="42"></input></td>
|
||||||
<td><button type="submit" class="button is-primary">Ajouter</button></td>
|
<td><button type="submit" class="button is-primary">Ajouter</button></td>
|
||||||
|
</form>
|
||||||
</tr>
|
</tr>
|
||||||
{% for item in item_list %}
|
{% for item in item_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.name }}</td>
|
<td>{{ item.name }}</td>
|
||||||
<td>{{ item.price }}</td>
|
<td>{{ item.price }}</td>
|
||||||
<td>{% if item.max_limit %}{{ item.max_limit }}{% else %}---{% endif %}</td>
|
<td>{% if item.max_limit %}{{ item.max_limit }}{% else %}---{% endif %}</td>
|
||||||
<td>Supprimer (pas possible pour l'instant)</td>
|
<td>
|
||||||
|
{% if item.ordered_nb == 0 %}
|
||||||
|
<button class="button is-light is-small js-modal-trigger" data-target="confirm-delete-{{ item.id }}">
|
||||||
|
Supprimer
|
||||||
|
</button>
|
||||||
|
{% else %}
|
||||||
|
Produit déjà commandé
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<!-- Confirm delete modal -->
|
||||||
|
<div id="confirm-delete-{{ item.id }}" class="modal">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="box">
|
||||||
|
<p>Voulez-vous vraiment supprimer le produit {{ item.name }} de la commande ?</p>
|
||||||
|
<form action="{% url 'order:item_delete' grouped_order.id item.id %}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="submit" name="{{ item.id }}" value="Oui" class="button is-danger"/>
|
||||||
|
<a class="button is-light" href="">Non</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="modal-close is-large" aria-label="close"></button>
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="buttons is-pulled-right">
|
<div class="buttons is-pulled-right">
|
||||||
<a href="{% url 'order:grouped_order_overview' pk=grouped_order.id %}" class="button is-primary">Valider</a>
|
<a href="{% url 'order:grouped_order_overview' pk=grouped_order.id %}" class="button is-primary">Valider</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
{% block extra_js %}
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// Functions to open and close a modal
|
||||||
|
function openModal($el) {
|
||||||
|
$el.classList.add('is-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeModal($el) {
|
||||||
|
$el.classList.remove('is-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeAllModals() {
|
||||||
|
(document.querySelectorAll('.modal') || []).forEach(($modal) => {
|
||||||
|
closeModal($modal);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a click event on buttons to open a specific modal
|
||||||
|
(document.querySelectorAll('.js-modal-trigger') || []).forEach(($trigger) => {
|
||||||
|
const modal = $trigger.dataset.target;
|
||||||
|
const $target = document.getElementById(modal);
|
||||||
|
|
||||||
|
$trigger.addEventListener('click', () => {
|
||||||
|
openModal($target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a click event on various child elements to close the parent modal
|
||||||
|
(document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => {
|
||||||
|
const $target = $close.closest('.modal');
|
||||||
|
|
||||||
|
$close.addEventListener('click', () => {
|
||||||
|
closeModal($target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add a keyboard event to close all modals
|
||||||
|
document.addEventListener('keydown', (event) => {
|
||||||
|
const e = event || window.event;
|
||||||
|
|
||||||
|
if (e.keyCode === 27) { // Escape key
|
||||||
|
closeAllModals();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
{% endblock %}
|
||||||
|
</script>
|
|
@ -22,10 +22,12 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>Date de livraison : {{ grouped_order.delivery_date }}</p>
|
<p>Date de livraison : {{ grouped_order.delivery_date }}</p>
|
||||||
<p>Date limite de commande : {{ grouped_order.deadline }}</p>
|
<p>Date limite de commande : {{ grouped_order.deadline }}</p>
|
||||||
|
<div class="buttons">
|
||||||
<a class="button is-light" href={% url 'order:grouped_order_detail' grouped_order.id %}>Retour à la page de commande</a>
|
<a class="button is-light" href={% url 'order:grouped_order_detail' grouped_order.id %}>Retour à la page de commande</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<p class="title">Partager et imprimer</p>
|
<p class="title">Partager et imprimer</p>
|
||||||
|
@ -54,6 +56,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="box">
|
<div class="box">
|
||||||
|
<a class="button is-primary is-pulled-right" href="{% url 'order:manage_items' grouped_order.pk %}">Gérer les produits</a>
|
||||||
<p class="title">Produits commandés</p>
|
<p class="title">Produits commandés</p>
|
||||||
{% if grouped_order.item_set.all %}
|
{% if grouped_order.item_set.all %}
|
||||||
<table class="table">
|
<table class="table">
|
||||||
|
|
|
@ -779,6 +779,67 @@ class TestGroupedOrderAddItemsView:
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_delete_item(self, client_log):
|
||||||
|
"""
|
||||||
|
A user on the manage item page creates and then deletes an item
|
||||||
|
"""
|
||||||
|
assert models.GroupedOrder.objects.count() == 0
|
||||||
|
create_gorder_url = reverse("order:create_grouped_order")
|
||||||
|
response = client_log.get(create_gorder_url)
|
||||||
|
assert response.status_code == 200
|
||||||
|
date = timezone.now().date() + datetime.timedelta(days=42)
|
||||||
|
deadline = timezone.now() + datetime.timedelta(days=32)
|
||||||
|
response = client_log.post(
|
||||||
|
create_gorder_url,
|
||||||
|
{"name": "titre test", "deadline": deadline, "delivery_date": date},
|
||||||
|
)
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url.endswith("gerer-produits")
|
||||||
|
assert models.GroupedOrder.objects.count() == 1
|
||||||
|
|
||||||
|
# Create an item
|
||||||
|
grouped_order = models.GroupedOrder.objects.first()
|
||||||
|
create_item_url = reverse("order:item_create", args=[grouped_order.id])
|
||||||
|
response = client_log.post(create_item_url, {"name": "Pain test", "price": "2"})
|
||||||
|
response.status_code == 302
|
||||||
|
response.url == reverse("order:manage_items", args=[grouped_order.pk])
|
||||||
|
assert grouped_order.item_set.count() == 1
|
||||||
|
|
||||||
|
# Delete the item
|
||||||
|
item = grouped_order.item_set.first()
|
||||||
|
delete_item_url = reverse("order:item_delete", args=[grouped_order.id, item.id])
|
||||||
|
response = client_log.post(delete_item_url)
|
||||||
|
assert response.status_code == 302
|
||||||
|
assert response.url == reverse("order:manage_items", args=[grouped_order.pk])
|
||||||
|
assert grouped_order.item_set.count() == 0
|
||||||
|
|
||||||
|
def test_create_or_delete_item__not_orga(self, client_log, other_user):
|
||||||
|
"""
|
||||||
|
A user that is not orga delete or create an item
|
||||||
|
They get a 403 forbidden error
|
||||||
|
"""
|
||||||
|
grouped_order = create_grouped_order(
|
||||||
|
days_before_delivery_date=5,
|
||||||
|
days_before_deadline=2,
|
||||||
|
name="gr order test",
|
||||||
|
orga_user=other_user,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create an item
|
||||||
|
grouped_order = models.GroupedOrder.objects.first()
|
||||||
|
create_item_url = reverse("order:item_create", args=[grouped_order.id])
|
||||||
|
response = client_log.post(create_item_url, {"name": "Pain test", "price": "2"})
|
||||||
|
response.status_code == 403
|
||||||
|
assert grouped_order.item_set.count() == 0
|
||||||
|
|
||||||
|
# Delete an item
|
||||||
|
item = grouped_order.item_set.create(name="Pain test", price="2")
|
||||||
|
assert grouped_order.item_set.count() == 1
|
||||||
|
delete_item_url = reverse("order:item_delete", args=[grouped_order.id, item.id])
|
||||||
|
response = client_log.post(delete_item_url)
|
||||||
|
assert response.status_code == 403
|
||||||
|
assert grouped_order.item_set.count() == 1
|
||||||
|
|
||||||
|
|
||||||
class TestItemCreateView:
|
class TestItemCreateView:
|
||||||
def test_create_item(self, client_log):
|
def test_create_item(self, client_log):
|
||||||
|
|
|
@ -30,6 +30,11 @@ urlpatterns = [
|
||||||
views.ItemCreateView.as_view(),
|
views.ItemCreateView.as_view(),
|
||||||
name="item_create",
|
name="item_create",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"<int:grouped_order_id>/gerer-produits/<int:pk>/supprimer",
|
||||||
|
views.ItemDeleteView.as_view(),
|
||||||
|
name="item_delete",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"<int:pk>/gerer/imprimer",
|
"<int:pk>/gerer/imprimer",
|
||||||
views.GroupedOrderSheetView.as_view(),
|
views.GroupedOrderSheetView.as_view(),
|
||||||
|
|
|
@ -130,6 +130,7 @@ class GroupedOrderAddItemsView(UserPassesTestMixin, generic.ListView):
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
"""Accessible only if the requesting user is the grouped order organizer"""
|
"""Accessible only if the requesting user is the grouped order organizer"""
|
||||||
grouped_order_id = self.kwargs.get("pk")
|
grouped_order_id = self.kwargs.get("pk")
|
||||||
|
# breakpoint()
|
||||||
return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user
|
return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user
|
||||||
|
|
||||||
|
|
||||||
|
@ -150,6 +151,21 @@ class ItemCreateView(UserPassesTestMixin, generic.CreateView):
|
||||||
return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user
|
return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user
|
||||||
|
|
||||||
|
|
||||||
|
class ItemDeleteView(UserPassesTestMixin, generic.DeleteView):
|
||||||
|
"""DeleteView for an item
|
||||||
|
The form does a GET to this view - it displays a confirmation page - then we post this view
|
||||||
|
"""
|
||||||
|
|
||||||
|
model = Item
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse_lazy("order:manage_items", args=[self.object.grouped_order.id])
|
||||||
|
|
||||||
|
def test_func(self):
|
||||||
|
"""Accessible only if the requesting user is the grouped order organizer"""
|
||||||
|
return self.get_object().grouped_order.orga == self.request.user
|
||||||
|
|
||||||
|
|
||||||
def order(request, grouped_order_id):
|
def order(request, grouped_order_id):
|
||||||
"""Creates an AnonymousUser, and an Order for this GroupedOrder, with related OrderedItems"""
|
"""Creates an AnonymousUser, and an Order for this GroupedOrder, with related OrderedItems"""
|
||||||
grouped_order = get_object_or_404(GroupedOrder, pk=grouped_order_id)
|
grouped_order = get_object_or_404(GroupedOrder, pk=grouped_order_id)
|
||||||
|
|
Loading…
Reference in a new issue