From 4115dc4e00b57a1a7d1021b51e68dcfe5e86fa1d Mon Sep 17 00:00:00 2001 From: Morten Lyngstad <81157760+mortenlyn@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:48:47 +0200 Subject: [PATCH 1/7] Add new headers to CSV-files and refactor build_csv_data method (#294) Co-authored-by: Morten Madsen Lyngstad --- src/genlab_bestilling/api/serializers.py | 25 +++-- src/genlab_bestilling/api/views.py | 137 +++++++++++++++++++---- 2 files changed, 130 insertions(+), 32 deletions(-) diff --git a/src/genlab_bestilling/api/serializers.py b/src/genlab_bestilling/api/serializers.py index e47cfb43..a5e4e924 100644 --- a/src/genlab_bestilling/api/serializers.py +++ b/src/genlab_bestilling/api/serializers.py @@ -102,9 +102,10 @@ class SampleCSVSerializer(serializers.ModelSerializer): analysis_orders = serializers.SerializerMethodField() project = serializers.SerializerMethodField() isolation_method = serializers.SerializerMethodField() - marked = serializers.SerializerMethodField() - plucked = serializers.SerializerMethodField() - isolated = serializers.SerializerMethodField() + is_marked = serializers.SerializerMethodField() + is_plucked = serializers.SerializerMethodField() + is_isolated = serializers.SerializerMethodField() + internal_note = serializers.SerializerMethodField() class Meta: model = Sample @@ -123,9 +124,10 @@ class Meta: "analysis_orders", "project", "isolation_method", - "marked", - "plucked", - "isolated", + "is_marked", + "is_plucked", + "is_isolated", + "internal_note", ] def get_fish_id(self, obj: Sample) -> str: @@ -148,15 +150,20 @@ def get_isolation_method(self, obj: Sample) -> str: def _flag(self, value: bool) -> str: return "x" if value else "" - def get_marked(self, obj: Sample) -> str: + def get_is_marked(self, obj: Sample) -> str: return self._flag(obj.is_marked) - def get_plucked(self, obj: Sample) -> str: + def get_is_plucked(self, obj: Sample) -> str: return self._flag(obj.is_plucked) - def get_isolated(self, obj: Sample) -> str: + def get_is_isolated(self, obj: Sample) -> str: return self._flag(obj.is_isolated) + def get_internal_note(self, obj: Sample) -> str: + if obj.internal_note: + return obj.internal_note + return "" + class SampleUpdateSerializer(serializers.ModelSerializer): has_error = serializers.SerializerMethodField() diff --git a/src/genlab_bestilling/api/views.py b/src/genlab_bestilling/api/views.py index 9ea27c65..bd8b3b30 100644 --- a/src/genlab_bestilling/api/views.py +++ b/src/genlab_bestilling/api/views.py @@ -1,3 +1,4 @@ +import re import uuid from django.db import transaction @@ -92,30 +93,64 @@ class SampleViewset(ModelViewSet): "length": "Length", "weight": "Weight", "classification": "Classification", - "year": "Date", - "notes": "Remarks", - "project": "Projectnumber", + "year": "Year", + "notes": "Notes", + "project": "Project Number", "isolation_method": "Isolation Method", "qiagen_number": "Qiagen#", "is_marked": "Marked", "is_plucked": "Plucked", "is_isolated": "Isolated", "station": "Station", - "placement_in_fridge": "Placement in fridge", - "delivered_to_lab": "Delivered to lab", + "placement_in_fridge": "Placement in Fridge", + "delivered_to_lab": "Delivered to Lab", + "fluidigm#": "Fluidigm#", + "laksov_species": "LaksOV + Species", + "species_date": "Species Date", + "pcr": "PCR", + "fluidigm": "Fluidigm", + "output": "Output", + "analysis_note": "Analysis Note", + "rerun": "Rerun", + "rerun_qiagen": "Rerun Qiagen", + "river": "River", + "str_date": "STR Date", + "rerun_date": "Rerun Date", + "watercourse_number": "Watercourse Number", + "under_locality": "Sub-locality", + "county": "County", + "snp_assay_1": "SNP Assay 1", + "snp_assay_2": "SNP Assay 2", + "str_mixab": "STR Mix AB", + "str_mixc": "STR Mix C", + "str_mixy": "STR Mix Y", + "internal_note": "Internal Note", + "bb#": "BB#", + "output_bb": "Output", + "bba2#": "BBA2#", + "output_bba2": "Output", + "mixab": "Mix AB", + "ab_rep#": "AB Rep#", + "mixc": "Mix C", + "c_rep#": "C Rep#", + "re_extracted_date": "Re-extracted Date", + "re_extracted_qiagen#": "Re-extracted Qiagen#", + "weight_g_for_diet_analysis": "Weight (g) for Diet Analysis", + "position": "Position", } # NOTE: This can be modified to include more fields based on species or area. CSV_FIELDS_BY_AREA: dict[str, list[str]] = { "Akvatisk": [ + "name", "genlab_id", "fish_id", "guid", "order", "analysis_orders", "location.name", + "watercourse_number", "pop_id", - "name", "species.name", "gender", "length", @@ -127,32 +162,52 @@ class SampleViewset(ModelViewSet): "type.name", "isolation_method", "qiagen_number", + "fluidigm#", + "laksov_species", + "species_date", "is_marked", "is_plucked", "is_isolated", + "pcr", + "fluidigm", + "output", + "analysis_note", + "rerun", + "rerun_date", ], "Elvemusling": [ + "name", "genlab_id", "fish_id", "guid", + "river", "location.name", + "under_locality", + "watercourse_number", + "county", "year", - "name", "station", "type.name", "length", "notes", "isolation_method", "qiagen_number", + "position", "placement_in_fridge", "is_marked", "is_plucked", "is_isolated", + "pcr", + "str_date", + "output", + "analysis_note", + "rerun", + "rerun_date", ], "Terrestrisk": [ + "name", "genlab_id", "guid", - "name", "type.name", "species.name", "location.name", @@ -160,13 +215,29 @@ class SampleViewset(ModelViewSet): "order", "analysis_orders", "notes", + "snp_assay_1", + "snp_assay_2", + "str_mixab", + "str_mixc", + "str_mixy", "is_marked", "is_plucked", "is_isolated", "isolation_method", "qiagen_number", + "internal_note", + "bb#", + "output_bb", + "bba2#", + "output_bba2", + "mixab", + "ab_rep#", + "mixc", + "c_rep#", + "re_extracted_date", + "re_extracted_qiagen#", + "weight_g_for_diet_analysis", ], - # Same as "Terrestrisk" for now, can be modified later if needed. "default": [ "genlab_id", "guid", @@ -174,7 +245,6 @@ class SampleViewset(ModelViewSet): "type.name", "species.name", "location.name", - "delivered_to_lab", "order", "analysis_orders", "notes", @@ -239,19 +309,40 @@ def get_nested(self, obj: dict, dotted: str) -> str | None: return obj def build_csv_data( - self, serialized_data: list[dict], fields: list[str] + self, serialized_data: list[dict], fields: list[str], area_name: str ) -> list[dict[str, str]]: - return [ - { - self.CSV_FIELD_LABELS[f]: ( - ", ".join(v) - if isinstance(v := self.get_nested(item, f), list) - else v or "" - ) - for f in fields - } - for item in serialized_data - ] + rows = [] + + for item in serialized_data: + row = {} + + for f in fields: + if area_name in {"Akvatisk", "Elvemusling"} and f == "location.name": + full_location = self.get_nested(item, "location.name") + + if ( + full_location + and re.search(r"\d+", full_location) + and " " in full_location + ): + watercourse, location = full_location.split(" ", 1) + else: + watercourse, location = "", full_location or "" + + row[self.CSV_FIELD_LABELS["watercourse_number"]] = watercourse + row[self.CSV_FIELD_LABELS["location.name"]] = location + + # We skip "watercourse_number" because it is handled above. + elif f != "watercourse_number": + value = self.get_nested(item, f) + if isinstance(value, list): + row[self.CSV_FIELD_LABELS[f]] = ", ".join(value) + else: + row[self.CSV_FIELD_LABELS[f]] = value or "" + + rows.append(row) + + return rows @action( methods=["GET"], @@ -269,7 +360,7 @@ def csv(self, request: Request) -> HttpResponse: ) fields, headers = self.get_csv_fields_and_labels(area_name, queryset) - data = self.build_csv_data(serializer.data, fields) + data = self.build_csv_data(serializer.data, fields, area_name) csv_data = CSVRenderer().render( data, From 7340dca05c3ffc1f3836845ac86146dfd8c5bc27 Mon Sep 17 00:00:00 2001 From: Morten Lyngstad <81157760+mortenlyn@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:20:28 +0200 Subject: [PATCH 2/7] Add possibility to toggle sample status (#297) Co-authored-by: Morten Madsen Lyngstad --- src/genlab_bestilling/models.py | 4 ++++ src/staff/tables.py | 2 +- src/staff/views.py | 37 +++++++++++++++++++++------------ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/genlab_bestilling/models.py b/src/genlab_bestilling/models.py index c23890a6..5e95ffe0 100644 --- a/src/genlab_bestilling/models.py +++ b/src/genlab_bestilling/models.py @@ -325,6 +325,10 @@ def to_draft(self) -> None: self.confirmed_at = None self.save() + def to_processing(self) -> None: + self.status = Order.OrderStatus.PROCESSING + self.save() + def toggle_seen(self) -> None: self.is_seen = not self.is_seen self.save() diff --git a/src/staff/tables.py b/src/staff/tables.py index ae6a3502..4bcb22c3 100644 --- a/src/staff/tables.py +++ b/src/staff/tables.py @@ -295,7 +295,7 @@ class Meta: "internal_note", "isolation_method", ] - order_by = () + order_by = ("genlab_id",) def render_checked(self, record: Any) -> str: return mark_safe( # noqa: S308 diff --git a/src/staff/views.py b/src/staff/views.py index 9fd4274d..91c64f1c 100644 --- a/src/staff/views.py +++ b/src/staff/views.py @@ -430,6 +430,10 @@ def post(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: self.update_isolation_methods(samples, isolation_method, request) return HttpResponseRedirect(self.get_success_url()) + def statuses_with_lower_or_equal_priority(self, status_name: str) -> list[str]: + index = self.VALID_STATUSES.index(status_name) + return self.VALID_STATUSES[: index + 1] + def assign_status_to_samples( self, samples: models.QuerySet, @@ -440,23 +444,24 @@ def assign_status_to_samples( messages.error(request, f"Status '{status_name}' is not valid.") return - update_fields = [] + statuses_to_turn_on = self.statuses_with_lower_or_equal_priority(status_name) + field_name = f"is_{status_name}" - if status_name == self.MARKED: - update_fields.append("is_marked") - samples.update(is_marked=True) + samples_to_turn_off_ids = list( + samples.filter(**{field_name: True}).values_list("id", flat=True) + ) + samples_to_turn_on_ids = list( + samples.filter(**{field_name: False}).values_list("id", flat=True) + ) - elif status_name == self.PLUCKED: - update_fields.extend(["is_marked", "is_plucked"]) - samples.update(is_marked=True, is_plucked=True) + Sample.objects.filter(id__in=samples_to_turn_off_ids).update( + **{field_name: False} + ) - elif status_name == self.ISOLATED: - update_fields.extend(["is_marked", "is_plucked", "is_isolated"]) - samples.update(is_marked=True, is_plucked=True, is_isolated=True) + update_dict = {f"is_{status}": True for status in statuses_to_turn_on} + Sample.objects.filter(id__in=samples_to_turn_on_ids).update(**update_dict) - messages.success( - request, f"{samples.count()} samples updated with status '{status_name}'." - ) + messages.success(request, "Samples updated successfully") # Checks if all samples in the order are isolated # If they are, it updates the order status to completed @@ -467,6 +472,12 @@ def check_all_isolated(self, samples: models.QuerySet) -> None: self.request, "All samples are isolated. The order status is updated to completed.", ) + elif self.get_order().status == Order.OrderStatus.COMPLETED: + self.get_order().to_processing() + messages.success( + self.request, + "Not all samples are isolated. The order status is updated to processing.", # noqa: E501 + ) def update_isolation_methods( self, samples: models.QuerySet, isolation_method: str, request: HttpRequest From 2de07eb8c883c8d74b0aca554319691cd0f3138d Mon Sep 17 00:00:00 2001 From: Ole Magnus Date: Fri, 18 Jul 2025 15:27:41 +0200 Subject: [PATCH 3/7] Make contact name required (#293) --- ...ontact_email_alter_order_contact_person.py | 28 +++++++++++++++++++ src/genlab_bestilling/models.py | 4 +-- 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/genlab_bestilling/migrations/0029_alter_order_contact_email_alter_order_contact_person.py diff --git a/src/genlab_bestilling/migrations/0029_alter_order_contact_email_alter_order_contact_person.py b/src/genlab_bestilling/migrations/0029_alter_order_contact_email_alter_order_contact_person.py new file mode 100644 index 00000000..c0969e59 --- /dev/null +++ b/src/genlab_bestilling/migrations/0029_alter_order_contact_email_alter_order_contact_person.py @@ -0,0 +1,28 @@ +# Generated by Django 5.2.3 on 2025-07-18 07:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("genlab_bestilling", "0028_sample_is_isolated_sample_is_marked_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="order", + name="contact_email", + field=models.EmailField( + help_text="Email to contact with questions about this order", + max_length=254, + null=True, + ), + ), + migrations.AlterField( + model_name="order", + name="contact_person", + field=models.CharField( + help_text="Person to contact with questions about this order", null=True + ), + ), + ] diff --git a/src/genlab_bestilling/models.py b/src/genlab_bestilling/models.py index 5e95ffe0..d6a4ab53 100644 --- a/src/genlab_bestilling/models.py +++ b/src/genlab_bestilling/models.py @@ -282,12 +282,12 @@ class OrderPriority: ) contact_person = models.CharField( null=True, - blank=True, + blank=False, help_text="Person to contact with questions about this order", ) contact_email = models.EmailField( null=True, - blank=True, + blank=False, help_text="Email to contact with questions about this order", ) responsible_staff = models.ManyToManyField( From f001005b0814699f0d486995532d3b20b6cdaf79 Mon Sep 17 00:00:00 2001 From: Bertine <112892518+aastabk@users.noreply.github.com> Date: Fri, 18 Jul 2025 15:44:59 +0200 Subject: [PATCH 4/7] Add a clear all button for the filters (#299) --- .../templates/genlab_bestilling/base_filter.html | 1 + src/staff/templates/staff/analysisorder_filter.html | 1 + src/staff/templates/staff/equipmentorder_filter.html | 1 + src/staff/templates/staff/extractionorder_filter.html | 1 + src/staff/templates/staff/extractionplate_filter.html | 1 + src/staff/templates/staff/project_filter.html | 1 + src/staff/templates/staff/sample_filter.html | 1 + src/staff/templates/staff/sample_lab.html | 1 + src/staff/templates/staff/samplemarkeranalysis_filter.html | 1 + 9 files changed, 9 insertions(+) diff --git a/src/genlab_bestilling/templates/genlab_bestilling/base_filter.html b/src/genlab_bestilling/templates/genlab_bestilling/base_filter.html index e27e6f3b..7b7be329 100644 --- a/src/genlab_bestilling/templates/genlab_bestilling/base_filter.html +++ b/src/genlab_bestilling/templates/genlab_bestilling/base_filter.html @@ -10,6 +10,7 @@

{% block page-title %}{% endblock page-title %}

{{ filter.form | crispy }} + Clear Filters
diff --git a/src/staff/templates/staff/analysisorder_filter.html b/src/staff/templates/staff/analysisorder_filter.html index c388eb48..4db95d15 100644 --- a/src/staff/templates/staff/analysisorder_filter.html +++ b/src/staff/templates/staff/analysisorder_filter.html @@ -11,6 +11,7 @@
{{ filter.form | crispy }} + Clear Filters
diff --git a/src/staff/templates/staff/equipmentorder_filter.html b/src/staff/templates/staff/equipmentorder_filter.html index 07928ac6..372f35b9 100644 --- a/src/staff/templates/staff/equipmentorder_filter.html +++ b/src/staff/templates/staff/equipmentorder_filter.html @@ -11,6 +11,7 @@
{{ filter.form | crispy }} + Clear Filters
diff --git a/src/staff/templates/staff/extractionorder_filter.html b/src/staff/templates/staff/extractionorder_filter.html index c85fc272..d6849d29 100644 --- a/src/staff/templates/staff/extractionorder_filter.html +++ b/src/staff/templates/staff/extractionorder_filter.html @@ -11,6 +11,7 @@
{{ filter.form | crispy }} + Clear Filters
diff --git a/src/staff/templates/staff/extractionplate_filter.html b/src/staff/templates/staff/extractionplate_filter.html index 4463ae68..c8ed54ab 100644 --- a/src/staff/templates/staff/extractionplate_filter.html +++ b/src/staff/templates/staff/extractionplate_filter.html @@ -16,6 +16,7 @@ {{ filter.form | crispy }} + Clear Filters {% render_table table %} diff --git a/src/staff/templates/staff/project_filter.html b/src/staff/templates/staff/project_filter.html index eb62d2fe..afc3319e 100644 --- a/src/staff/templates/staff/project_filter.html +++ b/src/staff/templates/staff/project_filter.html @@ -11,6 +11,7 @@
{{ filter.form | crispy }} + Clear Filters
diff --git a/src/staff/templates/staff/sample_filter.html b/src/staff/templates/staff/sample_filter.html index fffea62b..f0ec49e3 100644 --- a/src/staff/templates/staff/sample_filter.html +++ b/src/staff/templates/staff/sample_filter.html @@ -29,6 +29,7 @@
{{ filter.form | crispy }} + Clear Filters
diff --git a/src/staff/templates/staff/sample_lab.html b/src/staff/templates/staff/sample_lab.html index fececc23..24c2abc5 100644 --- a/src/staff/templates/staff/sample_lab.html +++ b/src/staff/templates/staff/sample_lab.html @@ -13,6 +13,7 @@

{% block page-title %}{% if order %}{{ order }} - Samp
{{ filter.form | crispy }} + Clear Filters
{% endcomment %} diff --git a/src/staff/templates/staff/samplemarkeranalysis_filter.html b/src/staff/templates/staff/samplemarkeranalysis_filter.html index a4478564..749af0e8 100644 --- a/src/staff/templates/staff/samplemarkeranalysis_filter.html +++ b/src/staff/templates/staff/samplemarkeranalysis_filter.html @@ -17,6 +17,7 @@
{{ filter.form | crispy }} + Clear Filters
From c31157d01a2624a96cfa720d6fdc52d83c10d51c Mon Sep 17 00:00:00 2001 From: Ole Magnus Date: Mon, 21 Jul 2025 14:18:54 +0200 Subject: [PATCH 5/7] Style analysis and extraction table (#310) --- src/staff/tables.py | 208 +++++++++++------- .../staff/components/priority_column.html | 8 +- src/staff/views.py | 25 ++- 3 files changed, 147 insertions(+), 94 deletions(-) diff --git a/src/staff/tables.py b/src/staff/tables.py index 4bcb22c3..d30a4ed1 100644 --- a/src/staff/tables.py +++ b/src/staff/tables.py @@ -4,6 +4,8 @@ from typing import Any import django_tables2 as tables +from django.db import models +from django.db.models.query import QuerySet from django.utils.safestring import mark_safe from genlab_bestilling.models import ( @@ -18,6 +20,46 @@ from nina.models import Project +class StatusMixinTable(tables.Table): + status = tables.Column( + orderable=True, + verbose_name="Status", + ) + + def order_status( + self, queryset: QuerySet[Order], is_descending: bool + ) -> tuple[QuerySet[Order], bool]: + prefix = "-" if is_descending else "" + sorted_by_status = queryset.annotate( + status_order=models.Case( + models.When(status=Order.OrderStatus.DELIVERED, then=0), + models.When(status=Order.OrderStatus.DRAFT, then=1), + models.When(status=Order.OrderStatus.PROCESSING, then=2), + models.When(status=Order.OrderStatus.COMPLETED, then=3), + ) + ).order_by(f"{prefix}status_order") + + return (sorted_by_status, True) + + 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", + "Draft": "Draft", + } + 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'{status_text}' # noqa: E501 + ) + + class ProjectTable(tables.Table): number = tables.Column( linkify=("staff:projects-detail", {"pk": tables.A("number")}), @@ -31,67 +73,54 @@ class Meta: fields = ("number", "name", "active", "verified_at") -class OrderTable(tables.Table): +class OrderTable(StatusMixinTable): id = tables.Column( linkify=True, orderable=False, empty_values=(), + verbose_name="Order ID", + ) + + def render_id(self, record: Any) -> str: + return str(record) + + priority = tables.TemplateColumn( + orderable=True, + verbose_name="Priority", + template_name="staff/components/priority_column.html", ) - is_urgent = tables.Column( + area = tables.Column( + accessor="genrequest__area__name", + verbose_name="Area", orderable=True, - visible=True, - verbose_name="", ) - status = tables.Column( - verbose_name="Status", - orderable=False, + description = tables.Column( + accessor="genrequest__name", + verbose_name="Description", + orderable=True, ) - is_seen = tables.Column( + responsible_staff = tables.ManyToManyColumn( + accessor="responsible_staff", + verbose_name="Assigned staff", orderable=False, - visible=True, - verbose_name="", + transform=lambda x: x.first_name + " " + x.last_name, ) class Meta: fields = [ - "name", + "priority", + "id", "status", - "genrequest", - "genrequest__name", - "genrequest__project", - "genrequest__area", - "genrequest__samples_owner", - "created_at", - "last_modified_at", - "is_urgent", - "is_seen", + "area", + "description", + "total_samples", + "responsible_staff", ] - sequence = ("is_seen", "is_urgent", "status", "id", "name") empty_text = "No Orders" - order_by = ("-is_urgent", "last_modified_at", "created_at") - - def render_id(self, record: Any) -> str: - return str(record) - - def render_is_urgent(self, value: bool) -> str: - html_exclaimation_mark = ( - "" - ) - if value: - return mark_safe(html_exclaimation_mark) # noqa: S308 - else: - return "" - - def render_is_seen(self, value: bool) -> str: - if not value: - return mark_safe( - '' - ) - return "" + order_by = ("-is_urgent",) class AnalysisOrderTable(OrderTable): @@ -101,9 +130,35 @@ class AnalysisOrderTable(OrderTable): empty_values=(), ) + markers = tables.ManyToManyColumn( + accessor="markers", + verbose_name="Markers", + orderable=False, + transform=lambda x: x.name, + ) + + expected_delivery_date = tables.DateColumn( + accessor="expected_delivery_date", + verbose_name="Delivery date", + format="d/m/Y", + orderable=True, + empty_values=(), + ) + class Meta(OrderTable.Meta): model = AnalysisOrder - fields = OrderTable.Meta.fields + ["return_samples"] + fields = OrderTable.Meta.fields + ["markers", "expected_delivery_date"] + sequence = ( + "priority", + "id", + "status", + "area", + "description", + "total_samples", + "markers", + "responsible_staff", + "expected_delivery_date", + ) class ExtractionOrderTable(OrderTable): @@ -113,26 +168,37 @@ class ExtractionOrderTable(OrderTable): empty_values=(), ) - sample_count = tables.Column( - accessor="sample_count", - verbose_name="Sample Count", - orderable=False, + def render_total_samples(self, record: ExtractionOrder) -> str: + return record.total_samples or "0" + + def render_total_samples_isolated(self, record: ExtractionOrder) -> str: + return record.total_samples_isolated or "0" + + confirmed_at = tables.DateColumn( + accessor="confirmed_at", + verbose_name="Confirmed at", + format="d/m/Y", + orderable=True, + empty_values=(), ) class Meta(OrderTable.Meta): model = ExtractionOrder fields = OrderTable.Meta.fields + [ - "species", - "sample_types", - "internal_status", - "needs_guid", - "return_samples", - "pre_isolated", + "total_samples_isolated", + "confirmed_at", ] - sequence = OrderTable.Meta.sequence + ("sample_count",) - - def render_sample_count(self, record: Any) -> str: - return record.sample_count or "0" + sequence = ( + "priority", + "id", + "status", + "area", + "description", + "total_samples", + "total_samples_isolated", + "responsible_staff", + "confirmed_at", + ) class EquipmentOrderTable(OrderTable): @@ -349,30 +415,6 @@ class Meta: empty_text = "No Plates" -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'{status_text}' # noqa: E501 - ) - - class StatusMixinTableSamples(tables.Table): sample_status = tables.Column( verbose_name="Sample Status", empty_values=(), orderable=True @@ -511,7 +553,6 @@ class UrgentOrderTable(StaffIDMixinTable, StatusMixinTable): priority = tables.TemplateColumn( orderable=False, verbose_name="Priority", - accessor="priority", template_name="staff/components/priority_column.html", ) @@ -588,7 +629,6 @@ class NewSeenOrderTable(StaffIDMixinTable): priority = tables.TemplateColumn( orderable=False, verbose_name="Priority", - accessor="priority", template_name="staff/components/priority_column.html", ) @@ -641,7 +681,6 @@ class AssignedOrderTable(StatusMixinTable, StaffIDMixinTable): priority = tables.TemplateColumn( orderable=False, verbose_name="Priority", - accessor="priority", template_name="staff/components/priority_column.html", ) @@ -673,7 +712,6 @@ class DraftOrderTable(StaffIDMixinTable): priority = tables.TemplateColumn( orderable=False, verbose_name="Priority", - accessor="priority", template_name="staff/components/priority_column.html", ) diff --git a/src/staff/templates/staff/components/priority_column.html b/src/staff/templates/staff/components/priority_column.html index ce76db60..d46c30d0 100644 --- a/src/staff/templates/staff/components/priority_column.html +++ b/src/staff/templates/staff/components/priority_column.html @@ -1,13 +1,15 @@ -{% if value == 3 %} +{% if record.is_urgent %} {% else %}
{% csrf_token %} + + {% comment %}Outlined flag icon does not work using the tag, so also using the SVG for the filled flag icon for consistency. If it can be fixed in the future it should.{% endcomment %} -