Skip to content

Commit cde749b

Browse files
committed
[#5006] Updated AddressValueSerializer to adapt manual filling of streetname and city
Updated street name and city serializer fields in order to be able to require these fields in case the component is required.
1 parent 52cb077 commit cde749b

File tree

4 files changed

+88
-6
lines changed

4 files changed

+88
-6
lines changed

src/openforms/contrib/brk/constants.py

+1
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ class AddressValue(TypedDict):
99
city: NotRequired[str]
1010
streetName: NotRequired[str]
1111
secretStreetCity: NotRequired[str]
12+
autoPopulated: NotRequired[bool]

src/openforms/formio/components/custom.py

+26-4
Original file line numberDiff line numberDiff line change
@@ -410,27 +410,43 @@ class AddressValueSerializer(serializers.Serializer):
410410
streetName = serializers.CharField(
411411
label=_("street name"),
412412
help_text=_("Derived street name"),
413-
required=False,
414-
allow_blank=True,
415413
)
416414
city = serializers.CharField(
417415
label=_("city"),
418416
help_text=_("Derived city"),
419-
required=False,
420-
allow_blank=True,
421417
)
422418
secretStreetCity = serializers.CharField(
423419
label=_("city and street name secret"),
424420
help_text=_("Secret for the combination of city and street name"),
425421
required=False,
426422
allow_blank=True,
427423
)
424+
autoPopulated = serializers.BooleanField(
425+
label=_("city and street name auto populated"),
426+
help_text=_("Whether city and street name have been retrieved from the API"),
427+
default=False,
428+
)
428429

429430
def __init__(self, **kwargs):
430431
self.derive_address = kwargs.pop("derive_address", None)
431432
self.component = kwargs.pop("component", None)
432433
super().__init__(**kwargs)
433434

435+
def get_fields(self):
436+
fields = super().get_fields()
437+
438+
# Street name and city are only required when the addressNL component is
439+
# required, so we modify the 'required' and 'allow_blank' accordingly
440+
if self.component and (
441+
not (validate := self.component.get("validate"))
442+
or validate.get("required") is False
443+
):
444+
fields["city"].required = False
445+
fields["city"].allow_blank = True
446+
fields["streetName"].required = False
447+
fields["streetName"].allow_blank = True
448+
return fields
449+
434450
def validate_city(self, value: str) -> str:
435451
if city_regex := glom(
436452
self.component, "openForms.components.city.validate.pattern", default=""
@@ -457,10 +473,16 @@ def validate_postcode(self, value: str) -> str:
457473
def validate(self, attrs):
458474
attrs = super().validate(attrs)
459475

476+
auto_populated = attrs.get("autoPopulated", False)
460477
city = attrs.get("city", "")
461478
street_name = attrs.get("streetName", "")
462479

463480
if self.derive_address:
481+
# when the user fills in manually the city and the street name we do not
482+
# need to check the secret city - street name combination
483+
if not auto_populated:
484+
return attrs
485+
464486
existing_hmac = attrs.get("secretStreetCity", "")
465487
postcode = attrs.get("postcode", "")
466488
number = attrs.get("houseNumber", "")

src/openforms/formio/formatters/custom.py

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class AddressValue(TypedDict):
4242
city: NotRequired[str]
4343
streetName: NotRequired[str]
4444
secretStreetCity: NotRequired[str]
45+
autoPopulated: NotRequired[bool]
4546

4647

4748
class AddressNLFormatter(FormatterBase):

src/openforms/formio/tests/validation/test_addressnl.py

+60-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def test_addressNL_field_regex_pattern_success(self):
106106

107107
self.assertTrue(is_valid)
108108

109-
def test_missing_keys(self):
109+
def test_missing_keys_when_component_optional(self):
110110
component: AddressNLComponent = {
111111
"key": "addressNl",
112112
"type": "addressNL",
@@ -129,6 +129,34 @@ def test_missing_keys(self):
129129
self.assertEqual(postcode_error.code, "required")
130130
self.assertEqual(house_number_error.code, "required")
131131

132+
def test_missing_keys_when_component_required(self):
133+
component: AddressNLComponent = {
134+
"key": "addressNl",
135+
"type": "addressNL",
136+
"label": "AddressNL missing keys",
137+
"deriveAddress": False,
138+
"validate": {"required": True},
139+
}
140+
141+
invalid_values = {
142+
"addressNl": {
143+
"houseLetter": "A",
144+
}
145+
}
146+
147+
is_valid, errors = validate_formio_data(component, invalid_values)
148+
149+
postcode_error = extract_error(errors["addressNl"], "postcode")
150+
house_number_error = extract_error(errors["addressNl"], "houseNumber")
151+
street_name_error = extract_error(errors["addressNl"], "streetName")
152+
city_error = extract_error(errors["addressNl"], "city")
153+
154+
self.assertFalse(is_valid)
155+
self.assertEqual(postcode_error.code, "required")
156+
self.assertEqual(house_number_error.code, "required")
157+
self.assertEqual(street_name_error.code, "required")
158+
self.assertEqual(city_error.code, "required")
159+
132160
def test_plugin_validator(self):
133161
with replace_validators_registry() as register:
134162
register("postcode_validator")(PostcodeValidator)
@@ -150,6 +178,8 @@ def test_plugin_validator(self):
150178
"houseNumber": "3",
151179
"houseLetter": "A",
152180
"houseNumberAddition": "",
181+
"streetName": "Keizersgracht",
182+
"city": "Amsterdam",
153183
}
154184
},
155185
)
@@ -176,7 +206,7 @@ def test_addressNL_field_secret_success(self):
176206
"key": "addressNl",
177207
"type": "addressNL",
178208
"label": "AddressNL secret success",
179-
"deriveAddress": False,
209+
"deriveAddress": True,
180210
}
181211

182212
message = "1015CJ/117/Amsterdam/Keizersgracht"
@@ -190,6 +220,7 @@ def test_addressNL_field_secret_success(self):
190220
"city": "Amsterdam",
191221
"streetName": "Keizersgracht",
192222
"secretStreetCity": secret,
223+
"autoPopulated": True,
193224
}
194225
}
195226

@@ -214,6 +245,7 @@ def test_addressNL_field_secret_failure(self):
214245
"city": "Amsterdam",
215246
"streetName": "Keizersgracht",
216247
"secretStreetCity": "invalid secret",
248+
"autoPopulated": True,
217249
}
218250
}
219251

@@ -224,6 +256,32 @@ def test_addressNL_field_secret_failure(self):
224256
self.assertFalse(is_valid)
225257
self.assertEqual(secret_error.code, "invalid")
226258

259+
def test_addressNL_field_secret_not_used_when_manual_address(self):
260+
component: AddressNLComponent = {
261+
"key": "addressNl",
262+
"type": "addressNL",
263+
"label": "AddressNL secret failure",
264+
"deriveAddress": True,
265+
"validate": {"required": False},
266+
}
267+
268+
data = {
269+
"addressNl": {
270+
"postcode": "1015CJ",
271+
"houseNumber": "117",
272+
"houseLetter": "",
273+
"houseNumberAddition": "",
274+
"city": "Amsterdam",
275+
"streetName": "Keizersgracht",
276+
"secretStreetCity": "a secret",
277+
"autoPopulated": False,
278+
}
279+
}
280+
281+
is_valid, _ = validate_formio_data(component, data)
282+
283+
self.assertTrue(is_valid)
284+
227285
def test_addressNL_field_missing_city(self):
228286
component: AddressNLComponent = {
229287
"key": "addressNl",

0 commit comments

Comments
 (0)