"""TariffWise engine. Deterministic walk of the Chapter 64 tree. The walk descends from a heading to a ten digit leaf. At each node the children are evaluated in schedule order. A child matches, fails, or needs a fact. A needed fact stops the walk and names the gap. An unparsed condition stops the walk for review. The path taken is the rationale. """ import json import re NODES = json.load(open("tree.json")) BYID = {n["id"]: n for n in NODES} ROOTS = [n for n in NODES if n["parent"] is None] # --------------------------------------------------------------------- # Fact schema. Every key the schedule's splits can turn on. # --------------------------------------------------------------------- FACT_KEYS = { "sole_material": "outer sole constituent material, rubber_plastics, leather, composition_leather, or other", "upper_material": "upper constituent material by greatest external surface area, rubber_plastics, leather, composition_leather, textile, or other", "upper_textile_kind": "when the upper is textile, vegetable_fibers, wool_felt, or other_textile", "waterproof_molded": "true when soles and uppers are rubber or plastics and the upper is neither fixed to the sole nor assembled by stitching, riveting, nailing, screwing, plugging or similar", "protective": "true when the footwear protects against water, oil, grease, chemicals, cold or inclement weather", "metal_toe_cap": "true when a protective metal toe cap is present", "covers_ankle": "true when the footwear covers the ankle", "covers_knee": "true when the footwear covers the knee", "sports_spikes": "true when designed for a sport with spikes, sprigs, stops, clips, bars or provision for them, or ski, skating, snowboard, wrestling, boxing or cycling boots", "ski_boot": "true for ski boots, cross country ski footwear and snowboard boots", "athletic_like": "true for tennis shoes, basketball shoes, gym shoes, training shoes and the like", "leather_esa_over_50":"true when over 50 percent of the upper external surface area is leather including accessories added back", "value_per_pair": "customs value in US dollars per pair", "gender_age": "men, women, youths_boys, misses, children, infants, or unisex", "house_slipper": "true for house slippers", "work_footwear": "true for work footwear", "welt": "true for welt construction footwear", "zori": "true for zoris, one piece molded rubber or plastic thong sandals", "upper_esa_rubber_plastics_over_90": "true when over 90 percent of the upper external surface area including accessories is rubber or plastics", "foxing_band": "true when the footwear has a foxing or foxing like band applied or molded at the sole and overlapping the upper", "open_toe_or_heel": "true when the footwear has an open toe or open heel", "slip_on": "true when the footwear is of the slip on type without laces, buckles or fasteners", "sole_attach_stitch": "true when the sole is affixed to the upper mainly by stitching", "vulcanized_construction": "true for footwear made by vulcanization or similar one piece processes", "textile_sole_contact":"true when textile material has the greatest surface area in contact with the ground", "leather_strap_instep_big_toe": "true when the upper consists of leather straps across the instep and around the big toe", "wood_platform": "true when the footwear is made on a base or platform of wood", "inner_sole": "true when the footwear has an inner sole", "rp_weight_under_10": "true when the footwear is less than 10 percent by weight of rubber and plastics", "turned_construction": "true for turn or turned footwear, sewn wrong side out to a leather sole then turned", "golf_shoes": "true for golf shoes", } # --------------------------------------------------------------------- # Condition matchers. Each returns True, False, or a needed fact key. # UNPARSED marks text no rule recognizes. # --------------------------------------------------------------------- UNPARSED = "UNPARSED" def need(facts, key): return facts[key] if key in facts else key COMPOUND_MARKERS = ("which consist", "straps", "provided", "except as", "in which") def match_condition(desc, facts): ov = facts.get("_overrides", {}) if desc in ov: return bool(ov[desc]) d = desc.lower().rstrip(":").strip() # residual buckets always match once earlier siblings failed if d in ("other", "other footwear", "other:"): return True # leather strap sandal type of 6403.20 if "leather straps across the instep and around the big toe" in d: t = need(facts, "leather_strap_instep_big_toe") return t if t == "leather_strap_instep_big_toe" else bool(facts["leather_strap_instep_big_toe"]) # sole grouping rows under 6403 and 6404 if d.startswith("footwear with outer soles of rubber or plastics"): s = need(facts, "sole_material") return s if s == "sole_material" else facts["sole_material"] == "rubber_plastics" if d.startswith("footwear with outer soles of leather or composition leather"): s = need(facts, "sole_material") return s if s == "sole_material" else facts["sole_material"] in ("leather","composition_leather") # open toe or heel and slip on lines, honoring the except clauses if d.startswith("footwear with open toes or open heels"): if "foxing" in d: f = need(facts, "foxing_band") if f == "foxing_band": return f if facts["foxing_band"]: return False if "6404.19.20" in d: p = need(facts, "protective") if p == "protective": return p if facts["protective"]: return False o = need(facts, "open_toe_or_heel") if o == "open_toe_or_heel": return o if facts["open_toe_or_heel"]: return True if "slip-on" in d or "slip on" in d: sl = need(facts, "slip_on") return sl if sl == "slip_on" else bool(facts["slip_on"]) return False # weight of rubber or plastics split under 6404.19 if "less than 10 percent by weight of rubber or plastics" in d: w = need(facts, "rp_weight_under_10") return w if w == "rp_weight_under_10" else bool(facts["rp_weight_under_10"]) if "10 percent or more by weight of rubber or plastics" in d: w = need(facts, "rp_weight_under_10") return w if w == "rp_weight_under_10" else not facts["rp_weight_under_10"] # turned construction and golf shoes if d.startswith("turn or turned footwear"): t = need(facts, "turned_construction") return t if t == "turned_construction" else bool(facts["turned_construction"]) if d == "golf shoes": g = need(facts, "golf_shoes") return g if g == "golf_shoes" else bool(facts["golf_shoes"]) # compound conditions no simple rule should decide if any(m in d for m in COMPOUND_MARKERS): return UNPARSED # value bands m = re.search(r"valued not over \$?([\d.]+)", d) if m: v = need(facts, "value_per_pair") if v == "value_per_pair": return v return float(facts["value_per_pair"]) <= float(m.group(1)) m = re.search(r"valued over \$?([\d.]+)(?:/pair)? but not over \$?([\d.]+)", d) if m: v = need(facts, "value_per_pair") if v == "value_per_pair": return v return float(m.group(1)) < float(facts["value_per_pair"]) <= float(m.group(2)) m = re.search(r"valued over \$?([\d.]+)", d) if m: v = need(facts, "value_per_pair") if v == "value_per_pair": return v return float(facts["value_per_pair"]) > float(m.group(1)) # gender and age lines g = need(facts, "gender_age") gmap = { "for men": "men", "men's": "men", "for women": "women", "women's": "women", "for youths and boys": "youths_boys", "for misses": "misses", "for children": "children", "for infants": "infants", "for men, youths and boys": ("men","youths_boys"), "for other persons": None, "for children and infants": ("children","infants"), "for misses, children and infants": ("misses","children","infants"), } for text, val in gmap.items(): if d == text or d.startswith(text + " "): if g == "gender_age": return g if val is None: return facts["gender_age"] not in ("men","youths_boys") if isinstance(val, tuple): return facts["gender_age"] in val return facts["gender_age"] == val # ankle and knee if "covering the ankle but not covering the knee" in d: a = need(facts, "covers_ankle") if a == "covers_ankle": return a if not facts["covers_ankle"]: return False k = need(facts, "covers_knee") return k if k == "covers_knee" else not facts["covers_knee"] if "not covering the knee" not in d and "covering the knee" in d: k = need(facts, "covers_knee") return k if k == "covers_knee" else bool(facts["covers_knee"]) if "not covering the ankle" in d: a = need(facts, "covers_ankle") return a if a == "covers_ankle" else not facts["covers_ankle"] if "covering the ankle" in d: a = need(facts, "covers_ankle") if a == "covers_ankle": return a if not facts["covers_ankle"]: return False if "but not covering the knee" in d: k = need(facts, "covers_knee") return k if k == "covers_knee" else not facts["covers_knee"] return True # sports and athletic if d.startswith("sports footwear"): s = need(facts, "sports_spikes") if s == "sports_spikes": return s if facts["sports_spikes"]: return True if "tennis shoes, basketball shoes, gym shoes" in d: a = need(facts, "athletic_like") return a if a == "athletic_like" else bool(facts["athletic_like"]) return False if "ski-boots" in d or "ski boots" in d or "snowboard" in d: s = need(facts, "ski_boot") return s if s == "ski_boot" else bool(facts["ski_boot"]) if "tennis shoes, basketball shoes, gym shoes" in d: a = need(facts, "athletic_like") return a if a == "athletic_like" else bool(facts["athletic_like"]) # wood platform line of 6403.59.10 if "base or platform of wood" in d: w = need(facts, "wood_platform") if w == "wood_platform": return w if not facts["wood_platform"]: return False t = need(facts, "metal_toe_cap") if t == "metal_toe_cap": return t if facts["metal_toe_cap"]: return False i = need(facts, "inner_sole") return i if i == "inner_sole" else not facts["inner_sole"] # toe cap and protection, only when the line is about the toe cap itself if ("protective metal toe-cap" in d or "protective metal toe cap" in d) and d.startswith(("incorporating", "other footwear, incorporating", "footwear incorporating", "not incorporating")): t = need(facts, "metal_toe_cap") if t == "metal_toe_cap": return t if "not " in d.split("incorporating")[0]: return not facts["metal_toe_cap"] return bool(facts["metal_toe_cap"]) if "protection against water, oil, grease or chemicals or cold or inclement weather" in d: p = need(facts, "protective") if p == "protective": return p if d.startswith("footwear designed to be worn over"): return bool(facts["protective"]) return bool(facts["protective"]) if d.startswith("other footwear, not designed to be") or "not designed to be worn over" in d: p = need(facts, "protective") return p if p == "protective" else not facts["protective"] # upper leather share if "over 50 percent of the external surface area" in d and "leather" in d: l = need(facts, "leather_esa_over_50") return l if l == "leather_esa_over_50" else bool(facts["leather_esa_over_50"]) # rubber plastics share over 90 if "over 90 percent of the external surface area" in d: r = need(facts, "upper_esa_rubber_plastics_over_90") if r == "upper_esa_rubber_plastics_over_90": return r val = bool(facts["upper_esa_rubber_plastics_over_90"]) if "foxing" in d: f = need(facts, "foxing_band") if f == "foxing_band": return f return val and not facts["foxing_band"] return val # upper material lines if "uppers of vegetable fibers" in d or "of vegetable fibers" in d: u = need(facts, "upper_textile_kind") return u if u == "upper_textile_kind" else facts["upper_textile_kind"] == "vegetable_fibers" if "soles and uppers of wool felt" in d: u = need(facts, "upper_textile_kind") return u if u == "upper_textile_kind" else facts["upper_textile_kind"] == "wool_felt" if "uppers of leather or composition leather" in d: u = need(facts, "upper_material") return u if u == "upper_material" else facts["upper_material"] in ("leather","composition_leather") if "uppers of textile materials" in d or "uppers of textile material" in d: u = need(facts, "upper_material") return u if u == "upper_material" else facts["upper_material"] == "textile" if d.startswith("of leather"): u = need(facts, "upper_material") return u if u == "upper_material" else facts["upper_material"] == "leather" if d.startswith("of textile materials"): u = need(facts, "upper_material") return u if u == "upper_material" else facts["upper_material"] == "textile" # sole lines if "outer soles of leather" in d: s = need(facts, "sole_material") return s if s == "sole_material" else facts["sole_material"] == "leather" if "outer soles of rubber, plastics, leather or composition leather" in d: return True if "outer soles and uppers of rubber or plastics" in d: s = need(facts, "sole_material"); u = need(facts, "upper_material") if s == "sole_material": return s if u == "upper_material": return u return facts["sole_material"] == "rubber_plastics" and facts["upper_material"] == "rubber_plastics" # construction and type lines if "welt footwear" in d: w = need(facts, "welt") return w if w == "welt" else bool(facts["welt"]) if "house slippers" in d: h = need(facts, "house_slipper") return h if h == "house_slipper" else bool(facts["house_slipper"]) if "work footwear" in d: w = need(facts, "work_footwear") return w if w == "work_footwear" else bool(facts["work_footwear"]) if "zoris" in d: z = need(facts, "zori") return z if z == "zori" else bool(facts["zori"]) return UNPARSED # --------------------------------------------------------------------- # The walk. # --------------------------------------------------------------------- def walk(facts, start=None): """Walk to a leaf. Returns a dict with status, code or gap, and the path.""" path = [] def effective_rate(node): cur = node while cur is not None: if cur["general"].strip(): return cur["general"].strip() cur = BYID[cur["parent"]] if cur["parent"] is not None else None return "" def descend(node): if not node["children"]: return {"status": "code", "code": node["htsno"], "general": effective_rate(node), "path": path} kids = [BYID[c] for c in node["children"]] for kid in kids: r = match_condition(kid["desc"], facts) if r is True: path.append({"htsno": kid["htsno"], "desc": kid["desc"]}) return descend(kid) if r is False: continue if r == UNPARSED: return {"status": "review", "reason": "condition needs judgment", "at": kid["desc"], "path": path} return {"status": "need_fact", "fact": r, "question_about": FACT_KEYS[r], "at": kid["desc"], "path": path} return {"status": "review", "reason": "no child matched", "at": node["desc"], "path": path} if start is None: # heading selection from the top for root in ROOTS: r = heading_match(root, facts) if r is True: path.append({"htsno": root["htsno"], "desc": root["desc"]}) return descend(root) if r is False: continue if isinstance(r, str): return {"status": "need_fact", "fact": r, "question_about": FACT_KEYS[r], "at": root["desc"], "path": path} return {"status": "review", "reason": "no heading matched", "path": path} return descend(start) def heading_match(root, facts): h = root["htsno"] s = facts.get("sole_material"); u = facts.get("upper_material") if h == "6401": if s is not None and s != "rubber_plastics": return False if u is not None and u != "rubber_plastics": return False for k in ("sole_material","upper_material","waterproof_molded"): if k not in facts: return k return bool(facts["waterproof_molded"]) if h == "6402": if s is not None and s != "rubber_plastics": return False if u is not None and u != "rubber_plastics": return False for k in ("sole_material","upper_material"): if k not in facts: return k if "waterproof_molded" not in facts: return "waterproof_molded" return not facts["waterproof_molded"] if h == "6403": for k in ("sole_material","upper_material"): if k not in facts: return k return (s in ("rubber_plastics","leather","composition_leather") and u in ("leather",)) if h == "6404": for k in ("sole_material","upper_material"): if k not in facts: return k return (s in ("rubber_plastics","leather","composition_leather") and u == "textile") if h == "6405": return True return False def rationale(result, facts): lines = [] for i, step in enumerate(result.get("path", []), 1): num = step["htsno"] or "grouping" lines.append(f"{i}. {num} {step['desc']}") return lines if __name__ == "__main__": print("engine loaded", len(NODES), "nodes")