diff --git a/djangorota/rota/forms.py b/djangorota/rota/forms.py
index a7e3470..8d9b035 100644
--- a/djangorota/rota/forms.py
+++ b/djangorota/rota/forms.py
@@ -334,9 +334,32 @@ class ShiftForm(forms.Form):
help_text="Maximum allowed difference in allocated shifts for this shift (leave blank for default)",
)
+ # Allow entering shift-specific constraints as JSON. This should be a
+ # list of constraint dicts compatible with the scheduler's SingleShift
+ # `constraints` field. Example: `[{"name": "night", "options": {...}}]`
+ constraints = forms.CharField(
+ required=False,
+ widget=forms.Textarea(attrs={"rows": 4, "class": "textarea"}),
+ help_text="Optional JSON list of constraint objects for this shift (e.g. [{'name':'night','options':{}}])",
+ )
+
def clean_sites(self):
val = self.cleaned_data["sites"]
sites = [s.strip() for s in val.split(",") if s.strip()]
if not sites:
raise forms.ValidationError("At least one site is required")
return sites
+
+ def clean_constraints(self):
+ val = self.cleaned_data.get("constraints")
+ if not val:
+ return []
+ try:
+ parsed = json.loads(val)
+ if not isinstance(parsed, list):
+ raise forms.ValidationError("Constraints must be a JSON list of constraint objects")
+ return parsed
+ except forms.ValidationError:
+ raise
+ except Exception as exc:
+ raise forms.ValidationError(f"Invalid JSON for constraints: {exc}")
diff --git a/djangorota/rota/views.py b/djangorota/rota/views.py
index 7e89360..9bb6b6f 100644
--- a/djangorota/rota/views.py
+++ b/djangorota/rota/views.py
@@ -882,6 +882,7 @@ def shift_add(request, rota_id):
"workers_required": int(data["workers_required"]),
"assign_as_block": bool(data["assign_as_block"]),
"balance_offset": data.get("balance_offset"),
+ "constraints": data.get("constraints", []),
}
current = rota.shifts or []
@@ -930,6 +931,7 @@ def shift_edit(request, rota_id, idx):
"days": data["days"],
"workers_required": int(data["workers_required"]),
"assign_as_block": bool(data["assign_as_block"]),
+ "constraints": data.get("constraints", []),
}
current = rota.shifts or []
current[idx] = shift_dict
@@ -958,6 +960,7 @@ def shift_edit(request, rota_id, idx):
"workers_required": shift.get("workers_required"),
"assign_as_block": shift.get("assign_as_block", False),
"balance_offset": shift.get("balance_offset", None),
+ "constraints": json.dumps(shift.get("constraints", [])) if shift.get("constraints") is not None else "",
}
form = ShiftForm(initial=initial)
modal_html = render_to_string("rota/partials/shift_form_modal.html", {"form": form, "rota": rota, "form_action": request.path}, request=request)