feat: add group management for workers and shifts, including validation for overlapping groups
This commit is contained in:
@@ -46,6 +46,7 @@ class WorkerForm(forms.ModelForm):
|
||||
assign_as_block_preferences = forms.CharField(required=False, widget=forms.Textarea, help_text="JSON mapping shift_name->weight", label="Block preferences (JSON)")
|
||||
shift_fte_overrides = forms.CharField(required=False, widget=forms.Textarea, help_text="JSON mapping shift_name->fte", label="Shift FTE overrides (JSON)")
|
||||
exact_shifts = forms.CharField(required=False, widget=forms.Textarea, help_text="JSON mapping shift_name->exact_count", label="Exact shifts (JSON)")
|
||||
groups = forms.CharField(required=False, widget=forms.Textarea, help_text="JSON list of group names (e.g. [\"group1\", \"group2\"])", label="Groups (JSON)")
|
||||
previous_shifts = forms.CharField(required=False, widget=forms.Textarea, help_text="Free JSON structure for previous shifts", label="Previous shifts (JSON)")
|
||||
shift_balance_extra = forms.CharField(required=False, widget=forms.Textarea, help_text="JSON structure for extra shift-balance penalties", label="Shift balance extra (JSON)")
|
||||
allowed_multi_shift_sets = forms.CharField(required=False, widget=forms.Textarea, help_text="JSON list of sets (e.g. [[\"a\",\"b\"], ...])", label="Allowed multi-shift sets (JSON)")
|
||||
@@ -96,6 +97,7 @@ class WorkerForm(forms.ModelForm):
|
||||
"assign_as_block_preferences",
|
||||
"shift_fte_overrides",
|
||||
"exact_shifts",
|
||||
"groups",
|
||||
"previous_shifts",
|
||||
"shift_balance_extra",
|
||||
"allowed_multi_shift_sets",
|
||||
@@ -149,6 +151,7 @@ class WorkerForm(forms.ModelForm):
|
||||
"assign_as_block_preferences",
|
||||
"shift_fte_overrides",
|
||||
"exact_shifts",
|
||||
"groups",
|
||||
"previous_shifts",
|
||||
"shift_balance_extra",
|
||||
"allowed_multi_shift_sets",
|
||||
@@ -800,6 +803,16 @@ class ShiftForm(forms.Form):
|
||||
widget=forms.Textarea(attrs={"rows": 4, "class": "textarea"}),
|
||||
help_text="Optional JSON list of constraint objects for this shift (e.g. [{'name':'night','options':{}}])",
|
||||
)
|
||||
include_groups = forms.CharField(
|
||||
required=False,
|
||||
help_text="Comma separated list of groups that can work this shift (leave empty for all)",
|
||||
label="Include groups",
|
||||
)
|
||||
exclude_groups = forms.CharField(
|
||||
required=False,
|
||||
help_text="Comma separated list of groups that cannot work this shift",
|
||||
label="Exclude groups",
|
||||
)
|
||||
|
||||
def clean_sites(self):
|
||||
val = self.cleaned_data["sites"]
|
||||
@@ -841,3 +854,22 @@ class ShiftForm(forms.Form):
|
||||
raise
|
||||
except Exception as exc:
|
||||
raise forms.ValidationError(f"Invalid JSON for constraints: {exc}")
|
||||
|
||||
def clean_include_groups(self):
|
||||
val = self.cleaned_data.get("include_groups") or ""
|
||||
return [g.strip() for g in val.split(",") if g.strip()]
|
||||
|
||||
def clean_exclude_groups(self):
|
||||
val = self.cleaned_data.get("exclude_groups") or ""
|
||||
return [g.strip() for g in val.split(",") if g.strip()]
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
include = cleaned_data.get("include_groups") or []
|
||||
exclude = cleaned_data.get("exclude_groups") or []
|
||||
overlap = set(include).intersection(set(exclude))
|
||||
if overlap:
|
||||
raise forms.ValidationError(
|
||||
f"Include groups and Exclude groups cannot overlap. Overlapping groups: {', '.join(overlap)}"
|
||||
)
|
||||
return cleaned_data
|
||||
|
||||
Reference in New Issue
Block a user