From b59925d3e29eac218335cb05f69d51a4ad11770d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Larra=C3=ADn?= Date: Sat, 11 Apr 2020 21:53:37 -0400 Subject: [PATCH 1/2] dte.data_models.DteDataL2: make some fields optional Fields `emisor_razon_social` and `receptor_razon_social` are now optional. --- cl_sii/dte/data_models.py | 18 ++++++++++-------- tests/test_dte_data_models.py | 19 ++++++------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/cl_sii/dte/data_models.py b/cl_sii/dte/data_models.py index be44f07a..b93c0775 100644 --- a/cl_sii/dte/data_models.py +++ b/cl_sii/dte/data_models.py @@ -347,12 +347,12 @@ class DteDataL2(DteDataL1): # fields ########################################################################### - emisor_razon_social: str = dc_field() + emisor_razon_social: Optional[str] = dc_field() """ "Razón social" (legal name) of the "emisor" of the DTE. """ - receptor_razon_social: str = dc_field() + receptor_razon_social: Optional[str] = dc_field() """ "Razón social" (legal name) of the "receptor" of the DTE. """ @@ -405,13 +405,15 @@ def __post_init__(self) -> None: """ super().__post_init__() - if not isinstance(self.emisor_razon_social, str): - raise TypeError("Inappropriate type of 'emisor_razon_social'.") - validate_contribuyente_razon_social(self.emisor_razon_social) + if self.emisor_razon_social is not None: + if not isinstance(self.emisor_razon_social, str): + raise TypeError("Inappropriate type of 'emisor_razon_social'.") + validate_contribuyente_razon_social(self.emisor_razon_social) - if not isinstance(self.receptor_razon_social, str): - raise TypeError("Inappropriate type of 'receptor_razon_social'.") - validate_contribuyente_razon_social(self.receptor_razon_social) + if self.receptor_razon_social is not None: + if not isinstance(self.receptor_razon_social, str): + raise TypeError("Inappropriate type of 'receptor_razon_social'.") + validate_contribuyente_razon_social(self.receptor_razon_social) if self.fecha_vencimiento_date is not None: if not isinstance(self.fecha_vencimiento_date, date): diff --git a/tests/test_dte_data_models.py b/tests/test_dte_data_models.py index 2af47153..c79702bd 100644 --- a/tests/test_dte_data_models.py +++ b/tests/test_dte_data_models.py @@ -238,19 +238,12 @@ def test_init_fail_razon_social_empty(self) -> None: ) self.assertEqual(cm.exception.args, ("Value must not be empty.", )) - def test_init_fail_razon_social_none(self) -> None: - with self.assertRaises(TypeError) as cm: - dataclasses.replace( - self.dte_l2_1, - emisor_razon_social=None, - ) - self.assertEqual(cm.exception.args, ("Inappropriate type of 'emisor_razon_social'.", )) - with self.assertRaises(TypeError) as cm: - dataclasses.replace( - self.dte_l2_1, - receptor_razon_social=None, - ) - self.assertEqual(cm.exception.args, ("Inappropriate type of 'receptor_razon_social'.", )) + def test_init_ok_razon_social_none(self) -> None: + _ = dataclasses.replace( + self.dte_l2_1, + emisor_razon_social=None, + receptor_razon_social=None, + ) def test_init_fail_regression_signature_value_bytes_with_x20(self) -> None: bytes_value_with_x20_as_base64 = 'IN2pkDBxqDnGl4Pfvboi' From 1f214634f5a694d336bd028fffcfefe5da5cfa21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Larra=C3=ADn?= Date: Mon, 13 Apr 2020 20:24:22 -0400 Subject: [PATCH 2/2] rcv.data_models: make unnecessary fields optional For subclasses of `RcvDetalleEntry` only one of these fields is necessary, which depends on the specific class. Later on the optional field will be removed; this is the first step for achieving that without breaking other people's code. - `emisor_razon_social` - `receptor_razon_social` --- cl_sii/rcv/data_models.py | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/cl_sii/rcv/data_models.py b/cl_sii/rcv/data_models.py index 3bf416d4..4c68fc2c 100644 --- a/cl_sii/rcv/data_models.py +++ b/cl_sii/rcv/data_models.py @@ -224,7 +224,7 @@ class RvDetalleEntry(RcvDetalleEntry): RCV_KIND = RcvKind.VENTAS RC_ESTADO_CONTABLE = None - emisor_razon_social: str = dc_field() + emisor_razon_social: Optional[str] = dc_field() """ "Razón social" (legal name) of the "emisor" of the "documento". """ @@ -244,9 +244,10 @@ class RvDetalleEntry(RcvDetalleEntry): def __post_init__(self) -> None: super().__post_init__() - if not isinstance(self.emisor_razon_social, str): - raise TypeError("Inappropriate type of 'emisor_razon_social'.") - cl_sii.dte.data_models.validate_contribuyente_razon_social(self.emisor_razon_social) + if self.emisor_razon_social is not None: + if not isinstance(self.emisor_razon_social, str): + raise TypeError("Inappropriate type of 'emisor_razon_social'.") + cl_sii.dte.data_models.validate_contribuyente_razon_social(self.emisor_razon_social) if not isinstance(self.receptor_razon_social, str): raise TypeError("Inappropriate type of 'receptor_razon_social'.") @@ -280,7 +281,7 @@ class RcRegistroDetalleEntry(RcvDetalleEntry): # TODO: docstring # TODO: can it be None? What happens for those "tipo docto" that do not have a receptor? - receptor_razon_social: str = dc_field() + receptor_razon_social: Optional[str] = dc_field() # TODO: docstring # note: must be timezone-aware. @@ -293,9 +294,10 @@ def __post_init__(self) -> None: raise TypeError("Inappropriate type of 'emisor_razon_social'.") cl_sii.dte.data_models.validate_contribuyente_razon_social(self.emisor_razon_social) - if not isinstance(self.receptor_razon_social, str): - raise TypeError("Inappropriate type of 'receptor_razon_social'.") - cl_sii.dte.data_models.validate_contribuyente_razon_social(self.receptor_razon_social) + if self.receptor_razon_social is not None: + if not isinstance(self.receptor_razon_social, str): + raise TypeError("Inappropriate type of 'receptor_razon_social'.") + cl_sii.dte.data_models.validate_contribuyente_razon_social(self.receptor_razon_social) if self.fecha_acuse_dt is not None: if not isinstance(self.fecha_acuse_dt, datetime): @@ -331,7 +333,7 @@ class RcReclamadoDetalleEntry(RcvDetalleEntry): # TODO: docstring # TODO: can it be None? What happens for those "tipo docto" that do not have a receptor? - receptor_razon_social: str = dc_field() + receptor_razon_social: Optional[str] = dc_field() # TODO: docstring # note: must be timezone-aware. @@ -344,9 +346,10 @@ def __post_init__(self) -> None: raise TypeError("Inappropriate type of 'emisor_razon_social'.") cl_sii.dte.data_models.validate_contribuyente_razon_social(self.emisor_razon_social) - if not isinstance(self.receptor_razon_social, str): - raise TypeError("Inappropriate type of 'receptor_razon_social'.") - cl_sii.dte.data_models.validate_contribuyente_razon_social(self.receptor_razon_social) + if self.receptor_razon_social is not None: + if not isinstance(self.receptor_razon_social, str): + raise TypeError("Inappropriate type of 'receptor_razon_social'.") + cl_sii.dte.data_models.validate_contribuyente_razon_social(self.receptor_razon_social) if self.fecha_reclamo_dt is not None: if not isinstance(self.fecha_reclamo_dt, datetime): @@ -371,7 +374,7 @@ class RcPendienteDetalleEntry(RcvDetalleEntry): # TODO: docstring # TODO: can it be None? What happens for those "tipo docto" that do not have a receptor? - receptor_razon_social: str = dc_field() + receptor_razon_social: Optional[str] = dc_field() def __post_init__(self) -> None: super().__post_init__() @@ -380,6 +383,7 @@ def __post_init__(self) -> None: raise TypeError("Inappropriate type of 'emisor_razon_social'.") cl_sii.dte.data_models.validate_contribuyente_razon_social(self.emisor_razon_social) - if not isinstance(self.receptor_razon_social, str): - raise TypeError("Inappropriate type of 'receptor_razon_social'.") - cl_sii.dte.data_models.validate_contribuyente_razon_social(self.receptor_razon_social) + if self.receptor_razon_social is not None: + if not isinstance(self.receptor_razon_social, str): + raise TypeError("Inappropriate type of 'receptor_razon_social'.") + cl_sii.dte.data_models.validate_contribuyente_razon_social(self.receptor_razon_social)