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
9 changes: 9 additions & 0 deletions src/genlab_bestilling/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,9 @@ def get_absolute_url(self) -> str:
kwargs={"pk": self.pk, "genrequest_id": self.genrequest_id},
)

def get_absolute_staff_url(self) -> str:
return reverse("staff:order-equipment-detail", kwargs={"pk": self.pk})

def confirm_order(self) -> Any:
if not EquimentOrderQuantity.objects.filter(order=self).exists():
raise Order.CannotConfirm(_("No equipments found"))
Expand Down Expand Up @@ -428,6 +431,9 @@ def get_absolute_url(self) -> str:
kwargs={"pk": self.pk, "genrequest_id": self.genrequest_id},
)

def get_absolute_staff_url(self) -> str:
return reverse("staff:order-extraction-detail", kwargs={"pk": self.pk})

def clone(self) -> None:
"""
Generates a clone of the model, with a different ID
Expand Down Expand Up @@ -528,6 +534,9 @@ def get_absolute_url(self) -> str:
kwargs={"pk": self.pk, "genrequest_id": self.genrequest_id},
)

def get_absolute_staff_url(self) -> str:
return reverse("staff:order-analysis-detail", kwargs={"pk": self.pk})

def get_type(self) -> str:
return "analysis"

Expand Down
137 changes: 137 additions & 0 deletions src/staff/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
EquipmentOrder,
ExtractionOrder,
ExtractionPlate,
Order,
Sample,
SampleMarkerAnalysis,
)
Expand Down Expand Up @@ -300,3 +301,139 @@ class Meta:
attrs = {"class": "w-full table-auto tailwind-table table-sm"}

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,
verbose_name="Status",
)

def render_status(self, value: Order.OrderStatus, record: Order) -> str:
status_colors = {
"Processing": "bg-yellow-100 text-yellow-800",
"Completed": "bg-green-100 text-green-800",
"Delivered": "bg-red-100 text-red-800",
}
status_text = {
"Processing": "Processing",
"Completed": "Completed",
"Delivered": "Not started",
}
color_class = status_colors.get(value, "bg-gray-100 text-gray-800")
status_text = status_text.get(value, "Unknown")
return mark_safe( # noqa: S308
f'<span class="px-2 py-1 text-xs font-medium rounded-full {color_class}">{status_text}</span>' # noqa: E501
)


class StaffIDMixinTable(tables.Table):
id = tables.Column(
orderable=False,
empty_values=(),
)

def render_id(
self, record: ExtractionOrder | AnalysisOrder | EquipmentOrder
) -> str:
url = record.get_absolute_staff_url()

return mark_safe(f'<a href="{url}">{record}</a>') # noqa: S308


class UrgentOrderTable(StaffIDMixinTable, StatusMixinTable):
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 value.strftime("%d/%m/%Y")
return "-"

class Meta:
model = Order
fields = ["id", "description", "delivery_date", "status"]
empty_text = "No urgent orders"
template_name = "django_tables2/tailwind_inner.html"


class NewOrderTable(StaffIDMixinTable):
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 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 = ["id", "description", "delivery_date", "samples"]
empty_text = "No new orders"
template_name = "django_tables2/tailwind_inner.html"


class AssignedOrderTable(StatusMixinTable, StaffIDMixinTable):
priority = tables.Column(
orderable=False,
verbose_name="Priority",
accessor="is_urgent",
)

def render_priority(self, value: bool) -> str:
if value:
return mark_safe(URGENT_FILLED) # noqa: S308
return ""

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

def render_samples_completed(self, value: int) -> str:
if value > 0:
return "- / " + str(value)
return "-"

class Meta:
model = Order
fields = ["priority", "id", "samples_completed", "status"]
empty_text = "No assigned orders"
template_name = "django_tables2/tailwind_inner.html"
6 changes: 6 additions & 0 deletions src/staff/templates/staff/components/order_table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% load django_tables2 %}

<div class="rounded-md border bg-white p-4">
<h4 class="text-2xl mb-4">{{ title }} ({{ count }})</h4>
{% render_table table %}
</div>
80 changes: 16 additions & 64 deletions src/staff/templates/staff/dashboard.html
Original file line number Diff line number Diff line change
@@ -1,82 +1,34 @@
{% extends 'staff/base.html' %}

{% load i18n %}
{% load static %}
{% load tz %}

{% block head_javascript %}
<script type="module" src="{% static 'js/staff/dashboard.js' %}"></script>
{% endblock %}
{% load order_tags %}

{% block content %}
<div class="flex items-center mb-5 gap-2">
<div class="flex items-center bg-white rounded-xl border">
<a data-active="{% if not request.GET.area %}true{% endif %}" href="{% url 'staff:dashboard' %}" class="px-4 py-2 rounded-xl data-[active='true']:bg-blue-400/40">All</a>
{% for area in areas %}
<a data-active="{% if request.GET.area == area.pk|stringformat:'s' %}true{% endif %}" href="{% url 'staff:dashboard' %}?area={{ area.pk }}" class="px-4 py-2 rounded-xl data-[active='true']:bg-blue-400/40">{{ area.name }}</a>
{% endfor %}
</div>

<p class="flex items-center gap-2 ml-auto">
<span>{{ now|date:'F j, Y' }}</span>
<span>|</span>
<span>Week {{ now|date:'W' }}</span>
</p>
</div>

{% if delivered_orders|length > 0 %}
<div class="rounded-md border bg-white p-4">
<p class="text-2xl mb-4">Delivered Orders</p>

{% for order in delivered_orders %}
{% if order.polymorphic_ctype.model == 'analysisorder' %}
<a class="hover:underline" href="{% url 'staff:order-analysis-detail' order.pk %}"><p>{{ order }} - {{ order.name }}</p></a>
{% elif order.polymorphic_ctype.model == 'equipmentorder' %}
<a class="hover:underline" href="{% url 'staff:order-equipment-detail' order.pk %}"><p>{{ order }} - {{ order.name }}</p></a>
{% elif order.polymorphic_ctype.model == 'extractionorder' %}
<a class="hover:underline" href="{% url 'staff:order-extraction-detail' order.pk %}"><p>{{ order }} - {{ order.name }}</p></a>
{% else %}
<p>{{ order }} - {{ order.name }}</p>
{% endif %}
{% endfor %}
<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 %}
</div>
{% endif %}

{% if urgent_orders|length > 0 %}
<div class="rounded-md border bg-white p-4">
<h4 class="text-2xl mb-4">Urgent orders</h4>

{% for order in urgent_orders %}
{% if order.polymorphic_ctype.model == 'analysisorder' %}
<a class="hover:underline" href="{% url 'staff:order-analysis-detail' order.pk %}"><p>{{ order }} - {{ order.name }} - Deadline: {{ order.expected_delivery_date|default:'-' }} - Status: {{ order.status|default:'-' }}</p></a>
{% elif order.polymorphic_ctype.model == 'equipmentorder' %}
<a class="hover:underline" href="{% url 'staff:order-equipment-detail' order.pk %}"><p>{{ order }} - {{ order.name }} - Deadline: {{ order.expected_delivery_date|default:'-' }} - Status: {{ order.status|default:'-' }}</p></a>
{% elif order.polymorphic_ctype.model == 'extractionorder' %}
<a class="hover:underline" href="{% url 'staff:order-extraction-detail' order.pk %}"><p>{{ order }} - {{ order.name }} - Deadline: {{ order.expected_delivery_date|default:'-' }} - Status: {{ order.status|default:'-' }}</p></a>
{% else %}
<p>{{ order }} - {{ order.name }}</p>
{% endif %}
{% endfor %}
</div>
{% else %}
<div class="rounded-md border bg-white p-4">
<h4 class="text-2xl mb-4">Urgent orders</h4>
<p>No urgent orders found.</p>
</div>
{% endif %}

{% if assigned_orders|length > 0 %}
<div class="rounded-md border bg-white p-4">
<h4 class="text-2xl mb-4">My orders ({{ assigned_orders|length }})</h4>

{% for order in assigned_orders %}
{% if order.polymorphic_ctype.model == 'analysisorder' %}
<a class="hover:underline" href="{% url 'staff:order-analysis-detail' order.pk %}"><p>{{ order }} - {{ order.name }}</p></a>
{% elif order.polymorphic_ctype.model == 'equipmentorder' %}
<a class="hover:underline" href="{% url 'staff:order-equipment-detail' order.pk %}"><p>{{ order }} - {{ order.name }}</p></a>
{% elif order.polymorphic_ctype.model == 'extractionorder' %}
<a class="hover:underline" href="{% url 'staff:order-extraction-detail' order.pk %}"><p>{{ order }} - {{ order.name }}</p></a>
{% else %}
<p>{{ order }} - {{ order.name }}</p>
{% endif %}
{% endfor %}
<div class="flex flex-col gap-8">
{% assigned_orders_table %}
</div>
{% else %}
<div class="rounded-md border bg-white p-4">
<h4 class="text-2xl mb-4">Assigned orders</h4>
<p>No assigned orders found.</p>
</div>
{% endif %}
</div>
{% endblock %}
Empty file.
107 changes: 107 additions & 0 deletions src/staff/templatetags/order_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
from django import template
from django.db import models

from genlab_bestilling.models import Area, Order

from ..tables import AssignedOrderTable, NewOrderTable, 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")

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(
models.Case(
models.When(status=Order.OrderStatus.PROCESSING, then=0),
models.When(status=Order.OrderStatus.DELIVERED, then=1),
models.When(status=Order.OrderStatus.COMPLETED, then=2),
default=3,
output_field=models.IntegerField(),
),
"-created_at",
)

return {
"title": "Urgent orders",
"table": UrgentOrderTable(urgent_orders),
"count": urgent_orders.count(),
"request": context.get("request"),
}


@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
def new_orders_table(context: dict, area: Area | None = None) -> dict:
new_orders = (
Order.objects.filter(status=Order.OrderStatus.DELIVERED)
.select_related("genrequest")
.annotate(sample_count=models.Count("extractionorder__samples"))
.only(
"id",
"genrequest__name",
"genrequest__expected_samples_delivery_date",
"status",
)
.order_by("status")
)

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

new_orders = new_orders.order_by("-created_at")

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


@register.inclusion_tag("staff/components/order_table.html", takes_context=True)
def assigned_orders_table(context: dict) -> dict:
assigned_orders = (
Order.objects.filter(
status__in=[
Order.OrderStatus.PROCESSING,
Order.OrderStatus.DELIVERED,
Order.OrderStatus.COMPLETED,
]
)
.select_related("genrequest")
.annotate(
sample_count=models.Count("extractionorder__samples"),
)
.only(
"id",
"genrequest__name",
"genrequest__expected_samples_delivery_date",
"status",
)
.order_by(
models.Case(
models.When(status=Order.OrderStatus.PROCESSING, then=0),
models.When(status=Order.OrderStatus.DELIVERED, then=1),
models.When(status=Order.OrderStatus.COMPLETED, then=2),
default=3,
output_field=models.IntegerField(),
),
"-created_at",
)
)

return {
"title": "My orders",
"table": AssignedOrderTable(assigned_orders),
"count": assigned_orders.count(),
"request": context.get("request"),
}
Loading