Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/cl_sii/extras/mm_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
raise ImportError("Package 'marshmallow' is required to use this module.") from exc

import datetime
from typing import Any, Mapping, Optional
from typing import Any, ClassVar, Mapping, Optional

import marshmallow.fields

Expand Down Expand Up @@ -47,11 +47,25 @@ class RutField(marshmallow.fields.Field):

"""

validate_dv: bool
validate_dv_by_default: ClassVar[bool] = False

default_error_messages = {
'invalid': 'Not a syntactically valid RUT.',
'invalid_dv': """RUT's "digito verificador" is incorrect.""",
'type': 'Invalid type.',
}

def __init__(
self,
*,
validate_dv: bool = validate_dv_by_default,
**kwargs: Any,
):
super().__init__(**kwargs)

self.validate_dv = validate_dv

def _serialize(
self, value: Optional[object], attr: str | None, obj: object, **kwargs: Any
) -> Optional[str]:
Expand All @@ -73,6 +87,13 @@ def _validated(self, value: Optional[object]) -> Optional[Rut]:
raise self.make_error('type') from exc
except ValueError as exc:
raise self.make_error('invalid') from exc

if self.validate_dv and validated is not None:
try:
validated.validate_dv(raise_exception=True)
except ValueError as exc:
raise self.make_error('invalid_dv') from exc

return validated


Expand Down
31 changes: 23 additions & 8 deletions src/tests/test_extras_mm_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class MyMmSchemaStrict(marshmallow.Schema):
emisor_rut = RutField(
required=True,
data_key='RUT of Emisor',
validate_dv=True,
)
other_field = marshmallow.fields.Integer(
required=False,
Expand All @@ -61,27 +62,27 @@ class MyMmSchemaStrict(marshmallow.Schema):
def test_load_ok_valid(self) -> None:
schema = self.LoadMyMmSchema()

data_valid_1 = {'RUT of Emisor': '1-1'}
data_valid_2 = {'RUT of Emisor': Rut('1-1')}
data_valid_3 = {'RUT of Emisor': ' 1.111.111-k \t '}
data_valid_1 = {'RUT of Emisor': '1-9'}
data_valid_2 = {'RUT of Emisor': Rut('1-9')}
data_valid_3 = {'RUT of Emisor': ' 1.111.119-k \t '}

result = schema.load(data_valid_1)
self.assertDictEqual(dict(result), {'emisor_rut': Rut('1-1')})
self.assertDictEqual(dict(result), {'emisor_rut': Rut('1-9')})

result = schema.load(data_valid_2)
self.assertDictEqual(dict(result), {'emisor_rut': Rut('1-1')})
self.assertDictEqual(dict(result), {'emisor_rut': Rut('1-9')})

result = schema.load(data_valid_3)
self.assertDictEqual(dict(result), {'emisor_rut': Rut('1111111-K')})
self.assertDictEqual(dict(result), {'emisor_rut': Rut('1111119-K')})

def test_dump_ok_valid(self) -> None:
schema = self.DumpMyMmSchema()

obj_valid_1 = self.MyObj(emisor_rut=Rut('1-1'))
obj_valid_1 = self.MyObj(emisor_rut=Rut('1-9'))
obj_valid_2 = self.MyObj(emisor_rut=None)

data = schema.dump(obj_valid_1)
self.assertDictEqual(data, {'emisor_rut': '1-1', 'other_field': None})
self.assertDictEqual(data, {'emisor_rut': '1-9', 'other_field': None})

data = schema.dump(obj_valid_2)
self.assertDictEqual(data, {'emisor_rut': None, 'other_field': None})
Expand Down Expand Up @@ -110,11 +111,13 @@ def test_dump_ok_strange(self) -> None:

def test_load_fail(self) -> None:
schema = self.LoadMyMmSchema()
schema_strict = self.MyMmSchemaStrict()

data_invalid_1 = {'RUT of Emisor': '123123123123'}
data_invalid_2 = {'RUT of Emisor': 123}
data_invalid_3 = {'RUT of Emisor': None}
data_invalid_4 = {}
data_invalid_5 = {'RUT of Emisor': '1-1'}

with self.assertRaises(marshmallow.ValidationError) as cm:
schema.load(data_invalid_1)
Expand All @@ -136,6 +139,18 @@ def test_load_fail(self) -> None:
cm.exception.messages, {'RUT of Emisor': ['Missing data for required field.']}
)

try:
schema.load(data_invalid_5)
except marshmallow.ValidationError as exc:
self.fail(f'{exc.__class__.__name__} raised')

with self.assertRaises(marshmallow.ValidationError) as cm:
schema_strict.load(data_invalid_5)
self.assertEqual(
cm.exception.messages,
{'RUT of Emisor': ["""RUT's "digito verificador" is incorrect."""]},
)

def test_dump_fail(self) -> None:
schema = self.DumpMyMmSchema()

Expand Down
Loading