Main
This commit is contained in:
102
main.py
Normal file
102
main.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import datetime
|
||||||
|
from random import randint
|
||||||
|
from typing import Tuple, NamedTuple, Union, Iterable
|
||||||
|
|
||||||
|
START_LEGACY_DATE: datetime.date = datetime.date(1800, 1, 1)
|
||||||
|
FINAL_LEGACY_DATE: datetime.date = datetime.date(2017, 7, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class PersonalCode(NamedTuple):
|
||||||
|
first_part: str
|
||||||
|
second_part: str
|
||||||
|
has_check_digit: bool = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_anonymous_personal_code(cls) -> "PersonalCode":
|
||||||
|
pc = f"3{randint(2 * 10 ** 9, 10 * 10 ** 9 - 1)}"
|
||||||
|
first_part = pc[:6]
|
||||||
|
second_part = pc[6:]
|
||||||
|
instance = cls(first_part, second_part)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_anonymous_with_check_digit(cls) -> "PersonalCode":
|
||||||
|
tmp = cls.generate_anonymous_personal_code()
|
||||||
|
check_digit = tmp._get_checksum_digit()
|
||||||
|
if check_digit == 10:
|
||||||
|
return tmp.generate_anonymous_with_check_digit()
|
||||||
|
second_part = tmp.second_part[:-1]+str(check_digit)
|
||||||
|
instance = cls(tmp.first_part, second_part, True)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_legacy_with_check_digit(cls, years: int = None) -> "PersonalCode":
|
||||||
|
if years is not None:
|
||||||
|
if years < (datetime.date.today()-FINAL_LEGACY_DATE).days//365:
|
||||||
|
raise ValueError(
|
||||||
|
f"Too young for legacy Personal Code! years < {(datetime.date.today()-FINAL_LEGACY_DATE).days//365}"
|
||||||
|
)
|
||||||
|
min_age_in_days = abs(years)*365
|
||||||
|
max_age_in_days = abs(years+1)*365
|
||||||
|
birthdate = datetime.date.today() - datetime.timedelta(days=randint(min_age_in_days, max_age_in_days))
|
||||||
|
else:
|
||||||
|
max_age_in_days = (FINAL_LEGACY_DATE-START_LEGACY_DATE).days
|
||||||
|
min_age_in_days = 1
|
||||||
|
birthdate = FINAL_LEGACY_DATE - datetime.timedelta(days=randint(min_age_in_days, max_age_in_days))
|
||||||
|
first_part = f"{birthdate.day:02d}{birthdate.month:02d}{str(birthdate.year)[2:]}"
|
||||||
|
century_digit = 2 if birthdate.year // 2000 else 1 if birthdate.year // 1900 else 0
|
||||||
|
second_part = f"{century_digit}{randint(0, 999):03}"
|
||||||
|
tmp = cls(first_part, second_part)
|
||||||
|
check_digit = tmp._get_checksum_digit()
|
||||||
|
if check_digit == 10:
|
||||||
|
return cls.generate_legacy_with_check_digit()
|
||||||
|
second_part = f"{second_part}{check_digit}"
|
||||||
|
return cls(first_part, second_part, True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_legacy_for_birthday(cls, *args: Union[Union[datetime.date], Union[int, int, int]]) -> "PersonalCode":
|
||||||
|
if len(args) == 1:
|
||||||
|
if not isinstance(args[0], datetime.date):
|
||||||
|
raise ValueError(
|
||||||
|
f"Calling method with one parameter, it must be of type `datetime.date` not `{type(args[0])}`"
|
||||||
|
)
|
||||||
|
birthday = args[0]
|
||||||
|
elif len(args) == 3:
|
||||||
|
if not all(isinstance(o, int) for o in args):
|
||||||
|
raise ValueError(
|
||||||
|
f"Calling method with three parameters, they all must be of type `int` not `{[type(arg) for arg in args]}`"
|
||||||
|
)
|
||||||
|
birthday = datetime.date(*args)
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
"Method must be called with either one argument which is `datetime.date` or three int parameters "
|
||||||
|
f"which represent year, month, day representing date between {START_LEGACY_DATE} and {FINAL_LEGACY_DATE}"
|
||||||
|
)
|
||||||
|
if not START_LEGACY_DATE <= birthday < FINAL_LEGACY_DATE:
|
||||||
|
raise ValueError(
|
||||||
|
f"Legacy non-anonymous personal codes are generated for birthdays since {START_LEGACY_DATE} till {FINAL_LEGACY_DATE}!\n"
|
||||||
|
f"{START_LEGACY_DATE} <= {birthday} < {FINAL_LEGACY_DATE}"
|
||||||
|
)
|
||||||
|
first_part = f"{birthday.day:02d}{birthday.month:02d}{str(birthday.year)[2:]}"
|
||||||
|
century_digit = 2 if birthday.year // 2000 else 1 if birthday.year // 1900 else 0
|
||||||
|
second_part = f"{century_digit}{randint(0, 999):03}"
|
||||||
|
tmp = cls(first_part, second_part)
|
||||||
|
check_digit = tmp._get_checksum_digit()
|
||||||
|
if check_digit == 10:
|
||||||
|
return cls.generate_legacy_with_check_digit()
|
||||||
|
second_part = f"{second_part}{check_digit}"
|
||||||
|
return cls(first_part, second_part, True)
|
||||||
|
|
||||||
|
def as_tuple(self) -> Tuple[str, str]:
|
||||||
|
return self.first_part, self.second_part
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.first_part}{self.second_part}"
|
||||||
|
|
||||||
|
def _get_checksum_digit(self) -> int:
|
||||||
|
_factors = [1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
|
||||||
|
return (1101 - sum(map(lambda p, f: int(p) * f, str(self)[:10], _factors))) % 11
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dashed(self):
|
||||||
|
return f"{self.first_part}-{self.second_part}"
|
Reference in New Issue
Block a user