Skip to content

Commit 7310e81

Browse files
committed
Mark orders as seen and prioritized from the dashboard
1 parent 01713f6 commit 7310e81

File tree

8 files changed

+178
-41
lines changed

8 files changed

+178
-41
lines changed

src/genlab_bestilling/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ class OrderStatus(models.TextChoices):
243243
# COMPLETED: Order has been completed, and results are available.
244244
COMPLETED = "completed", _("Completed")
245245

246+
class OrderPriority:
247+
URGENT = 3
248+
PRIORITIZED = 2
249+
NORMAL = 1
250+
246251
STATUS_ORDER = (
247252
OrderStatus.DRAFT,
248253
OrderStatus.DELIVERED,

src/staff/tables.py

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,6 @@ class Meta:
303303
empty_text = "No Plates"
304304

305305

306-
FLAG_OUTLINE = "<i class='fa-regular fa-flag fa-lg' title='Normal'></i>"
307-
FLAG_FILLED = "<i class='fa-solid fa-flag fa-lg' title='Prioritized'></i>"
308-
URGENT_FILLED = (
309-
"<i class='fa-solid fa-exclamation fa-lg text-red-500' title='Urgent'></i>"
310-
)
311-
312-
313306
class StatusMixinTable(tables.Table):
314307
status = tables.Column(
315308
orderable=False,
@@ -373,7 +366,14 @@ class Meta:
373366
template_name = "django_tables2/tailwind_inner.html"
374367

375368

376-
class NewOrderTable(StaffIDMixinTable):
369+
class NewUnseenOrderTable(StaffIDMixinTable):
370+
seen = tables.TemplateColumn(
371+
orderable=False,
372+
verbose_name="Seen",
373+
template_name="staff/components/seen_column.html",
374+
empty_values=(),
375+
)
376+
377377
description = tables.Column(
378378
accessor="genrequest__name",
379379
verbose_name="Description",
@@ -404,22 +404,61 @@ def render_samples(self, value: int) -> str:
404404

405405
class Meta:
406406
model = Order
407-
fields = ["id", "description", "delivery_date", "samples"]
408-
empty_text = "No new orders"
407+
fields = ["id", "description", "delivery_date", "samples", "seen"]
408+
empty_text = "No new unseen orders"
409409
template_name = "django_tables2/tailwind_inner.html"
410410

411411

412-
class AssignedOrderTable(StatusMixinTable, StaffIDMixinTable):
413-
priority = tables.Column(
412+
class NewSeenOrderTable(StaffIDMixinTable):
413+
priority = tables.TemplateColumn(
414414
orderable=False,
415415
verbose_name="Priority",
416-
accessor="is_urgent",
416+
accessor="priority",
417+
template_name="staff/components/priority_column.html",
417418
)
418419

419-
def render_priority(self, value: bool) -> str:
420+
description = tables.Column(
421+
accessor="genrequest__name",
422+
verbose_name="Description",
423+
orderable=False,
424+
)
425+
426+
delivery_date = tables.Column(
427+
accessor="genrequest__expected_samples_delivery_date",
428+
verbose_name="Delivery date",
429+
orderable=False,
430+
)
431+
432+
def render_delivery_date(self, value: Any) -> str:
420433
if value:
421-
return mark_safe(URGENT_FILLED) # noqa: S308
422-
return ""
434+
return value.strftime("%d/%m/%Y")
435+
return "-"
436+
437+
samples = tables.Column(
438+
accessor="sample_count",
439+
verbose_name="Samples",
440+
orderable=False,
441+
)
442+
443+
def render_samples(self, value: int) -> str:
444+
if value > 0:
445+
return str(value)
446+
return "-"
447+
448+
class Meta:
449+
model = Order
450+
fields = ["priority", "id", "description", "delivery_date", "samples"]
451+
empty_text = "No new seen orders"
452+
template_name = "django_tables2/tailwind_inner.html"
453+
454+
455+
class AssignedOrderTable(StatusMixinTable, StaffIDMixinTable):
456+
priority = tables.TemplateColumn(
457+
orderable=False,
458+
verbose_name="Priority",
459+
accessor="priority",
460+
template_name="staff/components/priority_column.html",
461+
)
423462

424463
samples_completed = tables.Column(
425464
accessor="sample_count",
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{% if value == 3 %}
2+
<i class="fa-solid fa-exclamation fa-lg text-red-500" title="Urgent"></i>
3+
{% else %}
4+
<form method="post" action="{% url 'staff:order-priority' pk=record.pk %}">
5+
{% csrf_token %}
6+
7+
{% comment %}Outlined flag icon does not work using the <i></i> tag, so also using the SVG for the filled flag icon for consistency. If it can be fixed in the future it should.{% endcomment %}
8+
9+
<button title="Mark as prioritized">
10+
{% if value == 2 %}
11+
<svg class="size-4 fill-blue-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
12+
<path d="M64 32C64 14.3 49.7 0 32 0S0 14.3 0 32L0 64 0 368 0 480c0 17.7 14.3 32 32 32s32-14.3 32-32l0-128 64.3-16.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30l0-247.7c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L64 48l0-16z" />
13+
</svg>
14+
{% else %}
15+
<svg class="size-4 stroke-gray-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
16+
<path d="M48 24C48 10.7 37.3 0 24 0S0 10.7 0 24L0 64 0 350.5 0 400l0 88c0 13.3 10.7 24 24 24s24-10.7 24-24l0-100 80.3-20.1c41.1-10.3 84.6-5.5 122.5 13.4c44.2 22.1 95.5 24.8 141.7 7.4l34.7-13c12.5-4.7 20.8-16.6 20.8-30l0-279.7c0-23-24.2-38-44.8-27.7l-9.6 4.8c-46.3 23.2-100.8 23.2-147.1 0c-35.1-17.6-75.4-22-113.5-12.5L48 52l0-28zm0 77.5l96.6-24.2c27-6.7 55.5-3.6 80.4 8.8c54.9 27.4 118.7 29.7 175 6.8l0 241.8-24.4 9.1c-33.7 12.6-71.2 10.7-103.4-5.4c-48.2-24.1-103.3-30.1-155.6-17.1L48 338.5l0-237z" />
17+
</svg>
18+
{% endif %}
19+
</button>
20+
</form>
21+
{% endif %}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<form method="post" action="{% url 'staff:order-seen' pk=record.pk %}">
2+
{% csrf_token %}
3+
<input title="Mark as seen" onchange="this.form.submit()" type="checkbox" class="size-4 border rounded" />
4+
</form>

src/staff/templates/staff/dashboard.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
<div class="grid grid-cols-2 gap-4">
2525
<div class="flex flex-col gap-8">
2626
{% urgent_orders_table area=area %}
27-
{% new_orders_table area=area %}
27+
{% new_unseen_orders_table area=area %}
28+
{% new_seen_orders_table area=area %}
2829
</div>
2930

3031
<div class="flex flex-col gap-8">

src/staff/templatetags/order_tags.py

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,30 @@
33

44
from genlab_bestilling.models import Area, Order
55

6-
from ..tables import AssignedOrderTable, NewOrderTable, UrgentOrderTable
6+
from ..tables import (
7+
AssignedOrderTable,
8+
NewSeenOrderTable,
9+
NewUnseenOrderTable,
10+
UrgentOrderTable,
11+
)
712

813
register = template.Library()
914

1015

1116
@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
1217
def urgent_orders_table(context: dict, area: Area | None = None) -> dict:
13-
urgent_orders = Order.objects.filter(
14-
is_urgent=True,
15-
status__in=[Order.OrderStatus.PROCESSING, Order.OrderStatus.DELIVERED],
16-
).select_related("genrequest")
18+
urgent_orders = (
19+
Order.objects.filter(
20+
is_urgent=True,
21+
)
22+
.exclude(status=Order.OrderStatus.DRAFT)
23+
.select_related("genrequest")
24+
)
1725

1826
if area:
1927
urgent_orders = urgent_orders.filter(genrequest__area=area)
2028

21-
urgent_orders = urgent_orders.only(
22-
"id", "genrequest__name", "genrequest__expected_samples_delivery_date", "status"
23-
).order_by(
29+
urgent_orders = urgent_orders.order_by(
2430
models.Case(
2531
models.When(status=Order.OrderStatus.PROCESSING, then=0),
2632
models.When(status=Order.OrderStatus.DELIVERED, then=1),
@@ -40,18 +46,43 @@ def urgent_orders_table(context: dict, area: Area | None = None) -> dict:
4046

4147

4248
@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
43-
def new_orders_table(context: dict, area: Area | None = None) -> dict:
49+
def new_seen_orders_table(context: dict, area: Area | None = None) -> dict:
4450
new_orders = (
45-
Order.objects.filter(status=Order.OrderStatus.DELIVERED)
51+
Order.objects.filter(status=Order.OrderStatus.DELIVERED, is_seen=True)
52+
.exclude(is_urgent=True)
4653
.select_related("genrequest")
47-
.annotate(sample_count=models.Count("extractionorder__samples"))
48-
.only(
49-
"id",
50-
"genrequest__name",
51-
"genrequest__expected_samples_delivery_date",
52-
"status",
54+
.annotate(
55+
sample_count=models.Count("extractionorder__samples"),
5356
)
54-
.order_by("status")
57+
.annotate(
58+
priority=models.Case(
59+
models.When(is_urgent=True, then=Order.OrderPriority.URGENT),
60+
models.When(is_prioritized=True, then=Order.OrderPriority.PRIORITIZED),
61+
default=1,
62+
)
63+
)
64+
)
65+
66+
if area:
67+
new_orders = new_orders.filter(genrequest__area=area)
68+
69+
new_orders = new_orders.order_by("-priority", "-created_at")
70+
71+
return {
72+
"title": "New seen orders",
73+
"table": NewSeenOrderTable(new_orders),
74+
"count": new_orders.count(),
75+
"request": context.get("request"),
76+
}
77+
78+
79+
@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
80+
def new_unseen_orders_table(context: dict, area: Area | None = None) -> dict:
81+
new_orders = (
82+
Order.objects.filter(status=Order.OrderStatus.DELIVERED, is_seen=False)
83+
.exclude(is_urgent=True)
84+
.select_related("genrequest")
85+
.annotate(sample_count=models.Count("extractionorder__samples"))
5586
)
5687

5788
if area:
@@ -60,8 +91,8 @@ def new_orders_table(context: dict, area: Area | None = None) -> dict:
6091
new_orders = new_orders.order_by("-created_at")
6192

6293
return {
63-
"title": "New orders",
64-
"table": NewOrderTable(new_orders),
94+
"title": "New unseen orders",
95+
"table": NewUnseenOrderTable(new_orders),
6596
"count": new_orders.count(),
6697
"request": context.get("request"),
6798
}
@@ -81,11 +112,12 @@ def assigned_orders_table(context: dict) -> dict:
81112
.annotate(
82113
sample_count=models.Count("extractionorder__samples"),
83114
)
84-
.only(
85-
"id",
86-
"genrequest__name",
87-
"genrequest__expected_samples_delivery_date",
88-
"status",
115+
.annotate(
116+
priority=models.Case(
117+
models.When(is_urgent=True, then=Order.OrderPriority.URGENT),
118+
models.When(is_prioritized=True, then=Order.OrderPriority.PRIORITIZED),
119+
default=1,
120+
)
89121
)
90122
.order_by(
91123
models.Case(
@@ -95,6 +127,7 @@ def assigned_orders_table(context: dict) -> dict:
95127
default=3,
96128
output_field=models.IntegerField(),
97129
),
130+
"-priority",
98131
"-created_at",
99132
)
100133
)

src/staff/urls.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
ManaullyCheckedOrderActionView,
1616
OrderAnalysisSamplesListView,
1717
OrderExtractionSamplesListView,
18+
OrderPrioritizedAdminView,
19+
OrderSeenAdminView,
1820
OrderStaffEditView,
1921
OrderToDraftActionView,
2022
OrderToNextStatusActionView,
@@ -136,4 +138,10 @@
136138
ExtractionPlateDetailView.as_view(),
137139
name="plates-detail",
138140
),
141+
path("orders/<int:pk>/seen/", OrderSeenAdminView.as_view(), name="order-seen"),
142+
path(
143+
"orders/<int:pk>/priority/",
144+
OrderPrioritizedAdminView.as_view(),
145+
name="order-priority",
146+
),
139147
]

src/staff/views.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,3 +660,29 @@ def get_success_url(self) -> str:
660660

661661
def form_invalid(self, form: Form) -> HttpResponse:
662662
return HttpResponseRedirect(self.get_success_url())
663+
664+
665+
class OrderSeenAdminView(StaffMixin, ActionView):
666+
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
667+
pk = kwargs.get("pk")
668+
order = Order.objects.get(pk=pk)
669+
order.toggle_seen()
670+
671+
return HttpResponseRedirect(
672+
reverse(
673+
"staff:dashboard",
674+
)
675+
)
676+
677+
678+
class OrderPrioritizedAdminView(StaffMixin, ActionView):
679+
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
680+
pk = kwargs.get("pk")
681+
order = Order.objects.get(pk=pk)
682+
order.toggle_prioritized()
683+
684+
return HttpResponseRedirect(
685+
reverse(
686+
"staff:dashboard",
687+
)
688+
)

0 commit comments

Comments
 (0)