Spaces:
Running
Running
File size: 18,630 Bytes
f4dcb85 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | """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")
|