From 8b7cb213ca99801feb4b91d0ee8fa44aafa29279 Mon Sep 17 00:00:00 2001 From: Lars van Rhijn Date: Sun, 12 Nov 2023 11:20:55 +0100 Subject: [PATCH 1/5] Add start of status screen and add new picked up button --- website/orders/api/v1/serializers.py | 14 +- website/orders/api/v1/views.py | 4 +- ...0008_order_picked_up_order_picked_up_at.py | 28 ++++ website/orders/models.py | 21 ++- website/orders/services.py | 16 +- .../templates/orders/order_admin_list.html | 44 +++++- .../templates/orders/order_admin_order.html | 51 ++++--- .../templates/orders/status_screen.html | 95 ++++++++++++ website/orders/urls.py | 1 + website/orders/views.py | 11 ++ .../tosti/static/tosti/css/status-screen.css | 9 ++ website/tosti/templates/tosti/base.html | 142 +++++++++--------- 12 files changed, 334 insertions(+), 102 deletions(-) create mode 100644 website/orders/migrations/0008_order_picked_up_order_picked_up_at.py create mode 100644 website/orders/templates/orders/status_screen.html create mode 100644 website/tosti/static/tosti/css/status-screen.css diff --git a/website/orders/api/v1/serializers.py b/website/orders/api/v1/serializers.py index e00b5354..c9e3f7fc 100644 --- a/website/orders/api/v1/serializers.py +++ b/website/orders/api/v1/serializers.py @@ -108,10 +108,22 @@ class Meta: "ready_at", "paid", "paid_at", + "picked_up", + "picked_up_at", "type", "priority", ] - read_only_fields = ["id", "created", "user", "product", "order_price", "ready_at", "paid_at"] + read_only_fields = [ + "id", + "created", + "user", + "product", + "order_price", + "ready_at", + "paid_at", + "picked_up_at", + "prioritize", + ] class ShiftSerializer(WritableModelSerializer): diff --git a/website/orders/api/v1/views.py b/website/orders/api/v1/views.py index 863220f2..2cd16e3f 100644 --- a/website/orders/api/v1/views.py +++ b/website/orders/api/v1/views.py @@ -72,7 +72,7 @@ def perform_create(self, serializer): # Save the order while ignoring the order_type, user, paid and ready argument as the user does not have # permissions to save orders for all users in the shift. order = serializer.save( - shift=shift, type=Order.TYPE_ORDERED, user=self.request.user, paid=False, ready=False + shift=shift, type=Order.TYPE_ORDERED, user=self.request.user, paid=False, ready=False, picked_up=False ) log_action(self.request.user, order, CHANGE, "Created order via API.") @@ -108,6 +108,8 @@ class OrderRetrieveUpdateDestroyAPIView(LoggedRetrieveUpdateDestroyAPIView): "ready": {"type": "boolean"}, "paid": {"type": "boolean"}, "priority": {"type": "number"}, + "picked_up": {"type": "boolean"}, + "deprioritize": {"type": "boolean"}, }, } ) diff --git a/website/orders/migrations/0008_order_picked_up_order_picked_up_at.py b/website/orders/migrations/0008_order_picked_up_order_picked_up_at.py new file mode 100644 index 00000000..554576a0 --- /dev/null +++ b/website/orders/migrations/0008_order_picked_up_order_picked_up_at.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.4 on 2023-11-12 09:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("orders", "0007_order_deprioritize"), + ] + + operations = [ + migrations.AddField( + model_name="order", + name="picked_up", + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name="order", + name="picked_up_at", + field=models.DateTimeField(blank=True, null=True), + ), + migrations.AlterField( + model_name="order", + name="picked_up", + field=models.BooleanField(default=False), + ), + ] diff --git a/website/orders/models.py b/website/orders/models.py index 8bb84dd5..e3705ff7 100644 --- a/website/orders/models.py +++ b/website/orders/models.py @@ -438,7 +438,9 @@ def _clean(self): elif old_instance is not None and not old_instance.finalized and self.finalized: # Shift was not finalized yet but will be made finalized now if not self.shift_done: - raise ValidationError({"finalized": "Shift can't be finalized if not all Orders are paid and ready"}) + raise ValidationError( + {"finalized": "Shift can't be finalized if not all Orders are paid, ready and picked up."} + ) if self.end <= self.start: raise ValidationError({"end": "End date cannot be before start date."}) @@ -545,7 +547,10 @@ class Order(models.Model): paid = models.BooleanField(default=False) paid_at = models.DateTimeField(null=True, blank=True) - type = models.PositiveIntegerField(choices=TYPES, default=TYPE_ORDERED) + picked_up = models.BooleanField(default=False) + picked_up_at = models.DateTimeField(null=True, blank=True) + + type = models.PositiveIntegerField(choices=TYPES, default=0) priority = models.PositiveIntegerField(choices=PRIORITIES, default=PRIORITY_NORMAL) @@ -587,12 +592,22 @@ def venue(self): """ return self.shift.venue + @property + def completed(self) -> bool: + """ + Check if an Order is completed. + + :return: True if this Order is paid, ready and picked up, False otherwise. + :rtype: boolean + """ + return self.paid and self.ready and self.picked_up + @property def done(self): """ Check if an Order is done. - :return: True if this Order is paid and ready, False otherwise + :return: True if this Order is paid, ready and picked up, False otherwise :rtype: boolean """ return self.paid and self.ready diff --git a/website/orders/services.py b/website/orders/services.py index 37fdf0b5..9ec03709 100644 --- a/website/orders/services.py +++ b/website/orders/services.py @@ -56,7 +56,7 @@ def execute_data_minimisation(dry_run=False): return users -def add_scanned_order(product: Product, shift: Shift, ready=True, paid=True) -> Order: +def add_scanned_order(product: Product, shift: Shift, ready=True, paid=True, picked_up=True) -> Order: """ Add a single Scanned Order (of type TYPE_SCANNED). @@ -64,6 +64,7 @@ def add_scanned_order(product: Product, shift: Shift, ready=True, paid=True) -> :param shift: The shift for which the Orders have to be created :param ready: Whether the Order should be directly made ready :param paid: Whether the Order should be directly made paid + :param picked_up: Whether the Order should be directly made picked up :return: The created Order """ # Check if Shift is not finalized @@ -79,7 +80,14 @@ def add_scanned_order(product: Product, shift: Shift, ready=True, paid=True) -> raise OrderException("This Product is not available in this Shift") return Order.objects.create( - product=product, shift=shift, type=Order.TYPE_SCANNED, user=None, user_association=None, ready=ready, paid=paid + product=product, + shift=shift, + type=Order.TYPE_SCANNED, + user=None, + user_association=None, + ready=ready, + paid=paid, + picked_up=picked_up, ) @@ -90,6 +98,7 @@ def add_user_order( priority: int = Order.PRIORITY_NORMAL, paid: bool = False, ready: bool = False, + picked_up: bool = False, **kwargs, ) -> Order: """ @@ -101,6 +110,7 @@ def add_user_order( :param priority: Which priority the Order should have :param paid: Whether the order should be set as paid :param ready: Whether the order should be set as ready + :param picked_up: Whether the order should be set as picked up :return: The created Order """ # Check order permissions @@ -147,6 +157,8 @@ def add_user_order( paid=paid, ready=ready, priority=priority, + picked_up=picked_up, + priority=priority, ) diff --git a/website/orders/templates/orders/order_admin_list.html b/website/orders/templates/orders/order_admin_list.html index d70fb6d7..e007fda6 100644 --- a/website/orders/templates/orders/order_admin_list.html +++ b/website/orders/templates/orders/order_admin_list.html @@ -220,6 +220,20 @@

Orders total

}); return orders_ready; }, + orders_picked_up() { + return this.orders.filter(order => order.picked_up); + }, + orders_picked_up_grouped() { + let orders_picked_up = {}; + this.orders_picked_up.forEach(order => { + if (order.product.name in orders_picked_up) { + orders_picked_up[order.product.name].amount += 1; + } else { + orders_picked_up[order.product.name] = {"product": order.product, "amount": 1}; + } + }); + return orders_picked_up; + }, orders_grouped() { let orders_total = {}; this.orders.forEach(order => { @@ -232,10 +246,10 @@

Orders total

return orders_total; }, orders_finished() { - return this.orders.filter(order => order.ready && order.paid && order.type !== 1); + return this.orders.filter(order => order.ready && order.paid && order.picked_up && order.type !== 1); }, orders_to_process() { - return this.orders.filter(order => !order.ready || !order.paid && order.type !== 1); + return this.orders.filter(order => !order.ready || !order.picked_up || !order.paid && order.type !== 1); }, orders_scanned() { return this.orders.filter(order => order.type === 1); @@ -378,6 +392,32 @@

Orders total

} }).catch(error => show_error_from_api(error)); }, + toggle_picked_up(order) { + fetch( + `/api/v1/shifts/{{ shift.id }}/orders/${order.id}/`, + { + method: 'PATCH', + headers: { + "X-CSRFToken": get_csrf_token(), + "Accept": 'application/json', + "Content-Type": 'application/json', + }, + body: JSON.stringify({ + picked_up: !order.picked_up + }) + } + ).then(response => { + if (response.status === 200) { + return response; + } else { + throw response; + } + }).then(() => { + if (typeof (update_refresh_list) !== 'undefined') { + update_refresh_list(); + } + }).catch(error => show_error_from_api(error)); + }, delete_order(order) { if (window.confirm('Do you want to delete this order?')) { fetch( diff --git a/website/orders/templates/orders/order_admin_order.html b/website/orders/templates/orders/order_admin_order.html index 20d94fff..a7b4cf18 100644 --- a/website/orders/templates/orders/order_admin_order.html +++ b/website/orders/templates/orders/order_admin_order.html @@ -1,30 +1,37 @@ \ No newline at end of file diff --git a/website/orders/templates/orders/status_screen.html b/website/orders/templates/orders/status_screen.html new file mode 100644 index 00000000..e425ea52 --- /dev/null +++ b/website/orders/templates/orders/status_screen.html @@ -0,0 +1,95 @@ +{% extends 'tosti/base.html' %} +{% load static %} + +{% block styles %} + +{% endblock %} + +{% block header %} + +{% endblock %} + +{% block page %} +
+
+
+

In progress

+
+
+

Ready

+
+
+
+{% endblock %} + +{% block footer %} + +{% endblock %} + +{% block js %} + +{% endblock %} \ No newline at end of file diff --git a/website/orders/urls.py b/website/orders/urls.py index fbb6ca6d..66f261cb 100644 --- a/website/orders/urls.py +++ b/website/orders/urls.py @@ -12,4 +12,5 @@ path("/admin/", views.ShiftManagementView.as_view(), name="shift_admin"), path("/overview/", views.ShiftView.as_view(), name="shift_overview"), path("/join/", views.JoinShiftView.as_view(), name="shift_join"), + path("/status/", views.StatusScreen.as_view(), name="status"), ] diff --git a/website/orders/views.py b/website/orders/views.py index 41680424..53f8e7c7 100644 --- a/website/orders/views.py +++ b/website/orders/views.py @@ -145,6 +145,17 @@ def post(self, request, **kwargs): return render(request, self.template_name, {"shift": shift}) +class StatusScreen(TemplateView): + """Status screen for a Shift.""" + + template_name = "orders/status_screen.html" + + def get(self, request, **kwargs): + """GET request for status screen view.""" + shift = kwargs.get("shift") + return render(request, self.template_name, {"shift": shift}) + + class AccountHistoryTabView(LoginRequiredMixin, TemplateView): """Account order history view.""" diff --git a/website/tosti/static/tosti/css/status-screen.css b/website/tosti/static/tosti/css/status-screen.css new file mode 100644 index 00000000..217befab --- /dev/null +++ b/website/tosti/static/tosti/css/status-screen.css @@ -0,0 +1,9 @@ +.site-header { + height: 84px; +} + +@media screen and (max-width: 992px) { + .site-header { + height: 59px; + } +} \ No newline at end of file diff --git a/website/tosti/templates/tosti/base.html b/website/tosti/templates/tosti/base.html index 6f4f1749..c2959625 100644 --- a/website/tosti/templates/tosti/base.html +++ b/website/tosti/templates/tosti/base.html @@ -185,6 +185,77 @@

Identify yourself


+ {% endblock %}
{% block page %}{% endblock %} @@ -204,76 +275,5 @@

Identify yourself


{% block js %}{% endblock %} - From db9b5dce4658ad20f61252e81f41960d7c247bcb Mon Sep 17 00:00:00 2001 From: Lars van Rhijn Date: Sun, 10 Mar 2024 10:58:07 +0100 Subject: [PATCH 2/5] Add actual orders to the screen --- website/orders/api/v1/filters.py | 1 + website/orders/api/v1/views.py | 8 +-- ...009_order_picked_up_order_picked_up_at.py} | 12 +--- website/orders/models.py | 2 +- website/orders/services.py | 1 - .../static/orders}/css/status-screen.css | 7 ++ .../templates/orders/status_screen.html | 69 +++++++++++++++++-- 7 files changed, 77 insertions(+), 23 deletions(-) rename website/orders/migrations/{0008_order_picked_up_order_picked_up_at.py => 0009_order_picked_up_order_picked_up_at.py} (64%) rename website/{tosti/static/tosti => orders/static/orders}/css/status-screen.css (51%) diff --git a/website/orders/api/v1/filters.py b/website/orders/api/v1/filters.py index 4d92cfd1..ca02cec6 100644 --- a/website/orders/api/v1/filters.py +++ b/website/orders/api/v1/filters.py @@ -54,6 +54,7 @@ class Meta: ), "ready": ("exact",), "paid": ("exact",), + "picked_up": ("exact",), "type": ("exact",), "product": ("exact",), } diff --git a/website/orders/api/v1/views.py b/website/orders/api/v1/views.py index 2cd16e3f..5046aaea 100644 --- a/website/orders/api/v1/views.py +++ b/website/orders/api/v1/views.py @@ -42,10 +42,9 @@ class OrderListCreateAPIView(ListCreateAPIView): "GET": ["orders:order"], "POST": ["orders:manage"], } - filter_backends = [ - django_filters.rest_framework.DjangoFilterBackend, - ] + filter_backends = [django_filters.rest_framework.DjangoFilterBackend, filters.OrderingFilter] filterset_class = OrderFilter + ordering_fields = ["paid_at", "ready_at", "picked_up_at"] queryset = Order.objects.select_related("user", "product") def get_queryset(self): @@ -107,9 +106,8 @@ class OrderRetrieveUpdateDestroyAPIView(LoggedRetrieveUpdateDestroyAPIView): "properties": { "ready": {"type": "boolean"}, "paid": {"type": "boolean"}, - "priority": {"type": "number"}, "picked_up": {"type": "boolean"}, - "deprioritize": {"type": "boolean"}, + "priority": {"type": "number"}, }, } ) diff --git a/website/orders/migrations/0008_order_picked_up_order_picked_up_at.py b/website/orders/migrations/0009_order_picked_up_order_picked_up_at.py similarity index 64% rename from website/orders/migrations/0008_order_picked_up_order_picked_up_at.py rename to website/orders/migrations/0009_order_picked_up_order_picked_up_at.py index 554576a0..775996ea 100644 --- a/website/orders/migrations/0008_order_picked_up_order_picked_up_at.py +++ b/website/orders/migrations/0009_order_picked_up_order_picked_up_at.py @@ -1,28 +1,22 @@ -# Generated by Django 4.2.4 on 2023-11-12 09:32 +# Generated by Django 4.2.9 on 2024-03-10 09:10 from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ("orders", "0007_order_deprioritize"), + ("orders", "0008_order_priority"), ] operations = [ migrations.AddField( model_name="order", name="picked_up", - field=models.BooleanField(default=True), + field=models.BooleanField(default=False), ), migrations.AddField( model_name="order", name="picked_up_at", field=models.DateTimeField(blank=True, null=True), ), - migrations.AlterField( - model_name="order", - name="picked_up", - field=models.BooleanField(default=False), - ), ] diff --git a/website/orders/models.py b/website/orders/models.py index e3705ff7..8f5f1831 100644 --- a/website/orders/models.py +++ b/website/orders/models.py @@ -550,7 +550,7 @@ class Order(models.Model): picked_up = models.BooleanField(default=False) picked_up_at = models.DateTimeField(null=True, blank=True) - type = models.PositiveIntegerField(choices=TYPES, default=0) + type = models.PositiveIntegerField(choices=TYPES, default=TYPE_ORDERED) priority = models.PositiveIntegerField(choices=PRIORITIES, default=PRIORITY_NORMAL) diff --git a/website/orders/services.py b/website/orders/services.py index 9ec03709..acf21bfa 100644 --- a/website/orders/services.py +++ b/website/orders/services.py @@ -156,7 +156,6 @@ def add_user_order( user_association=user.association, paid=paid, ready=ready, - priority=priority, picked_up=picked_up, priority=priority, ) diff --git a/website/tosti/static/tosti/css/status-screen.css b/website/orders/static/orders/css/status-screen.css similarity index 51% rename from website/tosti/static/tosti/css/status-screen.css rename to website/orders/static/orders/css/status-screen.css index 217befab..eba9e4bb 100644 --- a/website/tosti/static/tosti/css/status-screen.css +++ b/website/orders/static/orders/css/status-screen.css @@ -2,6 +2,13 @@ height: 84px; } +.order-list { + font-size: 30pt; + list-style-type: none; + padding-inline-start: unset; + padding: unset; +} + @media screen and (max-width: 992px) { .site-header { height: 59px; diff --git a/website/orders/templates/orders/status_screen.html b/website/orders/templates/orders/status_screen.html index e425ea52..b21cd7e6 100644 --- a/website/orders/templates/orders/status_screen.html +++ b/website/orders/templates/orders/status_screen.html @@ -2,7 +2,7 @@ {% load static %} {% block styles %} - + {% endblock %} {% block header %} @@ -26,12 +26,39 @@

In progress

+ +
  • + #${ order.id }$ - ${ order.product.name }$ +
  • +

    Ready

    + +
  • + #${ order.id }$ - ${ order.product.name }$ +
  • +
    + {% endblock %} {% block footer %} @@ -43,8 +70,10 @@

    Ready

    const STATUS_SCREEN_CONTAINER_ID = "status-screen-container"; const statusScreenApp = createApp({ + delimiters: ['${', '}$'], data() { return { + orders: [], refreshing: false, refreshTimer: null, lastRefresh: null, @@ -58,17 +87,28 @@

    Ready

    unmounted() { document.removeEventListener("visibilitychange", this.visibilityChange); }, + computed: { + orders_in_progress() { + return this.orders.filter(order => { + return order.ready === false; + }); + }, + orders_ready() { + return this.orders.filter(order => { + return order.ready === true; + }); + }, + }, methods: { visibilityChange(event) { if (event.target.hidden) { clearTimeout(this.refreshTimer); } else { clearTimeout(this.refreshTimer); - this.recalculate_progress_interval = setInterval(this.updateTrackProgress, 100); if (this.lastRefresh === null || (new Date()).getTime() - this.lastRefresh > 5000) { this.refresh(); } else { - this.refreshTimer = setTimeout(this.refresh, this.track_progress_percentage === 100 ? 1000 : 5000); + this.refreshTimer = setTimeout(this.refresh, 5000); } } }, @@ -80,16 +120,31 @@

    Ready

    clearTimeout(this.refreshTimer); this.refreshing = true; return fetch( - + `/api/v1/shifts/{{ shift.id }}/orders/?type=0&picked_up=false&ordering=ready_at`, + { + method: 'GET', + headers: { + "X-CSRFToken": get_csrf_token(), + "Accept": 'application/json', + } + } + ).then(response => { + if (response.status === 200) { + return response.json(); + } else { + throw response; + } + }).then(data => { + this.orders = data; }).catch(error => { - console.log(`An error occurred while refreshing player {{ player.id }}. Error: ${error}`) + console.log(`An error occurred while refreshing orders for shift {{ shift.id }}. Error: ${error}`) }).finally(() => { this.lastRefresh = (new Date()).getTime(); this.refreshing = false; - this.refresh_timer = setTimeout(this.refresh, this.track_progress_percentage === 100 ? 1000 : 5000); + this.refresh_timer = setTimeout(this.refresh, 5000); }); } } - }).mount('#qrcode'); + }).mount(`#${STATUS_SCREEN_CONTAINER_ID}`); {% endblock %} \ No newline at end of file From 9891f975ae117ab10a7502e5d06b543ea034a562 Mon Sep 17 00:00:00 2001 From: Lars van Rhijn Date: Mon, 18 Mar 2024 20:02:25 +0100 Subject: [PATCH 3/5] Change interface of status screen --- .../static/orders/css/status-screen.css | 29 +++++++++++- .../templates/orders/status_screen.html | 47 ++++++++++++++++--- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/website/orders/static/orders/css/status-screen.css b/website/orders/static/orders/css/status-screen.css index eba9e4bb..f8816bbe 100644 --- a/website/orders/static/orders/css/status-screen.css +++ b/website/orders/static/orders/css/status-screen.css @@ -2,11 +2,38 @@ height: 84px; } -.order-list { +.user-order-list { font-size: 30pt; list-style-type: none; padding-inline-start: unset; padding: unset; + display: flex; + justify-content: center; + align-content: flex-start; + gap: 10px; + flex-wrap: wrap; +} + +.user-order-list li.user-order-item { + display: inline-flex; + background-color: var(--primary); + border-radius: 15px; + padding: 10px 15px; + justify-content: center; +} + +.user-order-list li .order-user-name { + margin-right: 20px; +} + +.order-list { + list-style-type: none; + padding-inline-start: unset; + padding: unset; +} + +.order-list li.order-item { + display: inline; } @media screen and (max-width: 992px) { diff --git a/website/orders/templates/orders/status_screen.html b/website/orders/templates/orders/status_screen.html index b21cd7e6..9eb9fbe2 100644 --- a/website/orders/templates/orders/status_screen.html +++ b/website/orders/templates/orders/status_screen.html @@ -26,17 +26,29 @@

    In progress

    - -
  • - #${ order.id }$ - ${ order.product.name }$ + +
  • +
    ${user_orders_object.user.first_name}$
    +
      +
    • + + +
    • +
  • Ready

    - -
  • - #${ order.id }$ - ${ order.product.name }$ + +
  • +
    ${user_orders_object.user.first_name}$
    +
      +
    • + + +
    • +
  • @@ -88,6 +100,12 @@

    Ready

    document.removeEventListener("visibilitychange", this.visibilityChange); }, computed: { + orders_in_progress_grouped_user() { + return this.map_orders_by_user(this.orders_in_progress); + }, + orders_ready_grouped_user() { + return this.map_orders_by_user(this.orders_ready); + }, orders_in_progress() { return this.orders.filter(order => { return order.ready === false; @@ -100,6 +118,23 @@

    Ready

    }, }, methods: { + map_orders_by_user(orders) { + let orders_mapped_user = {}; + for (let i = 0; i < orders.length; i++) { + let order = orders[i]; + let user_id = order['user']['id']; + let user = order['user']; + if (user_id in orders_mapped_user) { + orders_mapped_user[user_id]['orders'].push(order); + } else { + orders_mapped_user[user_id] = { + 'orders': [order], + 'user': user, + } + } + } + return orders_mapped_user; + }, visibilityChange(event) { if (event.target.hidden) { clearTimeout(this.refreshTimer); From 566d3ac90d3842329ff35382f85e8331d6306d05 Mon Sep 17 00:00:00 2001 From: Lars van Rhijn Date: Sun, 28 Apr 2024 21:59:35 +0200 Subject: [PATCH 4/5] Move status screen to its own app --- pyproject.toml | 6 +++--- ...y => 0003_order_picked_up_order_picked_up_at.py} | 5 +++-- website/orders/urls.py | 1 - website/orders/views.py | 11 ----------- website/status_screen/__init__.py | 0 website/status_screen/apps.py | 8 ++++++++ website/status_screen/migrations/__init__.py | 0 .../static/status_screen}/css/status-screen.css | 0 .../templates/status_screen}/status_screen.html | 2 +- website/status_screen/urls.py | 7 +++++++ website/status_screen/views.py | 13 +++++++++++++ website/tosti/settings/base.py | 6 ++++-- website/tosti/urls.py | 4 ++++ 13 files changed, 43 insertions(+), 20 deletions(-) rename website/orders/migrations/{0009_order_picked_up_order_picked_up_at.py => 0003_order_picked_up_order_picked_up_at.py} (83%) create mode 100644 website/status_screen/__init__.py create mode 100644 website/status_screen/apps.py create mode 100644 website/status_screen/migrations/__init__.py rename website/{orders/static/orders => status_screen/static/status_screen}/css/status-screen.css (100%) rename website/{orders/templates/orders => status_screen/templates/status_screen}/status_screen.html (98%) create mode 100644 website/status_screen/urls.py create mode 100644 website/status_screen/views.py diff --git a/pyproject.toml b/pyproject.toml index a729fcb8..3aef89a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,7 +53,7 @@ sentry-sdk = "^1.14.0" [tool.black] line-length = 119 -target-version = ["py310"] +target-version = ["py311"] exclude = ''' /( migrations @@ -62,5 +62,5 @@ exclude = ''' ''' [build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/website/orders/migrations/0009_order_picked_up_order_picked_up_at.py b/website/orders/migrations/0003_order_picked_up_order_picked_up_at.py similarity index 83% rename from website/orders/migrations/0009_order_picked_up_order_picked_up_at.py rename to website/orders/migrations/0003_order_picked_up_order_picked_up_at.py index 775996ea..6a5eb9a5 100644 --- a/website/orders/migrations/0009_order_picked_up_order_picked_up_at.py +++ b/website/orders/migrations/0003_order_picked_up_order_picked_up_at.py @@ -1,11 +1,12 @@ -# Generated by Django 4.2.9 on 2024-03-10 09:10 +# Generated by Django 5.0.4 on 2024-04-28 19:53 from django.db import migrations, models class Migration(migrations.Migration): + dependencies = [ - ("orders", "0008_order_priority"), + ("orders", "0002_initial"), ] operations = [ diff --git a/website/orders/urls.py b/website/orders/urls.py index 66f261cb..fbb6ca6d 100644 --- a/website/orders/urls.py +++ b/website/orders/urls.py @@ -12,5 +12,4 @@ path("/admin/", views.ShiftManagementView.as_view(), name="shift_admin"), path("/overview/", views.ShiftView.as_view(), name="shift_overview"), path("/join/", views.JoinShiftView.as_view(), name="shift_join"), - path("/status/", views.StatusScreen.as_view(), name="status"), ] diff --git a/website/orders/views.py b/website/orders/views.py index 53f8e7c7..41680424 100644 --- a/website/orders/views.py +++ b/website/orders/views.py @@ -145,17 +145,6 @@ def post(self, request, **kwargs): return render(request, self.template_name, {"shift": shift}) -class StatusScreen(TemplateView): - """Status screen for a Shift.""" - - template_name = "orders/status_screen.html" - - def get(self, request, **kwargs): - """GET request for status screen view.""" - shift = kwargs.get("shift") - return render(request, self.template_name, {"shift": shift}) - - class AccountHistoryTabView(LoginRequiredMixin, TemplateView): """Account order history view.""" diff --git a/website/status_screen/__init__.py b/website/status_screen/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/website/status_screen/apps.py b/website/status_screen/apps.py new file mode 100644 index 00000000..dad9fa38 --- /dev/null +++ b/website/status_screen/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig + + +class StatusScreenConfig(AppConfig): + """Status Screen App Config.""" + + default_auto_field = "django.db.models.BigAutoField" + name = "status_screen" diff --git a/website/status_screen/migrations/__init__.py b/website/status_screen/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/website/orders/static/orders/css/status-screen.css b/website/status_screen/static/status_screen/css/status-screen.css similarity index 100% rename from website/orders/static/orders/css/status-screen.css rename to website/status_screen/static/status_screen/css/status-screen.css diff --git a/website/orders/templates/orders/status_screen.html b/website/status_screen/templates/status_screen/status_screen.html similarity index 98% rename from website/orders/templates/orders/status_screen.html rename to website/status_screen/templates/status_screen/status_screen.html index 9eb9fbe2..fcf28ee1 100644 --- a/website/orders/templates/orders/status_screen.html +++ b/website/status_screen/templates/status_screen/status_screen.html @@ -2,7 +2,7 @@ {% load static %} {% block styles %} - + {% endblock %} {% block header %} diff --git a/website/status_screen/urls.py b/website/status_screen/urls.py new file mode 100644 index 00000000..96833e73 --- /dev/null +++ b/website/status_screen/urls.py @@ -0,0 +1,7 @@ +from django.urls import path + +from status_screen import views + +urlpatterns = [ + path("/", views.StatusScreen.as_view(), name="status"), +] diff --git a/website/status_screen/views.py b/website/status_screen/views.py new file mode 100644 index 00000000..a6278a2f --- /dev/null +++ b/website/status_screen/views.py @@ -0,0 +1,13 @@ +from django.shortcuts import render +from django.views.generic import TemplateView + + +class StatusScreen(TemplateView): + """Status screen for a Shift.""" + + template_name = "status_screen/status_screen.html" + + def get(self, request, **kwargs): + """GET request for status screen view.""" + shift = kwargs.get("shift") + return render(request, self.template_name, {"shift": shift}) diff --git a/website/tosti/settings/base.py b/website/tosti/settings/base.py index 547dc47e..46b28b3d 100644 --- a/website/tosti/settings/base.py +++ b/website/tosti/settings/base.py @@ -37,6 +37,7 @@ "transactions", "orders", "silvasoft", + "status_screen", "oauth2_provider", "corsheaders", "yivi", @@ -195,7 +196,8 @@ ), "VENUES_SEND_RESERVATION_REQUEST_EMAILS_TO": ( "noreply@example.com, noreply@example.com", - "Where to send venue reservation request notifications to (e-mail address), enter multiple addresses by using a comma (,)", + "Where to send venue reservation request notifications to (e-mail address), enter multiple addresses by using " + "a comma (,)", str, ), "SHIFTS_DEFAULT_MAX_ORDERS_TOTAL": (70, "Default maximum number of orders per shift", int), @@ -282,4 +284,4 @@ AGE_VERIFICATION_INSTITUTE_VALUE = "ru.nl" YIVI_SERVER_URL = os.environ.get("YIVI_SERVER_URL") -YIVI_SERVER_TOKEN = os.environ.get("YIVI_SERVER_TOKEN") \ No newline at end of file +YIVI_SERVER_TOKEN = os.environ.get("YIVI_SERVER_TOKEN") diff --git a/website/tosti/urls.py b/website/tosti/urls.py index 5514de71..24c18fe7 100644 --- a/website/tosti/urls.py +++ b/website/tosti/urls.py @@ -50,6 +50,10 @@ "fridges/", include(("fridges.urls", "fridges"), namespace="fridges"), ), + path( + "status/", + include(("status_screen.urls", "status_screen"), namespace="status_screen"), + ), path("api/", include("tosti.api.urls")), path("saml/", include("djangosaml2.urls")), path( From fe199fb4907aa1ffbd6fe35354cd2783541d8b0c Mon Sep 17 00:00:00 2001 From: Lars van Rhijn Date: Mon, 3 Jun 2024 16:38:13 +0200 Subject: [PATCH 5/5] Add redirect view to redirect to current status screen --- website/borrel/urls.py | 5 +---- .../status_screen/status_screen.html | 2 +- website/status_screen/urls.py | 1 + website/status_screen/views.py | 20 ++++++++++++++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/website/borrel/urls.py b/website/borrel/urls.py index ca7d64ed..116e80dc 100644 --- a/website/borrel/urls.py +++ b/website/borrel/urls.py @@ -1,9 +1,6 @@ -from django.urls import path, register_converter +from django.urls import path from borrel import views -from venues.converters import VenueConverter - -register_converter(VenueConverter, "venue") urlpatterns = [ diff --git a/website/status_screen/templates/status_screen/status_screen.html b/website/status_screen/templates/status_screen/status_screen.html index fcf28ee1..d65879a5 100644 --- a/website/status_screen/templates/status_screen/status_screen.html +++ b/website/status_screen/templates/status_screen/status_screen.html @@ -155,7 +155,7 @@

    Ready

    clearTimeout(this.refreshTimer); this.refreshing = true; return fetch( - `/api/v1/shifts/{{ shift.id }}/orders/?type=0&picked_up=false&ordering=ready_at`, + "{% url 'v1:orders_listcreate' shift=shift %}?type=0&picked_up=false&ordering=ready_at", { method: 'GET', headers: { diff --git a/website/status_screen/urls.py b/website/status_screen/urls.py index 96833e73..cc8d1313 100644 --- a/website/status_screen/urls.py +++ b/website/status_screen/urls.py @@ -3,5 +3,6 @@ from status_screen import views urlpatterns = [ + path("redirect//", views.VenueRedirectView.as_view(), name="venue-redirect"), path("/", views.StatusScreen.as_view(), name="status"), ] diff --git a/website/status_screen/views.py b/website/status_screen/views.py index a6278a2f..7196f1d6 100644 --- a/website/status_screen/views.py +++ b/website/status_screen/views.py @@ -1,6 +1,11 @@ -from django.shortcuts import render +from django.http import Http404 +from django.shortcuts import render, redirect +from django.urls import reverse +from django.views import View from django.views.generic import TemplateView +from orders.templatetags.start_shift import currently_active_shift_for_venue + class StatusScreen(TemplateView): """Status screen for a Shift.""" @@ -11,3 +16,16 @@ def get(self, request, **kwargs): """GET request for status screen view.""" shift = kwargs.get("shift") return render(request, self.template_name, {"shift": shift}) + + +class VenueRedirectView(View): + """Redirect to the current shift of a venue.""" + + def get(self, request, **kwargs): + """Redirect a user to the active status screen of a shift.""" + venue = kwargs.get("venue") + shift = currently_active_shift_for_venue(venue) + if shift is None: + raise Http404() + else: + return redirect(reverse("status_screen:status", kwargs={"shift": shift}))