Repository: joke2k/faker

Issue:
Fix Turkish Republic National Number generation bug
The current implementation of the TCKN provider generates invalid Turkish National Identification Numbers because it does not follow the official checksum rules. Specifically:

The first digit can be zero (which is invalid).

The 10th digit calculation does not follow the official odd/even sum formula.

The 11th digit checksum is incorrect.

This issue causes Faker to produce TCKN numbers that fail real-world validation.


Discussion:

Patch:
diff --git a/faker/providers/ssn/tr_TR/__init__.py b/faker/providers/ssn/tr_TR/__init__.py
index b68fc84386..d5f6466fc1 100644
--- a/faker/providers/ssn/tr_TR/__init__.py
+++ b/faker/providers/ssn/tr_TR/__init__.py
@@ -2,17 +2,33 @@
 
 
 class Provider(BaseProvider):
-    # Source:
-    # Turkey Republic National Number is identity number.
-    # Identity number contains 11 numbers,
-    # First number can't be zero
-    # Eleventh number is result of division after sum first number
+    # Source (https://tr.wikipedia.org/wiki/T.C._Kimlik_Numaras%C4%B1)
+    # Turkey Republic National Number (TCKN) is an 11-digit identity number.
+    # Rules:
+    # 1. The number consists of 11 digits.
+    # 2. The first digit cannot be zero.
+    # 3. The 10th digit is calculated as:
+    #    ((sum of digits in odd positions (1st, 3rd, 5th, 7th, 9th) * 7)
+    #    - sum of digits in even positions (2nd, 4th, 6th, 8th)) mod 10.
+    # 4. The 11th digit is the modulo 10 of the sum of the first 10 digits.
+    # 5. The number must satisfy these rules to be considered valid.
 
     def ssn(self) -> str:
         """
-        :example: '89340691651'
+        :example: '85420031070'
         """
-        first_part: int = self.random_element((1, 2, 3, 4, 5, 6, 7, 8, 9))
-        middle_part: str = self.bothify("#########")
-        last_part: int = sum(int(x) for x in f"{first_part}{middle_part}") % 10
-        return f"{first_part}{middle_part}{last_part}"
+        digits = [self.random_int(1, 9)]
+
+        for _ in range(8):
+            digits.append(self.random_int(0, 9))
+
+        odd_sum = sum(digits[i] for i in [0, 2, 4, 6, 8])
+        even_sum = sum(digits[i] for i in [1, 3, 5, 7])
+        tenth = ((odd_sum * 7) - even_sum) % 10
+        digits.append(tenth)
+
+        total_sum = sum(digits)
+        eleventh = total_sum % 10
+        digits.append(eleventh)
+
+        return "".join(str(d) for d in digits)


Test patch:
diff --git a/tests/providers/test_ssn.py b/tests/providers/test_ssn.py
index 45455ba3e3..85b47b0d37 100644
--- a/tests/providers/test_ssn.py
+++ b/tests/providers/test_ssn.py
@@ -1211,19 +1211,29 @@ class TestTrTr(unittest.TestCase):
     num_sample_runs = 10
 
     def setUp(self):
+        Faker.seed(0)
         self.fake = Faker("tr_TR")
         self.samples = [self.fake.ssn() for _ in range(self.num_sample_runs)]
-        Faker.seed(0)
 
-    def first_part_non_zero(self):
+    def test_first_part_non_zero(self):
         for sample in self.samples:
-            assert sample[0] != 0
+            self.assertNotEqual(sample[0], "0")
 
-    def compare_first_ten_and_last_part(self):
+    def test_eleventh_digit_matches_sum_mod_10(self):
         for sample in self.samples:
             first_ten_number = sample[:-1]
-            last_part = sample[-1]
-            assert sum(int(x) for x in f"{first_ten_number}") % 10 == last_part
+            last_part = int(sample[-1])
+            total_sum = sum(int(x) for x in first_ten_number)
+            self.assertEqual(total_sum % 10, last_part)
+
+    def test_tenth_digit_correct(self):
+        for sample in self.samples:
+            digits = [int(d) for d in sample]
+            odd_sum = sum(digits[i] for i in [0, 2, 4, 6, 8])
+            even_sum = sum(digits[i] for i in [1, 3, 5, 7])
+            tenth_digit = digits[9]
+            expected_tenth = ((odd_sum * 7) - even_sum) % 10
+            self.assertEqual(tenth_digit, expected_tenth)
 
 
 class TestEnIn(unittest.TestCase):