Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/genlab_bestilling/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ class OrderStatus(models.TextChoices):
# COMPLETED: Order has been completed, and results are available.
COMPLETED = "completed", _("Completed")

class OrderPriority:
URGENT = 3
PRIORITIZED = 2
NORMAL = 1

STATUS_ORDER = (
OrderStatus.DRAFT,
OrderStatus.DELIVERED,
Expand Down
71 changes: 55 additions & 16 deletions src/staff/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,6 @@ class Meta:
empty_text = "No Plates"


FLAG_OUTLINE = "<i class='fa-regular fa-flag fa-lg' title='Normal'></i>"
FLAG_FILLED = "<i class='fa-solid fa-flag fa-lg' title='Prioritized'></i>"
URGENT_FILLED = (
"<i class='fa-solid fa-exclamation fa-lg text-red-500' title='Urgent'></i>"
)


class StatusMixinTable(tables.Table):
status = tables.Column(
orderable=False,
Expand Down Expand Up @@ -373,7 +366,14 @@ class Meta:
template_name = "django_tables2/tailwind_inner.html"


class NewOrderTable(StaffIDMixinTable):
class NewUnseenOrderTable(StaffIDMixinTable):
seen = tables.TemplateColumn(
orderable=False,
verbose_name="Seen",
template_name="staff/components/seen_column.html",
empty_values=(),
)

description = tables.Column(
accessor="genrequest__name",
verbose_name="Description",
Expand Down Expand Up @@ -404,22 +404,61 @@ def render_samples(self, value: int) -> str:

class Meta:
model = Order
fields = ["id", "description", "delivery_date", "samples"]
empty_text = "No new orders"
fields = ["id", "description", "delivery_date", "samples", "seen"]
empty_text = "No new unseen orders"
template_name = "django_tables2/tailwind_inner.html"


class AssignedOrderTable(StatusMixinTable, StaffIDMixinTable):
priority = tables.Column(
class NewSeenOrderTable(StaffIDMixinTable):
priority = tables.TemplateColumn(
orderable=False,
verbose_name="Priority",
accessor="is_urgent",
accessor="priority",
template_name="staff/components/priority_column.html",
)

def render_priority(self, value: bool) -> str:
description = tables.Column(
accessor="genrequest__name",
verbose_name="Description",
orderable=False,
)

delivery_date = tables.Column(
accessor="genrequest__expected_samples_delivery_date",
verbose_name="Delivery date",
orderable=False,
)

def render_delivery_date(self, value: Any) -> str:
if value:
return mark_safe(URGENT_FILLED) # noqa: S308
return ""
return value.strftime("%d/%m/%Y")
return "-"

samples = tables.Column(
accessor="sample_count",
verbose_name="Samples",
orderable=False,
)

def render_samples(self, value: int) -> str:
if value > 0:
return str(value)
return "-"

class Meta:
model = Order
fields = ["priority", "id", "description", "delivery_date", "samples"]
empty_text = "No new seen orders"
template_name = "django_tables2/tailwind_inner.html"


class AssignedOrderTable(StatusMixinTable, StaffIDMixinTable):
priority = tables.TemplateColumn(
orderable=False,
verbose_name="Priority",
accessor="priority",
template_name="staff/components/priority_column.html",
)

samples_completed = tables.Column(
accessor="sample_count",
Expand Down
21 changes: 21 additions & 0 deletions src/staff/templates/staff/components/priority_column.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% if value == 3 %}
<i class="fa-solid fa-exclamation fa-lg text-red-500" title="Urgent"></i>
{% else %}
<form method="post" action="{% url 'staff:order-priority' pk=record.pk %}">
{% csrf_token %}

{% 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 %}

<button title="Mark as prioritized">
{% if value == 2 %}
<svg class="size-4 fill-blue-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<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" />
</svg>
{% else %}
<svg class="size-4 stroke-gray-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<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" />
</svg>
{% endif %}
</button>
</form>
{% endif %}
4 changes: 4 additions & 0 deletions src/staff/templates/staff/components/seen_column.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<form method="post" action="{% url 'staff:order-seen' pk=record.pk %}">
{% csrf_token %}
<input title="Mark as seen" onchange="this.form.submit()" type="checkbox" class="size-4 border rounded" />
</form>
3 changes: 2 additions & 1 deletion src/staff/templates/staff/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
<div class="grid grid-cols-2 gap-4">
<div class="flex flex-col gap-8">
{% urgent_orders_table area=area %}
{% new_orders_table area=area %}
{% new_unseen_orders_table area=area %}
{% new_seen_orders_table area=area %}
</div>

<div class="flex flex-col gap-8">
Expand Down
81 changes: 57 additions & 24 deletions src/staff/templatetags/order_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,30 @@

from genlab_bestilling.models import Area, Order

from ..tables import AssignedOrderTable, NewOrderTable, UrgentOrderTable
from ..tables import (
AssignedOrderTable,
NewSeenOrderTable,
NewUnseenOrderTable,
UrgentOrderTable,
)

register = template.Library()


@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
def urgent_orders_table(context: dict, area: Area | None = None) -> dict:
urgent_orders = Order.objects.filter(
is_urgent=True,
status__in=[Order.OrderStatus.PROCESSING, Order.OrderStatus.DELIVERED],
).select_related("genrequest")
urgent_orders = (
Order.objects.filter(
is_urgent=True,
)
.exclude(status=Order.OrderStatus.DRAFT)
.select_related("genrequest")
)

if area:
urgent_orders = urgent_orders.filter(genrequest__area=area)

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


@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
def new_orders_table(context: dict, area: Area | None = None) -> dict:
def new_seen_orders_table(context: dict, area: Area | None = None) -> dict:
new_orders = (
Order.objects.filter(status=Order.OrderStatus.DELIVERED)
Order.objects.filter(status=Order.OrderStatus.DELIVERED, is_seen=True)
.exclude(is_urgent=True)
.select_related("genrequest")
.annotate(sample_count=models.Count("extractionorder__samples"))
.only(
"id",
"genrequest__name",
"genrequest__expected_samples_delivery_date",
"status",
.annotate(
sample_count=models.Count("extractionorder__samples"),
)
.order_by("status")
.annotate(
priority=models.Case(
models.When(is_urgent=True, then=Order.OrderPriority.URGENT),
models.When(is_prioritized=True, then=Order.OrderPriority.PRIORITIZED),
default=1,
)
)
)

if area:
new_orders = new_orders.filter(genrequest__area=area)

new_orders = new_orders.order_by("-priority", "-created_at")

return {
"title": "New seen orders",
"table": NewSeenOrderTable(new_orders),
"count": new_orders.count(),
"request": context.get("request"),
}


@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
def new_unseen_orders_table(context: dict, area: Area | None = None) -> dict:
new_orders = (
Order.objects.filter(status=Order.OrderStatus.DELIVERED, is_seen=False)
.exclude(is_urgent=True)
.select_related("genrequest")
.annotate(sample_count=models.Count("extractionorder__samples"))
)

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

return {
"title": "New orders",
"table": NewOrderTable(new_orders),
"title": "New unseen orders",
"table": NewUnseenOrderTable(new_orders),
"count": new_orders.count(),
"request": context.get("request"),
}
Expand All @@ -81,11 +112,12 @@ def assigned_orders_table(context: dict) -> dict:
.annotate(
sample_count=models.Count("extractionorder__samples"),
)
.only(
"id",
"genrequest__name",
"genrequest__expected_samples_delivery_date",
"status",
.annotate(
priority=models.Case(
models.When(is_urgent=True, then=Order.OrderPriority.URGENT),
models.When(is_prioritized=True, then=Order.OrderPriority.PRIORITIZED),
default=1,
)
)
.order_by(
models.Case(
Expand All @@ -95,6 +127,7 @@ def assigned_orders_table(context: dict) -> dict:
default=3,
output_field=models.IntegerField(),
),
"-priority",
"-created_at",
)
)
Expand Down
8 changes: 8 additions & 0 deletions src/staff/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
ManaullyCheckedOrderActionView,
OrderAnalysisSamplesListView,
OrderExtractionSamplesListView,
OrderPrioritizedAdminView,
OrderSeenAdminView,
OrderStaffEditView,
OrderToDraftActionView,
OrderToNextStatusActionView,
Expand Down Expand Up @@ -136,4 +138,10 @@
ExtractionPlateDetailView.as_view(),
name="plates-detail",
),
path("orders/<int:pk>/seen/", OrderSeenAdminView.as_view(), name="order-seen"),
path(
"orders/<int:pk>/priority/",
OrderPrioritizedAdminView.as_view(),
name="order-priority",
),
]
26 changes: 26 additions & 0 deletions src/staff/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,3 +660,29 @@ def get_success_url(self) -> str:

def form_invalid(self, form: Form) -> HttpResponse:
return HttpResponseRedirect(self.get_success_url())


class OrderSeenAdminView(StaffMixin, ActionView):
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
pk = kwargs.get("pk")
order = Order.objects.get(pk=pk)
order.toggle_seen()

return HttpResponseRedirect(
reverse(
"staff:dashboard",
)
)


class OrderPrioritizedAdminView(StaffMixin, ActionView):
def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
pk = kwargs.get("pk")
order = Order.objects.get(pk=pk)
order.toggle_prioritized()

return HttpResponseRedirect(
reverse(
"staff:dashboard",
)
)