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: 0 additions & 5 deletions src/genlab_bestilling/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
Organization,
Sample,
SampleMarkerAnalysis,
SampleStatusAssignment,
SampleType,
Species,
)
Expand Down Expand Up @@ -534,9 +533,5 @@ class AnalysisResultAdmin(ModelAdmin):
]


@admin.register(SampleStatusAssignment)
class SampleStatusAssignmentAdmin(ModelAdmin): ...


@admin.register(IsolationMethod)
class IsolationMethodAdmin(ModelAdmin): ...
50 changes: 16 additions & 34 deletions src/genlab_bestilling/api/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import uuid

from django.db import transaction
from django.db.models import Exists, OuterRef, QuerySet
from django.db.models import QuerySet
from django.http import HttpResponse
from django.views import View
from drf_spectacular.utils import extend_schema
Expand Down Expand Up @@ -33,7 +33,6 @@
Marker,
Sample,
SampleMarkerAnalysis,
SampleStatusAssignment,
SampleType,
Species,
)
Expand Down Expand Up @@ -98,9 +97,9 @@ class SampleViewset(ModelViewSet):
"project": "Projectnumber",
"isolation_method": "Isolation Method",
"qiagen_number": "Qiagen#",
"marked": "Marked",
"plucked": "Plucked",
"isolated": "Isolated",
"is_marked": "Marked",
"is_plucked": "Plucked",
"is_isolated": "Isolated",
"station": "Station",
"placement_in_fridge": "Placement in fridge",
"delivered_to_lab": "Delivered to lab",
Expand Down Expand Up @@ -128,9 +127,9 @@ class SampleViewset(ModelViewSet):
"type.name",
"isolation_method",
"qiagen_number",
"marked",
"plucked",
"isolated",
"is_marked",
"is_plucked",
"is_isolated",
],
"Elvemusling": [
"genlab_id",
Expand All @@ -146,9 +145,9 @@ class SampleViewset(ModelViewSet):
"isolation_method",
"qiagen_number",
"placement_in_fridge",
"marked",
"plucked",
"isolated",
"is_marked",
"is_plucked",
"is_isolated",
],
"Terrestrisk": [
"genlab_id",
Expand All @@ -161,9 +160,9 @@ class SampleViewset(ModelViewSet):
"order",
"analysis_orders",
"notes",
"marked",
"plucked",
"isolated",
"is_marked",
"is_plucked",
"is_isolated",
"isolation_method",
"qiagen_number",
],
Expand All @@ -179,9 +178,9 @@ class SampleViewset(ModelViewSet):
"order",
"analysis_orders",
"notes",
"marked",
"plucked",
"isolated",
"is_marked",
"is_plucked",
"is_isolated",
"isolation_method",
"qiagen_number",
],
Expand All @@ -199,23 +198,6 @@ def get_queryset(self) -> QuerySet:
"order__genrequest__area",
"location",
)
.annotate(
is_marked=Exists(
SampleStatusAssignment.objects.filter(
sample=OuterRef("pk"), status="marked"
)
),
is_plucked=Exists(
SampleStatusAssignment.objects.filter(
sample=OuterRef("pk"), status="plucked"
)
),
is_isolated=Exists(
SampleStatusAssignment.objects.filter(
sample=OuterRef("pk"), status="isolated"
)
),
)
.order_by("genlab_id", "type")
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.2.3 on 2025-07-17 08:16

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("genlab_bestilling", "0027_alter_isolationmethod_name"),
]

operations = [
migrations.AddField(
model_name="sample",
name="is_isolated",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="sample",
name="is_marked",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="sample",
name="is_plucked",
field=models.BooleanField(default=False),
),
migrations.DeleteModel(
name="SampleStatusAssignment",
),
]
36 changes: 4 additions & 32 deletions src/genlab_bestilling/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,10 @@ class Sample(models.Model):
year = models.IntegerField()
notes = models.TextField(null=True, blank=True)

is_marked = models.BooleanField(default=False)
is_plucked = models.BooleanField(default=False)
is_isolated = models.BooleanField(default=False)

# "Merknad" in the Excel sheet.
internal_note = models.TextField(null=True, blank=True)
pop_id = models.CharField(max_length=150, null=True, blank=True)
Expand Down Expand Up @@ -770,38 +774,6 @@ def generate_genlab_id(self, commit: bool = True) -> str:
# assignee (one or plus?)


class SampleStatusAssignment(models.Model):
class SampleStatus(models.TextChoices):
MARKED = "marked", _("Marked")
PLUCKED = "plucked", _("Plucked")
ISOLATED = "isolated", _("Isolated")

sample = models.ForeignKey(
f"{an}.Sample",
on_delete=models.CASCADE,
related_name="sample_status_assignments",
)
status = models.CharField(
choices=SampleStatus.choices,
null=True,
blank=True,
verbose_name="Sample status",
help_text="The status of the sample in the lab",
)
order = models.ForeignKey(
f"{an}.Order",
on_delete=models.CASCADE,
related_name="sample_status_assignments",
null=True,
blank=True,
)

assigned_at = models.DateTimeField(auto_now_add=True)

class Meta:
unique_together = ("sample", "status", "order")


class SampleIsolationMethod(models.Model):
sample = models.ForeignKey(
f"{an}.Sample",
Expand Down
7 changes: 7 additions & 0 deletions src/staff/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,25 +251,31 @@ class SampleStatusTable(tables.Table):
orderable=True,
yesno="✔,-",
default=False,
accessor="is_marked",
)
plucked = tables.BooleanColumn(
verbose_name="Plucked",
orderable=True,
yesno="✔,-",
default=False,
accessor="is_plucked",
)
isolated = tables.BooleanColumn(
verbose_name="Isolated",
orderable=True,
yesno="✔,-",
default=False,
accessor="is_isolated",
)

class Meta:
model = Sample
fields = [
"checked",
"genlab_id",
"marked",
"plucked",
"isolated",
"internal_note",
"isolation_method",
"type",
Expand All @@ -284,6 +290,7 @@ class Meta:
"internal_note",
"isolation_method",
]
order_by = ()

def render_checked(self, record: Any) -> str:
return mark_safe( # noqa: S308
Expand Down
17 changes: 10 additions & 7 deletions src/staff/templatetags/order_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.db import models

from capps.users.models import User
from genlab_bestilling.models import Area, Order, SampleStatusAssignment
from genlab_bestilling.models import Area, Order

from ..tables import (
AssignedOrderTable,
Expand Down Expand Up @@ -167,12 +167,15 @@ def assigned_orders_table(context: dict) -> dict:
)
.select_related("genrequest")
.annotate(
isolated_sample_count=models.Count(
"sample_status_assignments",
distinct=True,
filter=models.Q(
sample_status_assignments__status=SampleStatusAssignment.SampleStatus.ISOLATED,
),
isolated_sample_count=models.Case(
models.When(
extractionorder__isnull=False,
then=models.Count(
"extractionorder__samples",
filter=models.Q(extractionorder__samples__is_isolated=True),
distinct=True,
),
)
),
sample_count=models.Case(
models.When(
Expand Down
80 changes: 80 additions & 0 deletions src/staff/templatetags/table_header_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from django import template
from django.http import HttpRequest

register = template.Library()


@register.inclusion_tag("django_tables2/header.html", takes_context=True)
def render_header(context: dict) -> dict:
url = Url(context["table"].prefixed_order_by_field, context["request"])
for column in context["table"].columns:
sort_url, remove_sort_url, first_sort, descending = url.get_sort_url(
column.name
)
column.ext = {
"sort_url": sort_url,
"remove_sort_url": remove_sort_url,
"first_sort": first_sort,
"descending": descending,
"next": remove_sort_url if not first_sort and descending else sort_url,
}

return context


class Url:
"""
Based on code from:
https://github.com/TheRealVizard/django-table-sort/blob/main/django_table_sort/table.py
"""

def __init__(self, sort_key_name: str, request: HttpRequest):
self.sort_key_name = sort_key_name
self.request = request

def contains_field(self, lookups: list, field: str) -> int:
"""Check if the field is in the sort lookups."""
try:
return lookups.index(field)
except ValueError:
return -1

def get_sort_url(self, field: str) -> tuple[str, str, bool, bool]:
"""Generate the urls to sort the table for the given field."""
lookups = self.request.GET.copy()
removed_lookup = self.request.GET.copy()

first_sort = True
descending = True

if self.sort_key_name in lookups.keys():
current_order = lookups.getlist(self.sort_key_name, [])
removed_order = current_order.copy()
position = self.contains_field(current_order, field)
if position != -1:
first_sort = False
descending = False
current_order[position] = f"-{field}"
removed_order.remove(field)
else:
position = self.contains_field(current_order, f"-{field}")
if position != -1:
first_sort = False
current_order[position] = field
removed_order.remove(f"-{field}")
else:
current_order.append(field)
lookups.setlist(self.sort_key_name, current_order)
if len(removed_order) >= 1:
removed_lookup.setlist(self.sort_key_name, removed_order)
else:
removed_lookup.pop(self.sort_key_name)
else:
lookups.setlist(self.sort_key_name, [field])

return (
lookups.urlencode(),
removed_lookup.urlencode(),
first_sort,
descending,
)
Loading