Skip to content

Commit

Permalink
Bulk create quotas redo without validityperiodform
Browse files Browse the repository at this point in the history
  • Loading branch information
mattjamc committed Mar 18, 2024
1 parent 4c05783 commit 4c27d3a
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 69 deletions.
26 changes: 26 additions & 0 deletions common/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,32 @@ def compress(self, data_list):
return None


class DateInputFieldTakesParameters(DateInputField):
def __init__(self, day, month, year, **kwargs):
error_messages = {
"required": "Enter the day, month and year",
"incomplete": "Enter the day, month and year",
}
fields = (day, month, year)

forms.MultiValueField.__init__(
self,
error_messages=error_messages,
fields=fields,
**kwargs,
)

def compress(self, data_list):
day, month, year = data_list or [None, None, None]
if day and month and year:
try:
return date(day=int(day), month=int(month), year=int(year))
except ValueError as e:
raise ValidationError(str(e).capitalize()) from e
else:
return None


class GovukDateRangeField(DateRangeField):
base_field = DateInputFieldFixed

Expand Down
37 changes: 37 additions & 0 deletions common/static/common/js/addNewQuotaDefinitionForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const addNewForm = (event) => {
event.preventDefault();

let numForms = document.querySelectorAll(".quota-definition-row").length;
let fieldset = document.querySelector(".quota-definition-row");
let formset = fieldset.parentNode;
let newForm = fieldset.cloneNode(true);

newForm.innerHTML = newForm.innerHTML.replaceAll('name="volume_0"', 'name="volume_' + numForms + '"');
newForm.innerHTML = newForm.innerHTML.replaceAll('name="start_date_0_0"', 'name="start_date_' + numForms + '_0"');
newForm.innerHTML = newForm.innerHTML.replaceAll('name="start_date_0_1"', 'name="start_date_' + numForms + '_1"');
newForm.innerHTML = newForm.innerHTML.replaceAll('name="start_date_0_2"', 'name="start_date_' + numForms + '_2"');
newForm.innerHTML = newForm.innerHTML.replaceAll('name="end_date_0_0"', 'name="end_date_' + numForms + '_0"');
newForm.innerHTML = newForm.innerHTML.replaceAll('name="end_date_0_1"', 'name="end_date_' + numForms + '_1"');
newForm.innerHTML = newForm.innerHTML.replaceAll('name="end_date_0_2"', 'name="end_date_' + numForms + '_2"');

let formFields = newForm.querySelectorAll("input");
for (let field of formFields.values()) {
field.value = "";
}

let submitButton = document.getElementById("submit-id-submit");
formset.insertBefore(newForm, submitButton);

let addNewButton = document.querySelector("#add-new-definition");
addNewButton.scrollIntoView(false);
}

const initAddNewDefinition = () => {
const btn = document.querySelector("#add-new-definition");

if (btn) {
btn.addEventListener("click", addNewForm);
}
}

export { initAddNewDefinition }
2 changes: 2 additions & 0 deletions common/static/common/js/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ require.context('govuk-frontend/govuk/assets');
import showHideCheckboxes from './showHideCheckboxes';
import { initAutocomplete } from './autocomplete';
import { initAutocompleteProgressiveEnhancement } from './autocompleteProgressiveEnhancement';
import { initAddNewDefinition } from './addNewQuotaDefinitionForm';
import { initAddNewEnhancement } from './addNewForm';
import { initCopyToNextDuties } from './copyDuties';
import { initAll } from 'govuk-frontend';
Expand All @@ -20,6 +21,7 @@ showHideCheckboxes();
// Initialise accessible-autocomplete components without a `name` attr in order
// to avoid the "dummy" autocomplete field being submitted as part of the form
// to the server.
initAddNewDefinition();
initAddNewEnhancement();
initAutocomplete(false);
initCopyToNextDuties();
Expand Down
182 changes: 154 additions & 28 deletions reference_documents/forms/preferential_quota_forms.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from datetime import date

from crispy_forms_gds.helper import FormHelper
from crispy_forms_gds.layout import Div
from crispy_forms_gds.layout import Field
Expand All @@ -9,7 +11,11 @@
from django import forms
from django.core.exceptions import ValidationError

from common.forms import DateInputFieldFixed
from common.forms import DateInputFieldTakesParameters
from common.forms import GovukDateRangeField
from common.forms import ValidityPeriodForm
from common.util import TaricDateRange
from reference_documents.models import PreferentialQuota
from reference_documents.models import PreferentialQuotaOrderNumber
from reference_documents.validators import commodity_code_validator
Expand Down Expand Up @@ -110,7 +116,7 @@ def clean_quota_duty_rate(self):
return data


class PreferentialQuotaBulkCreate(ValidityPeriodForm, forms.ModelForm):
class PreferentialQuotaBulkCreate(forms.Form):
commodity_codes = forms.CharField(
label="Commodity codes",
widget=forms.Textarea,
Expand Down Expand Up @@ -138,15 +144,6 @@ class PreferentialQuotaBulkCreate(ValidityPeriodForm, forms.ModelForm):
},
)

volume = forms.CharField(
validators=[],
error_messages={
"invalid": "Volume invalid",
"required": "Volume is required",
},
help_text="<br>",
)

measurement = forms.CharField(
validators=[],
error_messages={
Expand All @@ -155,8 +152,56 @@ class PreferentialQuotaBulkCreate(ValidityPeriodForm, forms.ModelForm):
},
)

def get_variant_index(self, post_data):
result = [0]
if "data" in post_data.keys():
for key in post_data["data"].keys():
if key.startswith("start_date_"):
variant_index = int(key.replace("start_date_", "").split("_")[0])
result.append(variant_index)
result = list(set(result))
result.sort()
return result

def __init__(self, reference_document_version, *args, **kwargs):
super().__init__(*args, **kwargs)
self.variant_indices = self.get_variant_index(kwargs)
self.fields["start_date_0"] = DateInputFieldFixed(
label="Start date",
required=True,
)
self.fields["end_date_0"] = DateInputFieldFixed(label="End date", required=True)
self.fields["volume_0"] = forms.CharField(
error_messages={
"invalid": "Volume invalid",
"required": "Volume is required",
},
help_text="<br>",
)
for index in self.variant_indices:
self.fields[f"start_date_{index}_0"] = forms.CharField()
self.fields[f"start_date_{index}_1"] = forms.CharField()
self.fields[f"start_date_{index}_2"] = forms.CharField()
self.fields[f"start_date_{index}"] = DateInputFieldTakesParameters(
day=self.fields[f"start_date_{index}_0"],
month=self.fields[f"start_date_{index}_1"],
year=self.fields[f"start_date_{index}_2"],
label="Start date",
)
self.fields[f"end_date_{index}_0"] = forms.CharField()
self.fields[f"end_date_{index}_1"] = forms.CharField()
self.fields[f"end_date_{index}_2"] = forms.CharField()
self.fields[f"end_date_{index}"] = DateInputFieldTakesParameters(
day=self.fields[f"end_date_{index}_0"],
month=self.fields[f"end_date_{index}_1"],
year=self.fields[f"end_date_{index}_2"],
label="End date",
)
self.fields[f"valid_between_{index}"] = GovukDateRangeField()
self.fields[f"volume_{index}"] = forms.CharField(
label="Volume",
help_text="<br>",
)
self.fields["preferential_quota_order_number"].queryset = (
PreferentialQuotaOrderNumber.objects.all()
.filter(reference_document_version=reference_document_version)
Expand All @@ -165,7 +210,7 @@ def __init__(self, reference_document_version, *args, **kwargs):
self.fields[
"preferential_quota_order_number"
].label_from_instance = lambda obj: f"{obj.quota_order_number}"
self.fields["end_date"].help_text = ""
self.fields["end_date_0"].help_text = ""
self.helper = FormHelper(self)
self.helper.label_size = Size.SMALL
self.helper.legend_size = Size.SMALL
Expand All @@ -184,18 +229,24 @@ def __init__(self, reference_document_version, *args, **kwargs):
),
Fieldset(
Div(
Field("start_date"),
Field(
"start_date_0",
),
),
Div(
Field("end_date"),
Field(
"end_date_0",
),
),
Div(
Field(
"volume",
"volume_0",
label="Volume",
field_width=Fixed.TEN,
),
),
style="display: grid; grid-template-columns: 2fr 2fr 1fr",
css_class="quota-definition-row",
),
Submit(
"submit",
Expand All @@ -204,23 +255,98 @@ def __init__(self, reference_document_version, *args, **kwargs):
data_prevent_double_click="true",
),
)
for index in self.variant_indices[1:]:
self.helper.layout.insert(
-1,
Fieldset(
Div(
Field(
f"start_date_{index}",
),
),
Div(
Field(
f"end_date_{index}",
),
),
Div(
Field(
f"volume_{index}",
field_width=Fixed.TEN,
),
),
style="display: grid; grid-template-columns: 2fr 2fr 1fr",
css_class="quota-definition-row",
),
)

def clean(self):
cleaned_data = super().clean()
commodity_codes = cleaned_data.get("commodity_codes").splitlines()
for commodity_code in commodity_codes:
try:
commodity_code_validator(commodity_code)
except ValidationError:
# Clean commodity codes
commodity_codes = cleaned_data.get("commodity_codes")
if commodity_codes:
for commodity_code in commodity_codes.splitlines():
try:
commodity_code_validator(commodity_code)
except ValidationError:
self.add_error(
"commodity_codes",
"Ensure all commodity codes are 10 digits and each on a new line",
)
# Clean validity periods
for index in self.variant_indices:
self.clean_validity_period(
self,
cleaned_data,
valid_between_field_name=f"valid_between_{index}",
start_date_field_name=f"start_date_{index}",
end_date_field_name=f"end_date_{index}",
)

@staticmethod
def clean_validity_period(
self,
cleaned_data,
valid_between_field_name,
start_date_field_name,
end_date_field_name,
):
start_date = cleaned_data.pop(start_date_field_name, None)
end_date = cleaned_data.pop(end_date_field_name, None)

# Data may not be present, e.g. if the user skips ahead in the sidebar
valid_between = self.initial.get(valid_between_field_name)
if end_date and start_date and end_date < start_date:
if valid_between:
if start_date != valid_between.lower:
self.add_error(
start_date_field_name,
"The start date must be the same as or before the end date.",
)
if end_date != self.initial[valid_between_field_name].upper:
self.add_error(
end_date_field_name,
"The end date must be the same as or after the start date.",
)
else:
self.add_error(
"commodity_codes",
"Ensure all commodity codes are 10 digits and each on a new line",
end_date_field_name,
"The end date must be the same as or after the start date.",
)
cleaned_data[valid_between_field_name] = TaricDateRange(start_date, end_date)

class Meta:
model = PreferentialQuota
fields = [
"preferential_quota_order_number",
"quota_duty_rate",
"measurement",
]
if start_date:
day, month, year = (start_date.day, start_date.month, start_date.year)
self.fields[start_date_field_name].initial = date(
day=int(day),
month=int(month),
year=int(year),
)

if end_date:
day, month, year = (end_date.day, end_date.month, end_date.year)
self.fields[end_date_field_name].initial = date(
day=int(day),
month=int(month),
year=int(year),
)
Loading

0 comments on commit 4c27d3a

Please sign in to comment.