from .logistics_hs_code_validate_types import HsCodeCheck _KINDS = {6: "hs", 8: "cn", 10: "taric"} def _invalid(reason: str) -> HsCodeCheck: return HsCodeCheck( valid=False, normalised=None, kind=None, chapter=None, heading=None, subheading=None, reason=reason ) def validate_hs_code(value: str) -> HsCodeCheck: """Check the format of a 6-digit HS, 8-digit CN or 10-digit TARIC/UK commodity code. Validators answer rather than raise: a malformed code is the answer "no".""" if not isinstance(value, str): return _invalid("empty") chars = [] for ch in value: if ch == " " or ch == ".": continue # Compare with ASCII explicitly: str.isdigit() accepts full-width digits. if ch < "0" or ch > "9": return _invalid("bad-character") chars.append(ch) digits = "".join(chars) if not digits: return _invalid("empty") kind = _KINDS.get(len(digits)) if kind is None: return _invalid("bad-length") # Text, not a number: chapter "01" must keep its zero. chapter = digits[0:2] if chapter == "00": return _invalid("bad-chapter") if chapter == "77": return _invalid("reserved-chapter") # 98 and 99 are left to national tariffs, so only a national-length code may use them. if chapter in ("98", "99") and kind == "hs": return _invalid("national-chapter") if digits[2:4] == "00": return _invalid("bad-heading") return HsCodeCheck( valid=True, normalised=digits, kind=kind, chapter=chapter, heading=digits[0:4], subheading=digits[0:6], reason=None, )