Compare commits

..

2 commits

Author SHA1 Message Date
selfhoster1312 ACAB
ed60e4762a 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-05 12:53:01 +00:00
selfhoster1312
cef342de83 feature: Add place relationship for distribution spots 2025-03-05 13:52:56 +01:00
6 changed files with 61 additions and 67 deletions

View file

@ -72,12 +72,4 @@ class Migration(migrations.Migration):
name="place", name="place",
field=models.ForeignKey(blank=True, null=True, on_delete=models.deletion.CASCADE, to='order.place'), field=models.ForeignKey(blank=True, null=True, on_delete=models.deletion.CASCADE, to='order.place'),
), ),
migrations.AddIndex(
model_name="groupedorder",
index=models.Index(fields=["code"], name="order_group_code_50902d_idx"),
),
migrations.AddIndex(
model_name="place",
index=models.Index(fields=["code"], name="order_place_code_4e2b27_idx"),
),
] ]

View file

@ -36,9 +36,6 @@ class GroupedOrder(models.Model):
default=False, verbose_name="Numéro de téléphone obligatoire" default=False, verbose_name="Numéro de téléphone obligatoire"
) )
class Meta:
indexes = [models.Index(fields=["code"])]
def create_code_from_pk(self): def create_code_from_pk(self):
"""When a grouped order is created, a unique code is generated, to be used to """When a grouped order is created, a unique code is generated, to be used to
build the order URL. build the order URL.
@ -63,6 +60,13 @@ class GroupedOrder(models.Model):
) )
self.code = f"{base_36_pk}{random_string}"[:code_length] self.code = f"{base_36_pk}{random_string}"[:code_length]
@property
def has_places(self):
# Check whether this GroupedOrder has any distribution Place enabled
if len(self.places.all()) > 0:
return True
return False
@property @property
def total_price(self): def total_price(self):
price = 0 price = 0
@ -222,9 +226,6 @@ class Place(models.Model):
) )
description = models.TextField("Description", null=True, blank=True) description = models.TextField("Description", null=True, blank=True)
class Meta:
indexes = [models.Index(fields=["code"])]
def __str__(self): # pragma: no cover def __str__(self): # pragma: no cover
return self.name return self.name

View file

@ -345,19 +345,13 @@ class GroupedOrderExportView(UserIsOrgaMixin, generic.DetailView):
context["items"] = items context["items"] = items
context["orders_dict"] = orders_dict context["orders_dict"] = orders_dict
# Query the DB only once for this grouped order's places if grouped_order.has_places:
places = [x for x in grouped_order.places.all()]
if len(places) > 0:
# Initialize empty list of orders for every place enabled for this GroupedOrder # Initialize empty list of orders for every place enabled for this GroupedOrder
places_orders = {x.code: {} for x in places} places = {x.code: {} for x in grouped_order.places.all()}
for order, order_items in orders_dict.items(): for order, order_items in orders_dict.items():
places_orders[order.place.code][order] = order_items places[order.place.code][order] = order_items
context["places"] = places
# places contains the full places objects
# places_orders contains the order filtered by place.code
context["places"] = {x.code: x for x in places}
context["places_orders"] = places_orders
return context return context
@ -419,7 +413,7 @@ class ExportGroupedOrderToCSVView(GroupedOrderExportView):
row.append("Note") row.append("Note")
row.append("Date") row.append("Date")
row.append("Heure") row.append("Heure")
if "places" in context: if grouped_order.has_places:
row.append("Lieu") row.append("Lieu")
writer.writerow(row) writer.writerow(row)
@ -431,7 +425,8 @@ class ExportGroupedOrderToCSVView(GroupedOrderExportView):
row = ["Nom", "Prénom"] row = ["Nom", "Prénom"]
writer.writerow(row) writer.writerow(row)
def format_csv_order_row(order, ordered_items, place=None): # write ordered values rows
for order, ordered_items in context["orders_dict"].items():
row = [order.author.last_name] row = [order.author.last_name]
row.append(order.author.first_name) row.append(order.author.first_name)
for ordered_nb in ordered_items: for ordered_nb in ordered_items:
@ -442,23 +437,9 @@ class ExportGroupedOrderToCSVView(GroupedOrderExportView):
row.append(order.note) row.append(order.note)
row.append(order.created_date.strftime("%d/%m/%Y")) row.append(order.created_date.strftime("%d/%m/%Y"))
row.append(order.created_date.strftime("%H:%M")) row.append(order.created_date.strftime("%H:%M"))
if place: if grouped_order.has_places:
row.append(place.name) row.append(order.place.name)
return row writer.writerow(row)
# Write ordered values rows.
# Avoid extra queries by reusing GroupedOrderExportView context
if "places" in context:
for place_code, place_orders in context["places_orders"].items():
for order, ordered_items in place_orders.items():
row = format_csv_order_row(
order, ordered_items, place=context["places"][place_code]
)
writer.writerow(row)
else:
for order, ordered_items in context["orders_dict"].items():
row = format_csv_order_row(order, ordered_items)
writer.writerow(row)
# write total row # write total row
row = ["", "TOTAL"] row = ["", "TOTAL"]

View file

@ -48,27 +48,31 @@ def place_order(request, code):
email = request.POST["email"] email = request.POST["email"]
note = request.POST["note"] note = request.POST["note"]
# Make sure requested place is valid in this group order # Make sure requested place is valid in this group order (and exists at all)
# Query grouped order places only once to avoid many DB roundtrips # If no places are enabled for this group order, chosen place is always None
grouped_order_places = grouped_order.places.all() if grouped_order.has_places:
if len(grouped_order_places) > 0: # If places are enabled for the GroupedOrder
# Places are enabled for this grouped order, make sure one was supplied if "place" not in request.POST:
if "place" not in request.POST or request.POST["place"] == "": # HTTP error code 400
return http.HttpResponse( return http.HttpResponse(
"Aucun lieu n'est spécifié alors que la commande groupée en exige un", "Aucun lieu n'est spécifié alors que la commande groupée en exige un",
status=400, status=400,
) )
place = request.POST["place"] places = grouped_order.places.all()
try: # Return 404 if the requested place does not exist at all
# QuerySet is already queried from DB so this is a cheap operation. place = Place.objects.all().filter(code=request.POST["place"]).first()
# Could fail if no entry is found, or multiple entries are found if not place:
place = grouped_order_places.get(code=place)
except Exception as e:
# Return 404 because the requested place, whether it exists or not,
# is not enabled for this GroupedOrder
return http.HttpResponseNotFound( return http.HttpResponseNotFound(
"Le lieu demandé n'est pas valide pour cette commande: %s" % place "Le lieu spécifié n'a pas été trouvé dans la base de données: %s"
% request.POST["place"]
)
if place not in places:
# Return 404 is the requested place exists but is not enabled for this
# GroupedOrder instance
return http.HttpResponseNotFound(
"Le lieu demandé n'est pas valide pour cette commande: %s"
% request.POST["place"]
) )
else: else:
place = None place = None

View file

@ -158,6 +158,25 @@ class TestPlaceModel:
assert response.status_code == 302 assert response.status_code == 302
assert Place.objects.count() == 1 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): def test_place_active_orders(self, client_log):
now = timezone.now() now = timezone.now()

View file

@ -1549,11 +1549,9 @@ class TestGroupedOrderSheetView:
assert len(response.context["items"]) == 0 assert len(response.context["items"]) == 0
assert len(response.context["orders_dict"]) == 0 assert len(response.context["orders_dict"]) == 0
assert "places" in response.context.keys() assert "places" in response.context.keys()
assert "places_orders" in response.context.keys()
assert len(response.context["places"]) == 2 assert len(response.context["places"]) == 2
assert len(response.context["places_orders"]) == 2 assert len(response.context["places"]["kropotkine"]) == 0
assert len(response.context["places_orders"]["kropotkine"]) == 0 assert len(response.context["places"]["luxemburg"]) == 0
assert len(response.context["places_orders"]["luxemburg"]) == 0
# we order some items in the grouped order # we order some items in the grouped order
order = order_items_in_grouped_order(grouped_order, place=place2) order = order_items_in_grouped_order(grouped_order, place=place2)
@ -1566,11 +1564,11 @@ class TestGroupedOrderSheetView:
assert "places" in response.context.keys() assert "places" in response.context.keys()
# test that orders are split by distribution place # test that orders are split by distribution place
places_orders = response.context["places_orders"] places = response.context["places"]
assert len(places_orders["kropotkine"]) == 0 assert len(places["kropotkine"]) == 0
assert len(places_orders["luxemburg"]) == 3 assert len(places["luxemburg"]) == 3
orders = list(places_orders["luxemburg"]) orders = list(places["luxemburg"])
assert orders[0].author.last_name == "alescargot" assert orders[0].author.last_name == "alescargot"
assert orders[0].author.first_name == "bob" assert orders[0].author.first_name == "bob"
assert orders[1].author.last_name == "alescargot" assert orders[1].author.last_name == "alescargot"
@ -1706,7 +1704,6 @@ class TestExportGroupOrderEmailAdressesToDownloadView:
orga_user=auth.get_user(client_log), orga_user=auth.get_user(client_log),
) )
grouped_order.places.add(place.id) grouped_order.places.add(place.id)
grouped_order.save()
item = models.Item.objects.create( item = models.Item.objects.create(
name="test item 1", grouped_order=grouped_order, price=2 name="test item 1", grouped_order=grouped_order, price=2
) )