Compare commits

..

2 commits

Author SHA1 Message Date
selfhoster1312 ACAB
f069bf0ae6 Merge branch 'feat-distribution-place' into 'develop'
Draft: feature: Add placekey relationship for distribution spots

See merge request la-chariotte/la-chariotte!129
2025-03-03 22:04:00 +00:00
selfhoster1312
a93864d2af feature: Add place relationship for distribution spots 2025-03-03 23:03:44 +01:00
10 changed files with 331 additions and 17 deletions

View file

@ -31,7 +31,7 @@ def link_existing_place(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
("order", "0029_set_phone_mandatory_for_existing_orders"),
("order", "0030_alter_groupedorder_code_alter_orderauthor_email_and_more"),
]
operations = [

View file

@ -228,3 +228,12 @@ class Place(models.Model):
def get_absolute_url(self):
return reverse("order:place_update", kwargs={"code": self.code})
def active_orders(self):
# Only return currently active orders (not yet delivered)
active_orders = (
self.orders.all()
.filter(delivery_date__gt=timezone.now())
.order_by("-delivery_date")
)
return active_orders

View file

@ -30,8 +30,8 @@
</td>
<td>
{% if place.code in context.orders.keys %}
{% for place_url, place_orders in context.orders.items %}
{% if place_url == place.code %}
{% for place_code, place_orders in context.orders.items %}
{% if place_code == place.code %}
{% for order in place_orders %}
{% url 'order:grouped_order_detail' code=order.code as order_url %}
{% if order_url %}

View file

@ -326,11 +326,11 @@ class GroupedOrderExportView(UserIsOrgaMixin, generic.DetailView):
context["orders_dict"] = orders_dict
if grouped_order.has_places:
places = dict()
# Initialize empty list of orders for every place enabled for this GroupedOrder
places = {x.code: {} for x in grouped_order.places.all()}
for order, order_items in orders_dict.items():
if order.place.name not in places:
lieux[order.place.name] = dict()
lieux[order.place.name][order] = order_items
places[order.place.code][order] = order_items
context["places"] = places
return context

View file

@ -1,5 +1,6 @@
from django import http
from django.contrib.auth.mixins import UserPassesTestMixin
from django.core.exceptions import SuspiciousOperation
from django.shortcuts import get_object_or_404, render
from django.urls import reverse, reverse_lazy
from django.utils import timezone
@ -50,6 +51,13 @@ def place_order(request, code):
# Make sure requested place is valid in this group order (and exists at all)
# If no places are enabled for this group order, chosen place is always None
if grouped_order.has_places:
# If places are enabled for the GroupedOrder
if "place" not in request.POST:
# HTTP error code 400
raise SuspiciousOperation(
"Aucun lieu n'est spécifié alors que la commande groupée en exige un"
)
places = grouped_order.places.all()
# Return 404 if the requested place does not exist at all
place = get_object_or_404(Place, code=request.POST["place"])

View file

@ -26,15 +26,14 @@ class PlaceIndexView(LoginRequiredMixin, generic.ListView):
def get_queryset(self):
places = Place.objects.filter(orga=self.request.user)
print(places)
# Let's filter orders by distribution place (for UI grouping)
orders = dict()
for place in places:
# TODO: maybe filter out finished GroupedOrder?
if place.orders.all():
orders[place.code] = place.orders.all()
# orders[place.code] = orders
# Only get currently-active grouped orders
active_orders = place.active_orders()
if active_orders:
orders[place.code] = active_orders
return {
"places": places,

View file

@ -5,7 +5,7 @@ from django.contrib import auth
from django.urls import reverse
from django.utils import timezone
from la_chariotte.order.models import GroupedOrder, Item
from la_chariotte.order.models import GroupedOrder, Item, Place
from .utils import create_grouped_order
@ -140,3 +140,70 @@ class TestItemModel:
assert grouped_order.item_set.first() == item
assert grouped_order.item_set.all()[1] == item3
assert grouped_order.item_set.all()[2] == item2
class TestPlaceModel:
def test_create_place(self, client_log):
assert Place.objects.count() == 0
create_place_url = reverse("order:place_create")
response = client_log.get(create_place_url)
assert response.status_code == 200
response = client_log.post(
create_place_url,
{
"name": "Centre social Kropotkine",
"code": "kropotkine",
},
)
assert response.status_code == 302
assert Place.objects.count() == 1
def test_order_has_places(self, client_log):
now = timezone.now()
place = Place.objects.create(
name="Centre social Kropotkine",
orga=auth.get_user(client_log),
code="kropotkine",
)
grouped_order_active = GroupedOrder.objects.create(
name="test",
orga=auth.get_user(client_log),
delivery_date=now.date(),
deadline=now + datetime.timedelta(days=30),
)
assert grouped_order_active.has_places == False
grouped_order_active.places.add(place.id)
assert grouped_order_active.has_places == True
def test_place_active_orders(self, client_log):
now = timezone.now()
place = Place.objects.create(
name="Centre Social Kropotkine",
orga=auth.get_user(client_log),
code="kropotkine",
)
grouped_order_active = GroupedOrder.objects.create(
name="test",
orga=auth.get_user(client_log),
delivery_date=now.date() + datetime.timedelta(days=30),
deadline=now + datetime.timedelta(days=30),
)
grouped_order_active.places.add(place.id)
grouped_order_inactive = GroupedOrder.objects.create(
name="test",
orga=auth.get_user(client_log),
delivery_date=now.date() - datetime.timedelta(days=30),
deadline=now + datetime.timedelta(days=30),
)
grouped_order_inactive.places.add(place.id)
assert place.orders.all().count() == 2
active_orders = place.active_orders()
assert active_orders.count() == 1
assert active_orders.first().id == grouped_order_active.id

View file

@ -1437,6 +1437,7 @@ class TestGroupedOrderSheetView:
assert response.context["grouped_order"] == grouped_order
assert len(response.context["items"]) == 0
assert len(response.context["orders_dict"]) == 0
assert "places" not in response.context.keys()
# we order some items in the grouped order
order = order_items_in_grouped_order(grouped_order)
@ -1446,6 +1447,7 @@ class TestGroupedOrderSheetView:
assert len(response.context["items"]) == 2
assert response.context["orders_dict"][order] == [3, 2]
assert response.context["grouped_order"].total_price == 35
assert "places" not in response.context.keys()
# test if the orders are sorted by last names
orders = list(response.context["orders_dict"].keys())
@ -1455,6 +1457,74 @@ class TestGroupedOrderSheetView:
assert orders[1].author.first_name == "bobby"
assert orders[2].author.last_name == "lescargot"
def test_get_pdf_sheet_with_places(self, client_log, other_user):
"""The orga of the grouped models.Order accesses the pdf sheet"""
place1 = models.Place.objects.create(
name="Centre social Kropotkine",
orga=auth.get_user(client_log),
code="kropotkine",
)
place2 = models.Place.objects.create(
name="Centre social Luxemburg",
orga=auth.get_user(client_log),
code="luxemburg",
)
grouped_order = create_grouped_order(
days_before_delivery_date=5,
days_before_deadline=2,
name="gr order test",
orga_user=auth.get_user(client_log),
)
grouped_order.places.add(place1.id)
grouped_order.places.add(place2.id)
generate_sheet_url = reverse(
"order:grouped_order_sheet",
kwargs={
"code": grouped_order.code,
},
)
response = client_log.get(generate_sheet_url)
assert response.status_code == 200
assert response.context["grouped_order"] == grouped_order
assert len(response.context["items"]) == 0
assert len(response.context["orders_dict"]) == 0
assert "places" in response.context.keys()
assert len(response.context["places"]) == 2
assert len(response.context["places"]["kropotkine"]) == 0
assert len(response.context["places"]["luxemburg"]) == 0
# we order some items in the grouped order
order = order_items_in_grouped_order(grouped_order, place=place2)
response = client_log.get(generate_sheet_url)
assert response.status_code == 200
assert response.context["grouped_order"] == grouped_order
assert len(response.context["items"]) == 2
assert response.context["orders_dict"][order] == [3, 2]
assert response.context["grouped_order"].total_price == 35
assert "places" in response.context.keys()
# test that orders are split by distribution place
places = response.context["places"]
assert len(places["kropotkine"]) == 0
assert len(places["luxemburg"]) == 3
orders = list(places["luxemburg"])
assert orders[0].author.last_name == "alescargot"
assert orders[0].author.first_name == "bob"
assert orders[1].author.last_name == "alescargot"
assert orders[1].author.first_name == "bobby"
assert orders[2].author.last_name == "lescargot"
# test that splitting by place does not affect orders_dict overall
orders = list(response.context["orders_dict"].keys())
assert orders[0].author.last_name == "alescargot"
assert orders[0].author.first_name == "bob"
assert orders[1].author.last_name == "alescargot"
assert orders[1].author.first_name == "bobby"
assert orders[2].author.last_name == "lescargot"
class TestExportGroupOrderEmailAdressesToDownloadView:
def test_user_not_logged_gets_redirected(self, client, other_user):

View file

@ -268,3 +268,164 @@ class TestOrder:
assert grouped_order.order_set.all().count() == 2
assert grouped_order.total_price == 35 - order_price
assert item.ordered_nb == 1
def test_order_valid_place(self, client_log):
"""The orga user requests a non-existing place for distribution. It fails"""
grouped_order = create_grouped_order(
days_before_delivery_date=5,
days_before_deadline=2,
name="gr order test",
orga_user=auth.get_user(client_log),
)
place = models.Place.objects.create(
name="Centre social Kropotkine",
code="kropotkine",
orga=auth.get_user(client_log),
)
grouped_order.places.add(place.id)
item = models.Item.objects.create(
name="test item 1", grouped_order=grouped_order, price=1
)
order_url = reverse(
"order:order",
kwargs={
"code": grouped_order.code,
},
)
response = client_log.post(
order_url,
{
f"quantity_{item.pk}": [4, 0],
"first_name": "Prénom",
"last_name": "Nom",
"phone": "0645632569",
"email": "test@mail.fr",
"note": "",
"place": place.code,
},
)
assert response.status_code == 302
# TODO: How to test trying to use a place from a different user/orga?
def test_order_invalid_place(self, client_log):
"""The orga user requests a non-existing place for distribution. It fails"""
grouped_order = create_grouped_order(
days_before_delivery_date=5,
days_before_deadline=2,
name="gr order test",
orga_user=auth.get_user(client_log),
)
place = models.Place.objects.create(
name="Centre social Kropotkine",
code="kropotkine",
orga=auth.get_user(client_log),
)
grouped_order.places.add(place.id)
item = models.Item.objects.create(
name="test item 1", grouped_order=grouped_order, price=1
)
order_url = reverse(
"order:order",
kwargs={
"code": grouped_order.code,
},
)
response = client_log.post(
order_url,
{
f"quantity_{item.pk}": [4, 0],
"first_name": "Prénom",
"last_name": "Nom",
"phone": "0645632569",
"email": "test@mail.fr",
"note": "",
"place": "foobar",
},
)
assert response.status_code == 404
def test_order_unaffiliated_place(self, client_log):
"""The orga user requests a place for distribution unrelated to this grouped order. It fails"""
grouped_order = create_grouped_order(
days_before_delivery_date=5,
days_before_deadline=2,
name="gr order test",
orga_user=auth.get_user(client_log),
)
place = models.Place.objects.create(
name="Centre social Kropotkine",
code="kropotkine",
orga=auth.get_user(client_log),
)
place2 = models.Place.objects.create(
name="Centre social Luxemburg",
code="luxemburg",
orga=auth.get_user(client_log),
)
grouped_order.places.add(place.id)
item = models.Item.objects.create(
name="test item 1", grouped_order=grouped_order, price=1
)
order_url = reverse(
"order:order",
kwargs={
"code": grouped_order.code,
},
)
response = client_log.post(
order_url,
{
f"quantity_{item.pk}": [4, 0],
"first_name": "Prénom",
"last_name": "Nom",
"phone": "0645632569",
"email": "test@mail.fr",
"note": "",
"place": place2.code,
},
)
assert response.status_code == 404
def test_order_no_place(self, client_log):
"""The orga user requests a non-existing place for distribution. It fails"""
grouped_order = create_grouped_order(
days_before_delivery_date=5,
days_before_deadline=2,
name="gr order test",
orga_user=auth.get_user(client_log),
)
place = models.Place.objects.create(
name="Centre social Kropotkine",
code="kropotkine",
orga=auth.get_user(client_log),
)
grouped_order.places.add(place.id)
item = models.Item.objects.create(
name="test item 1", grouped_order=grouped_order, price=1
)
order_url = reverse(
"order:order",
kwargs={
"code": grouped_order.code,
},
)
response = client_log.post(
order_url,
{
f"quantity_{item.pk}": [4, 0],
"first_name": "Prénom",
"last_name": "Nom",
"phone": "0645632569",
"email": "test@mail.fr",
"note": "",
},
)
assert response.status_code == 400

View file

@ -29,7 +29,7 @@ def create_grouped_order(
return grouped_order
def order_items_in_grouped_order(grouped_order):
def order_items_in_grouped_order(grouped_order, place=None):
"""Creates 2 OrderedItems and orders in the given grouped order. Returns the order"""
item_1 = grouped_order.item_set.create(name="test item", price="2")
item_2 = grouped_order.item_set.create(name="test item 2", price="9")
@ -45,9 +45,9 @@ def order_items_in_grouped_order(grouped_order):
phone="000",
email="bob3@escargot.fr",
)
order = grouped_order.order_set.create(author=author_1)
order_2 = grouped_order.order_set.create(author=author_2)
order_3 = grouped_order.order_set.create(author=author_3)
order = grouped_order.order_set.create(author=author_1, place=place)
order_2 = grouped_order.order_set.create(author=author_2, place=place)
order_3 = grouped_order.order_set.create(author=author_3, place=place)
models.OrderedItem.objects.create(order=order, item=item_1, nb=3)
models.OrderedItem.objects.create(order=order, item=item_2, nb=2)
models.OrderedItem.objects.create(order=order_2, item=item_1, nb=1)