Repository: joke2k/faker

Issue:
VAT for IT provider generates invalid values
* Faker version: `4.1.3`
* OS: Linux Debian

`company_vat` for `it_IT` providers randomly returns invalid VAT values.

### Expected behavior

As example, `company_vat()` generated the invalid value `IT00472451194`. This value is not valid because the last part of the code, `IT#######119#` is not a valid number for the algorithm that validates the Italian VAT (the [stdnum library](https://github.com/arthurdejong/python-stdnum), for example, correctly recognize this as an invalid VAT). As described in the ["Partita IVA" (VAT) wikipedia page](https://www.wikiwand.com/it/Partita_IVA), the valid values must be in the range `001-100` plus the values `120,121,888,999`.

The current code is:

```python
def company_vat(self):
        """
        Returns Italian VAT identification number (Partita IVA).
        """
        code = "0" + self.bothify('######') + str(self.generator.random.randrange(1, 121)).zfill(3)
        luhn_checksum = str(calculate_luhn(code))
        return 'IT{}{}'.format(code, luhn_checksum)
```

this code has some issues:

- The `randrange` is generating invalid values.
- The method is not generating all the possible VAT due to the missing `888` and `999` values. Also, the first digit of the VAT is allowed to be values other than 0 (currently it is fixed to 0).



Discussion:
Thank you for the report @LordGordonQ :)

Do you have time to work on a Pull Request to fix this?
> Thank you for the report @LordGordonQ :)
> 
> Do you have time to work on a Pull Request to fix this?

Yes, working on it right now. Also adding some tests that are missing.

Resolving patch:
diff --git a/faker/providers/company/it_IT/__init__.py b/faker/providers/company/it_IT/__init__.py
--- a/faker/providers/company/it_IT/__init__.py
+++ b/faker/providers/company/it_IT/__init__.py
@@ -352,10 +352,30 @@ def bs(self):
 
         return " ".join(result)
 
+    def _random_vat_office(self):
+        """
+        Returns a random code identifying the VAT office needed to build a valid VAT with company_vat.
+
+        See https://it.wikipedia.org/wiki/Partita_IVA#Tabella_degli_Uffici_IVA
+        """
+        val = self.random_int(1, 104)
+
+        # handle special cases
+        if val == 101:
+            return 120
+        elif val == 102:
+            return 121
+        elif val == 103:
+            return 888
+        elif val == 104:
+            return 999
+        # else: between 1 and 100 are all valid
+        return val
+
     def company_vat(self):
         """
         Returns Italian VAT identification number (Partita IVA).
         """
-        code = "0" + self.bothify('######') + str(self.generator.random.randrange(1, 121)).zfill(3)
+        code = self.bothify('#######') + str(self._random_vat_office()).zfill(3)
         luhn_checksum = str(calculate_luhn(code))
         return 'IT{}{}'.format(code, luhn_checksum)


Test patch:
diff --git a/tests/providers/test_company.py b/tests/providers/test_company.py
--- a/tests/providers/test_company.py
+++ b/tests/providers/test_company.py
@@ -1,11 +1,15 @@
 import re
 
 from datetime import datetime
+from unittest.mock import patch
+
+import pytest
 
 from faker.providers.company.en_PH import Provider as EnPhCompanyProvider
 from faker.providers.company.fil_PH import Provider as FilPhCompanyProvider
 from faker.providers.company.hu_HU import Provider as HuHuCompanyProvider
 from faker.providers.company.hy_AM import Provider as HyAmCompanyProvider
+from faker.providers.company.it_IT import Provider as ItItCompanyProvider
 from faker.providers.company.ja_JP import Provider as JaJpCompanyProvider
 from faker.providers.company.nl_NL import Provider as NlNlCompanyProvider
 from faker.providers.company.pl_PL import Provider as PlPlCompanyProvider
@@ -322,3 +326,30 @@ def test_bs(self, faker, num_samples):
             bs_words = bs.split()
             assert isinstance(bs, str)
             assert bs_words[0] in RuRuCompanyProvider.bsWords[0]
+
+
+class TestItIt:
+    """Test it_IT company provider methods"""
+
+    vat_regex = re.compile(r"^IT\d{7}(0\d{2}|100|120|121|888|999)\d$", flags=re.ASCII)
+
+    def test_company_vat(self, faker, num_samples):
+        for _ in range(num_samples):
+            company_vat = faker.company_vat()
+            assert self.vat_regex.match(company_vat)
+
+    @pytest.mark.parametrize("value, expected", (
+        (100, "100"),
+        (101, "120"),
+        (102, "121"),
+        (103, "888"),
+        (104, "999"),
+    ))
+    def test_company_vat_special_cases(self, faker, value, expected):
+        # this test allows to get full code coverage for company_vat fixing the internal state of the random generator
+        fake = ItItCompanyProvider(generator=faker)
+
+        with patch.object(fake, "random_int", return_value=value, autospec=True):
+            company_vat = fake.company_vat()
+            assert self.vat_regex.match(company_vat)
+            assert company_vat[9:12] == expected