Repository: joke2k/faker

Issue:
ssn.it_IT.Provider generates SSNs shorter than 16 chars
* Faker version:  tested with 13.14.0,  15.3.3
* OS: Ubuntu 22.04

Generating an Italian SSN, when the last (or first) name returned by `person.it_IT.Provider` is 3 characters long and contains latin chars, the resulting string is shorter than expected (16 chars). In this scenario:

- string is not shorter than 3 chars, so it does not get padded
- latin char is neither a vowel nor a consonant, so it gets ignored

### Steps to reproduce

```
from unittest import mock 

from faker import Factory

generator = Factory.create("it_IT")
generator.last_name = mock.MagicMock(return_value="Foà")

assert len(generator.ssn()) == 16

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError
```

### Expected behavior

The length of generated SSN should be 16 characters. Latin chars should be translated into equivalent ASCII chars (A for À, E for È and É, etc.)  

### Actual behavior

The length of generated SSN is 15 characters.



Discussion:
I'm preparing a PR for fixing this one

Resolving patch:
diff --git a/faker/providers/ssn/it_IT/__init__.py b/faker/providers/ssn/it_IT/__init__.py
--- a/faker/providers/ssn/it_IT/__init__.py
+++ b/faker/providers/ssn/it_IT/__init__.py
@@ -1,5 +1,7 @@
 """it_IT ssn provider (yields italian fiscal codes)"""
 
+import unicodedata
+
 from string import ascii_uppercase, digits
 
 from .. import Provider as SsnProvider
@@ -8051,6 +8053,8 @@ def _get_name_letters(self, sex: int) -> str:
         else:
             name = self.generator.first_name_female().upper()
 
+        name = self._transliterate_name(name)
+
         if len(name) < 3:
             return self._pad_shorter(name)
 
@@ -8074,6 +8078,8 @@ def _get_surname_letters(self) -> str:
             str
         """
         surname = self.generator.last_name().upper()
+        surname = self._transliterate_name(surname)
+
         if len(surname) < 3:
             return self._pad_shorter(surname)
 
@@ -8086,6 +8092,11 @@ def _get_surname_letters(self) -> str:
             surname_part = "".join(surname_consonants)[:3]
         return surname_part
 
+    @staticmethod
+    def _transliterate_name(name: str) -> str:
+        nfkd_form: str = unicodedata.normalize("NFKD", name)
+        return "".join([c for c in nfkd_form if unicodedata.combining(c) == 0])
+
     @staticmethod
     def _get_vowels(sequence: str) -> list:
         """


Test patch:
diff --git a/tests/providers/test_ssn.py b/tests/providers/test_ssn.py
--- a/tests/providers/test_ssn.py
+++ b/tests/providers/test_ssn.py
@@ -14,7 +14,7 @@
 from validators.i18n.es import es_nie as is_nie
 from validators.i18n.es import es_nif as is_nif
 
-from faker import Faker
+from faker import Factory, Faker
 from faker.providers.ssn.el_GR import tin_checksum as gr_tin_checksum
 from faker.providers.ssn.en_CA import checksum as ca_checksum
 from faker.providers.ssn.es_CL import rut_check_digit as cl_rut_checksum
@@ -904,6 +904,13 @@ def test_ssn(self):
     def test_checksum(self) -> None:
         assert it_checksum("MDDMRA80L41H501") == "R"
 
+    def test_ssn_with_latin_chars(self):
+        generator = Factory.create("it_IT")
+        generator.last_name = mock.MagicMock(return_value="Foà")
+        ssn = generator.ssn()
+        self.assertEqual(len(ssn), 16)
+        self.assertEqual(ssn[:3], "FOA")
+
 
 class TestPtBR(unittest.TestCase):
     def setUp(self):