fabiocaccamo / python-codicefiscale

:it: :credit_card: italian fiscal codes encoding, decoding and validation - codifica, decodifica e validazione del Codice Fiscale italiano.
MIT License
74 stars 24 forks source link

Error when the municipality is old (active = false) and the person is more than 100 years old #203

Open FaediMichele opened 3 weeks ago

FaediMichele commented 3 weeks ago

Example:

codicefiscale.encode('Michele', 'Faedi', 'm', '01/01/1907', 'Gallico')

I also have a solution. I try to create birthdate_str until it work or at maximum 3 attempt. Each attempt decrease the birthdate_year by 100.

def decode(code: str) -> dict[str, Any]:
    """
    Decodes the italian fiscal code.

    :param code: The code
    :type code: string

    :returns: The data associated to the code and some additional info.
    :rtype: dict
    """
    raw = decode_raw(code)

    code = raw["code"]

    birthdate_year = int(raw["birthdate_year"].translate(_OMOCODIA_DECODE_TRANS))
    birthdate_month = _MONTHS.index(raw["birthdate_month"]) + 1
    birthdate_day = int(raw["birthdate_day"].translate(_OMOCODIA_DECODE_TRANS))

    if birthdate_day > 40:
        birthdate_day -= 40
        gender = "F"
    else:
        gender = "M"

    current_year = datetime.now().year
    current_year_century_prefix = str(current_year)[0:-2]
    birthdate_year_suffix = str(birthdate_year).zfill(2)
    birthdate_year = int(f"{current_year_century_prefix}{birthdate_year_suffix}")
    if birthdate_year > current_year:
        birthdate_year -= 100

    attempt = 1
    while True:
        birthdate_str = f"{birthdate_year}/{birthdate_month}/{birthdate_day}"

        try:
            birthdate = _get_date(birthdate_str, separator="/")
            if not birthdate:
                raise ValueError(f"[codicefiscale] invalid date: {birthdate_str}")

            birthplace_code = raw["birthplace"][0] + raw["birthplace"][1:].translate(
                _OMOCODIA_DECODE_TRANS
            )
            birthplace = _get_birthplace(birthplace_code, birthdate)
            # print(birthplace)
            if not birthplace:
                raise ValueError(
                    "[codicefiscale] wrong birthplace code: "
                    f"{birthplace_code!r} / birthdate: {birthdate.isoformat()!r}."
                )
        except ValueError as e:
            attempt += 1
            birthdate_year -= 100
            if attempt > 3:
                raise e
        break

    cin = raw["cin"]
    cin_check = encode_cin(code)
    # print(cin, cin_check)
    if cin != cin_check:
        raise ValueError(
            "[codicefiscale] wrong CIN (Control Internal Number): "
            f"expected {cin_check!r}, found {cin!r}"
        )

    data = {
        "code": code,
        "omocodes": _get_omocodes(code),
        "gender": gender,
        "birthdate": birthdate,
        "birthplace": birthplace,
        "raw": raw,
    }

    # print(data)
    return data

Upvote & Fund

Fund with Polar

fabiocaccamo commented 2 weeks ago

@FaediMichele thank you for reporting this issue and a possible solution.

Could you please submit a PR with the changes you propose and a failing test case to avoid regressions?