mirror of
https://framagit.org/la-chariotte/la-chariotte.git
synced 2025-05-02 11:52:27 +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,43 +6,124 @@
|
|||
<p class="desktop-hidden mobile-content-title">
|
||||
{% block content_title %}Ajouter des produits à votre commande groupée{% endblock %}
|
||||
</p>
|
||||
|
||||
<p>Commande groupée "{{ grouped_order.name }}", le {{ grouped_order.delivery_date }}<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>
|
||||
|
||||
{% url 'order:item_create' pk=grouped_order.pk as create_item_url %}
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Prix unitaire</th>
|
||||
<th>Quantité max (optionnel)</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<form method="post" action="{{ create_item_url }}">
|
||||
{% csrf_token %}
|
||||
<td><input name="name" maxlength="100" placeholder="Nom du produit" autofocus 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><button type="submit" class="button is-primary">Ajouter</button></td>
|
||||
</tr>
|
||||
{% for item in item_list %}
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.price }}</td>
|
||||
<td>{% if item.max_limit %}{{ item.max_limit }}{% else %}---{% endif %}</td>
|
||||
<td>Supprimer (pas possible pour l'instant)</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="buttons is-pulled-right">
|
||||
<a href="{% url 'order:grouped_order_overview' pk=grouped_order.id %}" class="button is-primary">Valider</a>
|
||||
<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 class="title">Gestion des produits - {{ grouped_order.name }}</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 %}
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Prix unitaire</th>
|
||||
<th>Quantité max (optionnel)</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<form method="post" action="{{ create_item_url }}">
|
||||
{% csrf_token %}
|
||||
<td><input name="name" maxlength="100" placeholder="Nom du produit" autofocus 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><button type="submit" class="button is-primary">Ajouter</button></td>
|
||||
</form>
|
||||
</tr>
|
||||
{% for item in item_list %}
|
||||
<tr>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.price }}</td>
|
||||
<td>{% if item.max_limit %}{{ item.max_limit }}{% else %}---{% endif %}</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>
|
||||
<!-- 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 %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="buttons is-pulled-right">
|
||||
<a href="{% url 'order:grouped_order_overview' pk=grouped_order.id %}" class="button is-primary">Valider</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% 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,7 +22,9 @@
|
|||
{% endif %}
|
||||
<p>Date de livraison : {{ grouped_order.delivery_date }}</p>
|
||||
<p>Date limite de commande : {{ grouped_order.deadline }}</p>
|
||||
<a class="button is-light" href={% url 'order:grouped_order_detail' grouped_order.id %}>Retour à la page de commande</a>
|
||||
<div class="buttons">
|
||||
<a class="button is-light" href={% url 'order:grouped_order_detail' grouped_order.id %}>Retour à la page de commande</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -54,6 +56,7 @@
|
|||
</div>
|
||||
|
||||
<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>
|
||||
{% if grouped_order.item_set.all %}
|
||||
<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:
|
||||
def test_create_item(self, client_log):
|
||||
|
|
|
@ -30,6 +30,11 @@ urlpatterns = [
|
|||
views.ItemCreateView.as_view(),
|
||||
name="item_create",
|
||||
),
|
||||
path(
|
||||
"<int:grouped_order_id>/gerer-produits/<int:pk>/supprimer",
|
||||
views.ItemDeleteView.as_view(),
|
||||
name="item_delete",
|
||||
),
|
||||
path(
|
||||
"<int:pk>/gerer/imprimer",
|
||||
views.GroupedOrderSheetView.as_view(),
|
||||
|
|
|
@ -130,6 +130,7 @@ class GroupedOrderAddItemsView(UserPassesTestMixin, generic.ListView):
|
|||
def test_func(self):
|
||||
"""Accessible only if the requesting user is the grouped order organizer"""
|
||||
grouped_order_id = self.kwargs.get("pk")
|
||||
# breakpoint()
|
||||
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
|
||||
|
||||
|
||||
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):
|
||||
"""Creates an AnonymousUser, and an Order for this GroupedOrder, with related OrderedItems"""
|
||||
grouped_order = get_object_or_404(GroupedOrder, pk=grouped_order_id)
|
||||
|
|
Loading…
Reference in a new issue