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
58 changes: 58 additions & 0 deletions src/cl_sii/extras/dj_url_converters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""
cl_sii "extras" / Django URL converters.
"""

from __future__ import annotations

from typing import ClassVar

import cl_sii.dte.constants
import cl_sii.rut


class RutConverter:
"""
Django URL path converter for Chilean RUT.

Thousands separators are not supported.

Example:

>>> from django.urls import path, register_converter
>>> register_converter(RutConverter, 'cl_sii_rut')
>>> urlpatterns = [path('example/<cl_sii_rut:emisor_rut>/', ...)]

.. seealso::
https://docs.djangoproject.com/en/4.2/topics/http/urls/#registering-custom-path-converters
"""

regex: ClassVar[str] = r'\d{1,8}-[\dKk]'

def to_python(self, value: str) -> cl_sii.rut.Rut:
return cl_sii.rut.Rut(value)

def to_url(self, value: cl_sii.rut.Rut) -> str:
return str(value)


class TipoDteConverter:
"""
Django URL path converter for `Tipo DTE` object.

Example:

>>> from django.urls import path, register_converter
>>> register_converter(TipoDteConverter, 'cl_sii_tipo_dte')
>>> urlpatterns = [path('example/<cl_sii_tipo_dte:tipo_dte>/', ...)]

.. seealso::
https://docs.djangoproject.com/en/4.2/topics/http/urls/#registering-custom-path-converters
"""

regex: ClassVar[str] = r'\d{2,3}'

def to_python(self, value: str) -> cl_sii.dte.constants.TipoDte:
return cl_sii.dte.constants.TipoDte(int(value))

def to_url(self, value: cl_sii.dte.constants.TipoDte) -> str:
return str(value.value)
116 changes: 116 additions & 0 deletions src/tests/test_extras_dj_url_converters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from __future__ import annotations

import unittest
from typing import Sequence, Tuple

from cl_sii.dte.constants import TipoDte
from cl_sii.extras.dj_url_converters import RutConverter, TipoDteConverter
from cl_sii.rut import Rut


class RutConverterTest(unittest.TestCase):
"""
Tests for :class:`RutConverter`.
"""

def test_regex(self) -> None:
for rut_str in (
'60805000-0',
'78773510-K',
'123456-0',
'123-6',
'1-9',
'6-K',
):
self.assertRegex(rut_str, RutConverter.regex)

def test_regex_matches_leading_zeroes(self) -> None:
for rut_str in ('001-9', '000006-K', '0123456-0'):
self.assertRegex(rut_str, RutConverter.regex)

def test_regex_matches_uppercase_and_lowercase(self) -> None:
self.assertRegex('6-K', RutConverter.regex)
self.assertRegex('6-k', RutConverter.regex)

def test_to_python(self) -> None:
obj = RutConverter()

test_values: Sequence[Tuple[str, Rut]] = [
('60805000-0', Rut('60805000-0')),
('78773510-K', Rut('78773510-K')),
('123456-0', Rut('123456-0')),
('1-9', Rut('1-9')),
('01-9', Rut('1-9')),
('6-k', Rut('6-K')),
]

for string_test_value, python_test_value in test_values:
self.assertEqual(obj.to_python(string_test_value), python_test_value)

def test_to_url(self) -> None:
obj = RutConverter()

test_values: Sequence[Tuple[Rut, str]] = [
(Rut('60805000-0'), '60805000-0'),
(Rut('78773510-K'), '78773510-K'),
(Rut('123456-0'), '123456-0'),
(Rut('1-9'), '1-9'),
]

for python_test_value, string_test_value in test_values:
self.assertEqual(obj.to_url(python_test_value), string_test_value)


class TipoDteConverterTest(unittest.TestCase):
"""
Tests for :class:`TipoDteConverter`.
"""

def test_regex(self) -> None:
for tipo_dte_str in (
'33',
'34',
'43',
'46',
'52',
'56',
'61',
'110',
):
self.assertRegex(tipo_dte_str, TipoDteConverter.regex)

def test_to_python(self) -> None:
obj = TipoDteConverter()

test_values: Sequence[Tuple[str, TipoDte]] = [
('33', TipoDte(33)),
('34', TipoDte(34)),
('43', TipoDte(43)),
('46', TipoDte(46)),
('52', TipoDte(52)),
('56', TipoDte(56)),
('61', TipoDte(61)),
# warning: `110` is a valid value, but `TipoDte` doesn't support it yet.
# ('110', TipoDte(110)),
]

for string_test_value, python_test_value in test_values:
self.assertEqual(obj.to_python(string_test_value), python_test_value)

def test_to_url(self) -> None:
obj = TipoDteConverter()

test_values: Sequence[Tuple[TipoDte, str]] = [
(TipoDte(33), '33'),
(TipoDte(34), '34'),
(TipoDte(43), '43'),
(TipoDte(46), '46'),
(TipoDte(52), '52'),
(TipoDte(56), '56'),
(TipoDte(61), '61'),
# warning: `110` is a valid value, but `TipoDte` doesn't support it yet.
# (TipoDte(110), '110'),
]

for python_test_value, string_test_value in test_values:
self.assertEqual(obj.to_url(python_test_value), string_test_value)