Skip to content

Commit

Permalink
bulk update equipment
Browse files Browse the repository at this point in the history
  • Loading branch information
nicokant committed Jun 18, 2024
1 parent 361878f commit 00498fc
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 11 deletions.
65 changes: 59 additions & 6 deletions src/genlab_bestilling/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django import forms
from django.db.utils import IntegrityError
from django.forms.models import BaseModelForm, construct_instance
from formset.collection import FormCollection
from formset.renderers.tailwind import FormRenderer
from formset.utils import FormMixin
Expand Down Expand Up @@ -87,19 +89,70 @@ class Meta:
class EquipmentQuantityCollection(FormCollection):
min_siblings = 1
add_label = "Add equipment"
equipment = EquipmentOrderQuantityForm()
related_field = "order"
legend = "Equipments required"
equipments = EquipmentOrderQuantityForm()

def __init__(self, *args, order_id, **kwargs):
super().__init__(*args, **kwargs)
self.order_id = order_id

def retrieve_instance(self, data):
if data := data.get("equipment"):
if data := data.get("equipments"):
try:
return self.instance.equipments.get(id=data.get("id") or -1)
return EquimentOrderQuantity.objects.get(id=data.get("id") or -1)
except (AttributeError, EquimentOrderQuantity.DoesNotExist, ValueError):
return EquimentOrderQuantity(
quantity=data.get("quantity"), order=self.instance
equipment_id=data.get("equipment"),
quantity=data.get("quantity"),
)

def construct_instance(self, instance=None):
"""
Override method from:
https://github.com/jrief/django-formset/blob/releases/1.4/formset/collection.py#L447
"""
assert ( # noqa: S101
self.is_valid()
), f"Can not construct instance with invalid collection {self.__class__} object"
if self.has_many:
for valid_holders in self.valid_holders:
# first, handle holders which are forms
for _name, holder in valid_holders.items():
if not isinstance(holder, BaseModelForm):
continue
if holder.marked_for_removal:
holder.instance.delete()
continue
construct_instance(holder, holder.instance)
if getattr(self, "related_field", None):
setattr(holder.instance, self.related_field, instance)

# NOTE: only added this line to inject the order id
holder.instance.order_id = self.order_id

try:
holder.save()
except (IntegrityError, ValueError) as error:
# some errors are caught only after attempting to save
holder._update_errors(error)

# next, handle holders which are sub-collections
for _name, holder in valid_holders.items():
if callable(getattr(holder, "construct_instance", None)):
holder.construct_instance(holder.instance)
else:
for name, holder in self.valid_holders.items():
if callable(getattr(holder, "construct_instance", None)):
holder.construct_instance(instance)
elif isinstance(holder, BaseModelForm):
opts = holder._meta
holder.cleaned_data = self.cleaned_data[name]
holder.instance = instance
construct_instance(holder, instance, opts.fields, opts.exclude)
try:
holder.save()
except IntegrityError as error:
holder._update_errors(error)


class AnalysisOrderForm(FormMixin, forms.ModelForm):
default_renderer = FormRenderer(field_css_classes="mb-3")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,24 @@ <h3 class="text-4xl mb-5">Order #{{ object.id }} - {{ object.name }}</h3>
{% object-detail object=object %}


<h5 class="text-2xl my-5">Equipment</h5>
<h5 class="text-2xl my-5">Requested Equipment</h5>
{% #table headers=table_header %}
{% for oq in object.equipments.all %}
<tr>
{% #table-cell %}{{ oq.equipment }}{% /table-cell %}
{% #table-cell %}{{ oq.unit }}{% /table-cell %}
{% #table-cell %}{{ oq.quantity }}{% /table-cell %}
</tr>
{% empty %}
<tr>
<td colspan="3" class="text-center font-bold">No Equipment requested</td>
</tr>
{% endfor %}
{% /table %}

<div class="flex gap-5 my-5">
<a class="btn bg-primary" href="{% url 'project-equipment-update' project_id=object.project_id pk=object.id %}">Edit</a>
<a class="btn bg-secondary" href="{% url 'project-equipment-quantity-update' project_id=object.project_id pk=object.id %}">Edit requested equipment</a>
<button class="btn bg-secondary">Confirm Order</button>
</div>
{% endblock %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% extends "base.html" %}
{% load core %}

{% block content %}
<h3 class="text-4xl mb-5">{% if object.id %}{{ object }}{% else %}Create {{ view.model|verbose_name }}{% endif %}</h3>
<div class="flex gap-5 mb-5">
<a class="btn bg-primary" href="{% url 'project-equipment-detail' project_id=project.id pk=view.kwargs.pk %}"><i class="fas fa-arrow-left"></i> back</a>
</div>
{% formset endpoint=request.path csrf_token=csrf_token form_collection=form_collection %}
{% endblock %}
6 changes: 6 additions & 0 deletions src/genlab_bestilling/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
EquipmentOrderCreateView,
EquipmentOrderDetailView,
EquipmentOrderEditView,
EquipmentOrderQuantityUpdateView,
ProjectCreateView,
ProjectDetailView,
ProjectListView,
Expand Down Expand Up @@ -56,6 +57,11 @@
EquipmentOrderEditView.as_view(),
name="project-equipment-update",
),
path(
"projects/<int:project_id>/orders/equipment/<int:pk>/quantity/",
EquipmentOrderQuantityUpdateView.as_view(),
name="project-equipment-quantity-update",
),
path(
"projects/<int:project_id>/orders/analysis/create/",
AnalysisOrderCreateView.as_view(),
Expand Down
37 changes: 33 additions & 4 deletions src/genlab_bestilling/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from django.views.generic import CreateView, DetailView, UpdateView
from django_tables2.views import SingleTableView
from formset.views import (
BulkEditCollectionView,
FormViewMixin,
IncompleteSelectResponseMixin,
)
Expand All @@ -15,9 +16,10 @@
from .forms import (
AnalysisOrderForm,
EquipmentOrderForm,
EquipmentQuantityCollection,
ProjectForm,
)
from .models import AnalysisOrder, EquipmentOrder, Order, Project
from .models import AnalysisOrder, EquimentOrderQuantity, EquipmentOrder, Order, Project
from .tables import OrderTable, ProjectTable


Expand Down Expand Up @@ -71,6 +73,8 @@ class ProjectCreateView(FormsetCreateView):


class ProjectNestedMixin(LoginRequiredMixin):
project_id_accessor = "project_id"

def get_project(self):
return Project.objects.get(id=self.kwargs["project_id"])

Expand All @@ -83,7 +87,8 @@ def get(self, request, *args, **kwargs):
return super().get(request, *args, **kwargs)

def get_queryset(self) -> QuerySet[Any]:
return super().get_queryset().filter(project_id=self.project.id)
kwargs = {self.project_id_accessor: self.project.id}
return super().get_queryset().filter(**kwargs)

def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
ctx = super().get_context_data(**kwargs)
Expand Down Expand Up @@ -118,7 +123,7 @@ class EquipmentOrderEditView(

def get_success_url(self):
return reverse(
"project-analysis-detail",
"project-order-detail",
kwargs={"project_id": self.project.id, "pk": self.object.id},
)

Expand All @@ -132,7 +137,7 @@ class EquipmentOrderCreateView(

def get_success_url(self):
return reverse(
"project-analysis-detail",
"project-order-detail",
kwargs={"project_id": self.project.id, "pk": self.object.id},
)

Expand Down Expand Up @@ -172,3 +177,27 @@ class SamplesView(LoginRequiredMixin, DetailView):
def get_queryset(self) -> QuerySet[Any]:
self.project = Project.objects.get(id=self.kwargs["project_id"])
return super().get_queryset().filter(project_id=self.project.id)


class EquipmentOrderQuantityUpdateView(ProjectNestedMixin, BulkEditCollectionView):
collection_class = EquipmentQuantityCollection
template_name = "genlab_bestilling/equipmentorderquantity_form.html"
model = EquimentOrderQuantity
project_id_accessor = "order__project_id"

def get_collection_kwargs(self):
kwargs = super().get_collection_kwargs()
kwargs["order_id"] = self.kwargs["pk"]
return kwargs

def get_success_url(self):
return reverse(
"project-equipment-detail",
kwargs={"project_id": self.project.id, "pk": self.kwargs["pk"]},
)

def get_initial(self):
collection_class = self.get_collection_class()
queryset = self.get_queryset()
initial = collection_class(order_id=self.kwargs["pk"]).models_to_list(queryset)
return initial

0 comments on commit 00498fc

Please sign in to comment.