Spaces:
Paused
Paused
| """Classification router — HS code lookup and duty calculation.""" | |
| from __future__ import annotations | |
| import logging | |
| from datetime import datetime, timezone | |
| from fastapi import APIRouter, Depends, HTTPException | |
| from pydantic import BaseModel, Field | |
| from hermes.api.middleware import sanitize_input | |
| from hermes.core.auth import get_api_key_dependency | |
| logger = logging.getLogger(__name__) | |
| router = APIRouter(dependencies=[Depends(get_api_key_dependency)]) | |
| # ── Request/Response Models ────────────────────────────────────────── | |
| class ItemInput(BaseModel): | |
| description: str = Field(..., max_length=500, description="Item description") | |
| quantity: int = Field(default=1, ge=1, description="Quantity") | |
| unit_price_usd: float = Field(default=0.0, ge=0, description="Unit price in USD") | |
| origin_country: str = Field(..., min_length=2, max_length=2, description="ISO country code") | |
| class ClassifyRequest(BaseModel): | |
| items: list[ItemInput] = Field(..., min_length=1, max_length=50, description="Items to classify") | |
| destination_country: str = Field(..., min_length=2, max_length=2, description="Destination ISO country code") | |
| class ItemClassification(BaseModel): | |
| description: str | |
| hs_code: str | |
| taric_description: str | |
| origin: str | |
| customs_value: float | |
| duty_rate: float | |
| duty_amount: float | |
| vat_rate: float | |
| vat_amount: float | |
| total_landed_cost: float | |
| notes: str | |
| class DutySummary(BaseModel): | |
| customs_value: float | |
| total_duty: float | |
| total_vat: float | |
| shipping_cost: float | |
| total_taxes_fees: float | |
| total_landed_cost: float | |
| effective_rate: float | |
| class ClassifyResponse(BaseModel): | |
| status: str | |
| classified_at: str | |
| destination_country: str | |
| items: list[ItemClassification] | |
| summary: DutySummary | |
| # ── TARIC API Helpers ──────────────────────────────────────────────── | |
| TARIC_BASE_URL = "https://ec.europa.eu/taxation_customs/dds2/taric" | |
| TARIC_DESCRIPTION_URL = f"{TARIC_BASE_URL}/goodsDescrForWs" | |
| # Default duty rate for unknown products (15% is conservative EU average) | |
| DEFAULT_DUTY_RATE = 0.15 | |
| DEFAULT_VAT_RATE = 0.19 # German VAT | |
| async def fetch_taric_description(taric_code: str) -> dict: | |
| """Fetch TARIC code description from EU database.""" | |
| import httpx | |
| params = { | |
| "Goods_code": taric_code.replace(".", ""), | |
| "Country_code": "en", | |
| } | |
| try: | |
| async with httpx.AsyncClient(timeout=15.0) as client: | |
| resp = await client.get(TARIC_DESCRIPTION_URL, params=params) | |
| resp.raise_for_status() | |
| import xml.etree.ElementTree as ET | |
| root = ET.fromstring(resp.text) | |
| result = {} | |
| goods_code = root.find(".//Goods_code") | |
| if goods_code is not None: | |
| result["taric_code"] = goods_code.text or "" | |
| description = root.find(".//Description") | |
| if description is not None: | |
| result["description"] = description.text or "" | |
| return result | |
| except Exception as e: | |
| return {"taric_code": taric_code, "description": f"Lookup failed: {e}"} | |
| # ── Classification Logic ───────────────────────────────────────────── | |
| # Comprehensive HS code lookup table: keywords → (hs_code, description, duty_rate, notes) | |
| # Covers 100+ common import product categories | |
| HS_CODE_DATABASE: dict[str, tuple[str, str, float, str]] = { | |
| # ── Electronics & IT (Chapter 84-85) ────────────────────────── | |
| "earbuds": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"), | |
| "headphones": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"), | |
| "earphones": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"), | |
| "airpods": ("8518.30", "Headphones and earphones", 0.0, "ITA zero duty"), | |
| "charger": ("8504.40", "Static converters (chargers)", 0.0, "ITA zero duty"), | |
| "charging": ("8504.40", "Static converters (chargers)", 0.0, "ITA zero duty"), | |
| "power adapter": ("8504.40", "Static converters (chargers)", 0.0, "ITA zero duty"), | |
| "power supply": ("8504.40", "Static converters (power supplies)", 0.0, "ITA zero duty"), | |
| "usb-c": ("8504.40", "USB-C chargers/adapters", 0.0, "ITA zero duty"), | |
| "laptop": ("8471.30", "Portable digital computers", 0.0, "ITA zero duty"), | |
| "computer": ("8471.30", "Digital computers", 0.0, "ITA zero duty"), | |
| "notebook": ("8471.30", "Portable computers", 0.0, "ITA zero duty"), | |
| "macbook": ("8471.30", "Portable computers", 0.0, "ITA zero duty"), | |
| "desktop": ("8471.30", "Desktop computers", 0.0, "ITA zero duty"), | |
| "monitor": ("8528.52", "Monitors and displays", 0.0, "ITA zero duty"), | |
| "display": ("8528.52", "Monitors and displays", 0.0, "ITA zero duty"), | |
| "tv ": ("8528.72", "Television receivers", 0.14, "Standard rate"), | |
| "television": ("8528.72", "Television receivers", 0.14, "Standard rate"), | |
| "chip": ("8542.31", "Electronic integrated circuits", 0.0, "ITA zero duty"), | |
| "processor": ("8542.31", "Electronic integrated circuits", 0.0, "ITA zero duty"), | |
| "circuit": ("8542.31", "Electronic integrated circuits", 0.0, "ITA zero duty"), | |
| "semiconductor": ("8542.31", "Semiconductor devices", 0.0, "ITA zero duty"), | |
| "memory": ("8542.32", "Electronic integrated circuits (memory)", 0.0, "ITA zero duty"), | |
| "ssd": ("8523.51", "Solid-state non-volatile storage", 0.0, "ITA zero duty"), | |
| "hdd": ("8524.99", "Magnetic storage devices", 0.0, "ITA zero duty"), | |
| "hard drive": ("8524.99", "Magnetic storage devices", 0.0, "ITA zero duty"), | |
| "usb drive": ("8523.51", "Solid-state non-volatile storage", 0.0, "ITA zero duty"), | |
| "flash drive": ("8523.51", "Solid-state non-volatile storage", 0.0, "ITA zero duty"), | |
| "keyboard": ("8471.60", "Input/output units (keyboards)", 0.0, "ITA zero duty"), | |
| "mouse": ("8471.60", "Input/output units (mice)", 0.0, "ITA zero duty"), | |
| "printer": ("8443.32", "Printers, copying machines", 0.0, "ITA zero duty"), | |
| "scanner": ("8443.32", "Scanners", 0.0, "ITA zero duty"), | |
| "camera": ("8525.89", "Television cameras, digital cameras", 0.0, "ITA zero duty"), | |
| "webcam": ("8525.89", "Digital cameras", 0.0, "ITA zero duty"), | |
| "speaker": ("8518.22", "Loudspeakers", 0.0, "ITA zero duty"), | |
| "bluetooth speaker": ("8518.22", "Loudspeakers", 0.0, "ITA zero duty"), | |
| "router": ("8517.62", "Routers and switches", 0.0, "ITA zero duty"), | |
| "switch ": ("8517.62", "Network switches", 0.0, "ITA zero duty"), | |
| "modem": ("8517.62", "Modems", 0.0, "ITA zero duty"), | |
| "wifi": ("8517.62", "Wireless network equipment", 0.0, "ITA zero duty"), | |
| "antenna": ("8517.71", "Antenna and parts", 0.0, "ITA zero duty"), | |
| "battery": ("8507.60", "Lithium-ion accumulators", 0.0, "ITA zero duty"), | |
| "power bank": ("8507.60", "Portable battery packs", 0.0, "ITA zero duty"), | |
| "solar panel": ("8541.40", "Photovoltaic cells", 0.0, "ITA zero duty"), | |
| "led": ("9405.42", "LED light sources", 0.0, "ITA zero duty"), | |
| "light bulb": ("9405.42", "LED light sources", 0.0, "Standard rate"), | |
| "cable": ("8544.42", "Electric conductors, fitted with connectors", 0.0, "ITA zero duty"), | |
| "wire": ("8544.49", "Electric conductors", 0.0, "ITA zero duty"), | |
| "cable tie": ("3926.90", "Plastic articles", 0.065, "Standard rate"), | |
| "connector": ("8536.90", "Electrical connectors", 0.0, "ITA zero duty"), | |
| "plug": ("8536.90", "Electrical plugs and sockets", 0.0, "ITA zero duty"), | |
| "socket": ("8536.90", "Electrical plugs and sockets", 0.0, "ITA zero duty"), | |
| "extension cord": ("8544.42", "Extension cords", 0.0, "ITA zero duty"), | |
| "surge protector": ("8536.30", "Surge protectors", 0.0, "ITA zero duty"), | |
| "ups ": ("8504.40", "Uninterruptible power supplies", 0.0, "ITA zero duty"), | |
| "server": ("8471.50", "Processing units (servers)", 0.0, "ITA zero duty"), | |
| "workstation": ("8471.50", "Processing units", 0.0, "ITA zero duty"), | |
| "graphics card": ("8473.30", "Parts for computers", 0.0, "ITA zero duty"), | |
| "gpu ": ("8473.30", "Parts for computers", 0.0, "ITA zero duty"), | |
| "motherboard": ("8473.30", "Parts for computers", 0.0, "ITA zero duty"), | |
| "ram ": ("8542.32", "Memory modules", 0.0, "ITA zero duty"), | |
| "smartphone": ("8517.13", "Smartphones", 0.0, "ITA zero duty"), | |
| "mobile phone": ("8517.13", "Mobile phones", 0.0, "ITA zero duty"), | |
| "tablet": ("8471.30", "Tablet computers", 0.0, "ITA zero duty"), | |
| "ipad": ("8471.30", "Tablet computers", 0.0, "ITA zero duty"), | |
| "smartwatch": ("9102.12", "Smartwatches", 0.045, "Standard rate"), | |
| "drone": ("8802.20", "Unmanned aircraft", 0.0, "ITA zero duty"), | |
| "drone parts": ("8803.90", "Parts of aircraft", 0.0, "ITA zero duty"), | |
| "vr headset": ("9013.80", "Liquid crystal devices", 0.0, "ITA zero duty"), | |
| "headset": ("8518.30", "Headphones and headsets", 0.0, "ITA zero duty"), | |
| "microphone": ("8518.10", "Microphones", 0.0, "ITA zero duty"), | |
| "amplifier": ("8518.50", "Audio amplifiers", 0.0, "ITA zero duty"), | |
| "projector": ("9006.59", "Photographic projectors", 0.0, "ITA zero duty"), | |
| "external hard drive": ("8524.99", "Magnetic storage devices", 0.0, "ITA zero duty"), | |
| "smart home": ("8543.70", "Electrical machines with individual functions", 0.0, "ITA zero duty"), | |
| "thermostat": ("9032.10", "Thermostats", 0.0, "ITA zero duty"), | |
| "security camera": ("8525.83", "Television cameras", 0.0, "ITA zero duty"), | |
| "cctv": ("8525.83", "Television cameras", 0.0, "ITA zero duty"), | |
| "doorbell": ("8536.30", "Electric doorbells", 0.0, "ITA zero duty"), | |
| # ── Food & Beverages (Chapter 01-24) ───────────────────────── | |
| "coffee": ("0901.11", "Coffee, not roasted, not decaffeinated", 0.075, "Standard rate"), | |
| "coffee beans": ("0901.11", "Coffee beans, not roasted", 0.075, "Standard rate"), | |
| "arabica": ("0901.11", "Coffee beans, not roasted", 0.075, "Standard rate"), | |
| "robusta": ("0901.11", "Coffee beans, not roasted", 0.075, "Standard rate"), | |
| "roasted coffee": ("0901.21", "Coffee, roasted, not decaffeinated", 0.075, "Standard rate"), | |
| "tea": ("0902.10", "Green tea, in packages ≤ 3kg", 0.0, "Standard rate"), | |
| "black tea": ("0902.30", "Black tea, fermented, in packages ≤ 3kg", 0.0, "Standard rate"), | |
| "spice": ("0910.99", "Spices and mixes", 0.0, "Standard rate"), | |
| "pepper": ("0904.11", "Pepper, neither crushed nor ground", 0.0, "Standard rate"), | |
| "chili": ("0904.21", "Chili peppers, dried", 0.0, "Standard rate"), | |
| "cinnamon": ("0906.11", "Cinnamon, not crushed", 0.0, "Standard rate"), | |
| "rice": ("1006.30", "Semi-milled or milled rice", 0.0, "Standard rate"), | |
| "wheat": ("1001.19", "Wheat and meslin", 0.0, "Standard rate"), | |
| "flour": ("1101.00", "Wheat or meslin flour", 0.0, "Standard rate"), | |
| "sugar": ("1701.14", "Raw cane sugar", 0.0, "Standard rate"), | |
| "chocolate": ("1806.32", "Chocolate, not filled", 0.08, "Standard rate"), | |
| "cocoa": ("1801.00", "Cocoa beans", 0.0, "Standard rate"), | |
| "honey": ("0409.00", "Natural honey", 0.17, "Standard rate"), | |
| "olive oil": ("1509.10", "Virgin olive oil", 0.0, "Standard rate"), | |
| "vegetable oil": ("1507.10", "Soybean oil, crude", 0.0, "Standard rate"), | |
| "pasta": ("1902.19", "Pasta, not stuffed", 0.0, "Standard rate"), | |
| "noodles": ("1902.30", "Other pasta", 0.0, "Standard rate"), | |
| "biscuit": ("1905.31", "Sweet biscuits", 0.08, "Standard rate"), | |
| "cookie": ("1905.31", "Sweet biscuits", 0.08, "Standard rate"), | |
| "snack": ("1905.90", "Bakery products", 0.08, "Standard rate"), | |
| "chips": ("2008.19", "Roasted nuts and snacks", 0.0, "Standard rate"), | |
| "nuts": ("0802.11", "Almonds, fresh", 0.0, "Standard rate"), | |
| "almond": ("0802.11", "Almonds, fresh", 0.0, "Standard rate"), | |
| "cashew": ("0803.90", "Bananas and plantains", 0.0, "Standard rate"), | |
| "peanut": ("1202.41", "Groundnuts, not roasted", 0.0, "Standard rate"), | |
| "wine": ("2204.21", "Wine of fresh grapes, in containers ≤ 2L", 0.032, "Standard rate"), | |
| "beer": ("2203.00", "Beer made from malt", 0.0, "Standard rate"), | |
| "whisky": ("2208.30", "Whiskies", 0.0, "Standard rate"), | |
| "vodka": ("2208.90", "Spirits and liqueurs", 0.0, "Standard rate"), | |
| "juice": ("2009.12", "Orange juice, frozen", 0.0, "Standard rate"), | |
| "water bottle": ("2201.10", "Waters, mineral and aerated", 0.0, "Standard rate"), | |
| "milk": ("0401.20", "Milk and cream, not concentrated", 0.0, "Standard rate"), | |
| "cheese": ("0406.90", "Cheese and curd", 0.0, "Standard rate"), | |
| "butter": ("0405.10", "Butter", 0.0, "Standard rate"), | |
| "egg": ("0407.11", "Fresh eggs of chickens", 0.0, "Standard rate"), | |
| "frozen meat": ("0202.30", "Meat of bovine animals, boneless, frozen", 0.125, "Standard rate"), | |
| "chicken": ("0207.14", "Frozen chicken cuts", 0.0, "Standard rate"), | |
| "fish": ("0303.89", "Frozen fish", 0.0, "Standard rate"), | |
| "shrimp": ("0306.17", "Frozen shrimps and prawns", 0.0, "Standard rate"), | |
| "canned food": ("2023.90", "Prepared or preserved meat", 0.25, "Standard rate"), | |
| "sauce": ("2103.90", "Sauces and preparations", 0.0, "Standard rate"), | |
| "condiment": ("2103.90", "Sauces and condiments", 0.0, "Standard rate"), | |
| "vinegar": ("2209.00", "Vinegar", 0.0, "Standard rate"), | |
| "salt": ("2501.00", "Sodium chloride", 0.0, "Standard rate"), | |
| # ── Textiles & Clothing (Chapter 50-63) ────────────────────── | |
| "shirt": ("6105.10", "Men's shirts, cotton, knitted", 0.12, "Textile rate"), | |
| "t-shirt": ("6109.10", "T-shirts, cotton, knitted", 0.12, "Textile rate"), | |
| "polo": ("6105.10", "Men's shirts, cotton, knitted", 0.12, "Textile rate"), | |
| "jersey": ("6110.30", "Jerseys and pullovers", 0.12, "Textile rate"), | |
| "pullover": ("6110.30", "Pullovers and sweatshirts", 0.12, "Textile rate"), | |
| "sweater": ("6110.30", "Sweaters and pullovers", 0.12, "Textile rate"), | |
| "hoodie": ("6110.30", "Hoodies and sweatshirts", 0.12, "Textile rate"), | |
| "jacket": ("6201.93", "Men's jackets, man-made fibres", 0.12, "Textile rate"), | |
| "coat": ("6201.10", "Overcoats, raincoats", 0.12, "Textile rate"), | |
| "vest": ("6110.30", "Vests and waistcoats", 0.12, "Textile rate"), | |
| "pants": ("6203.42", "Men's trousers, cotton", 0.12, "Textile rate"), | |
| "trousers": ("6203.42", "Men's trousers, cotton", 0.12, "Textile rate"), | |
| "jeans": ("6203.42", "Men's jeans, cotton", 0.12, "Textile rate"), | |
| "shorts": ("6203.59", "Men's shorts", 0.12, "Textile rate"), | |
| "skirt": ("6204.53", "Women's skirts, man-made fibres", 0.12, "Textile rate"), | |
| "dress": ("6204.43", "Women's dresses, synthetic fibres", 0.12, "Textile rate"), | |
| "leggings": ("6115.95", "Stockings and leggings", 0.12, "Textile rate"), | |
| "socks": ("6115.95", "Stockings and socks", 0.12, "Textile rate"), | |
| "underwear": ("6107.11", "Men's underpants, cotton, knitted", 0.12, "Textile rate"), | |
| "bra": ("6212.10", "Brassieres", 0.12, "Textile rate"), | |
| "swimsuit": ("6112.41", "Women's swimwear, synthetic fibres", 0.12, "Textile rate"), | |
| "uniform": ("6110.30", "Uniforms and workwear", 0.12, "Textile rate"), | |
| "workwear": ("6211.33", "Men's clothing, man-made fibres", 0.12, "Textile rate"), | |
| "scarf": ("6117.10", "Shawls, scarves", 0.12, "Textile rate"), | |
| "tie ": ("6215.20", "Ties and bow ties", 0.12, "Textile rate"), | |
| "glove": ("6116.93", "Gloves, knitted", 0.12, "Textile rate"), | |
| "hat ": ("6505.00", "Hats and headgear, knitted", 0.12, "Textile rate"), | |
| "cap ": ("6505.00", "Caps and headgear", 0.12, "Textile rate"), | |
| "beanie": ("6505.00", "Headgear, knitted", 0.12, "Textile rate"), | |
| "blanket": ("6302.21", "Bed linen, cotton, printed", 0.12, "Textile rate"), | |
| "towel": ("6302.60", "Toilet and kitchen linen", 0.12, "Textile rate"), | |
| "curtain": ("6303.91", "Curtains, cotton", 0.12, "Textile rate"), | |
| "fabric": ("5208.12", "Woven cotton fabrics", 0.08, "Textile rate"), | |
| "yarn": ("5204.19", "Cotton sewing thread", 0.0, "Standard rate"), | |
| # ── Footwear (Chapter 64) ──────────────────────────────────── | |
| "shoes": ("6403.99", "Footwear with leather uppers", 0.169, "Footwear rate"), | |
| "boots": ("6403.99", "Boots with leather uppers", 0.169, "Footwear rate"), | |
| "sneakers": ("6404.11", "Sports footwear, rubber/plastic soles", 0.169, "Footwear rate"), | |
| "running shoes": ("6404.11", "Sports footwear, rubber/plastic soles", 0.169, "Footwear rate"), | |
| "sandals": ("6403.99", "Sandals with leather uppers", 0.169, "Footwear rate"), | |
| "slippers": ("6404.19", "Slippers, textile uppers", 0.169, "Footwear rate"), | |
| "flip flops": ("6404.19", "Flip flops, rubber soles", 0.169, "Footwear rate"), | |
| "heels": ("6403.99", "High-heeled shoes", 0.169, "Footwear rate"), | |
| "loafers": ("6403.99", "Leather loafers", 0.169, "Footwear rate"), | |
| "football boots": ("6404.11", "Football boots", 0.169, "Footwear rate"), | |
| "hiking boots": ("6403.99", "Hiking boots, leather uppers", 0.169, "Footwear rate"), | |
| "work boots": ("6403.99", "Safety boots", 0.169, "Footwear rate"), | |
| # ── Bags & Leather (Chapter 42) ────────────────────────────── | |
| "bag": ("4202.21", "Handbags, leather", 0.08, "Standard rate"), | |
| "handbag": ("4202.21", "Handbags, leather", 0.08, "Standard rate"), | |
| "backpack": ("4202.92", "Backpacks, textile", 0.08, "Standard rate"), | |
| "luggage": ("4202.12", "Trunks and suitcases, hard shell", 0.08, "Standard rate"), | |
| "suitcase": ("4202.12", "Suitcases, hard shell", 0.08, "Standard rate"), | |
| "wallet": ("4202.31", "Wallets, leather", 0.08, "Standard rate"), | |
| "purse": ("4202.31", "Purses, leather", 0.08, "Standard rate"), | |
| "briefcase": ("4202.12", "Briefcases", 0.08, "Standard rate"), | |
| "laptop bag": ("4202.92", "Laptop bags", 0.08, "Standard rate"), | |
| "belt ": ("4203.30", "Belts and bandoliers, leather", 0.08, "Standard rate"), | |
| # ── Toys & Games (Chapter 95) ──────────────────────────────── | |
| "toy": ("9503.00", "Toys and models", 0.047, "Standard rate"), | |
| "doll": ("9503.00", "Dolls and toy figures", 0.047, "Standard rate"), | |
| "puzzle": ("9503.00", "Puzzles and jigsaws", 0.047, "Standard rate"), | |
| "lego": ("9503.00", "Construction toys", 0.047, "Standard rate"), | |
| "board game": ("9504.90", "Board games", 0.0, "Standard rate"), | |
| "card game": ("9504.90", "Card games", 0.0, "Standard rate"), | |
| "playing cards": ("9504.40", "Playing cards", 0.0, "Standard rate"), | |
| "action figure": ("9503.00", "Toy figures", 0.047, "Standard rate"), | |
| "stuffed animal": ("9503.00", "Stuffed toys", 0.047, "Standard rate"), | |
| "plush": ("9503.00", "Stuffed toys", 0.047, "Standard rate"), | |
| "remote control car": ("9503.00", "Radio-controlled toys", 0.047, "Standard rate"), | |
| "rc car": ("9503.00", "Radio-controlled toys", 0.047, "Standard rate"), | |
| "balloon": ("9503.00", "Toy balloons", 0.047, "Standard rate"), | |
| "kite": ("9503.00", "Kites and similar toys", 0.047, "Standard rate"), | |
| "video game": ("9504.50", "Video game consoles and machines", 0.0, "Standard rate"), | |
| "console": ("9504.50", "Game consoles", 0.0, "Standard rate"), | |
| "controller": ("9504.50", "Game controllers", 0.0, "Standard rate"), | |
| # ── Furniture (Chapter 94) ─────────────────────────────────── | |
| "chair": ("9401.30", "Swivel chairs with adjustable height", 0.0, "Standard rate"), | |
| "desk": ("9403.30", "Office furniture, wood", 0.0, "Standard rate"), | |
| "table": ("9403.40", "Kitchen furniture, wood", 0.0, "Standard rate"), | |
| "sofa": ("9401.61", "Upholstered seats, wooden frame", 0.0, "Standard rate"), | |
| "couch": ("9401.61", "Upholstered seats, wooden frame", 0.0, "Standard rate"), | |
| "bed ": ("9403.50", "Wooden furniture for bedrooms", 0.0, "Standard rate"), | |
| "mattress": ("9404.21", "Mattresses of cellular rubber", 0.0, "Standard rate"), | |
| "bookshelf": ("9403.40", "Shelving, wood", 0.0, "Standard rate"), | |
| "cabinet": ("9403.40", "Cabinets, wood", 0.0, "Standard rate"), | |
| "wardrobe": ("9403.50", "Wooden furniture for bedrooms", 0.0, "Standard rate"), | |
| "filing cabinet": ("9403.10", "Metal furniture for offices", 0.0, "Standard rate"), | |
| "shoe rack": ("9403.40", "Shelving, wood", 0.0, "Standard rate"), | |
| "tv stand": ("9403.40", "TV stands, wood", 0.0, "Standard rate"), | |
| # ── Home & Kitchen (Chapter 69-73, 82-83) ──────────────────── | |
| "mug": ("6912.00", "Ceramic tableware", 0.0, "Standard rate"), | |
| "cup": ("6912.00", "Ceramic cups", 0.0, "Standard rate"), | |
| "plate": ("6911.10", "Tableware, porcelain", 0.0, "Standard rate"), | |
| "bowl": ("6911.10", "Ceramic bowls", 0.0, "Standard rate"), | |
| "glass": ("7013.37", "Drinking glasses", 0.0, "Standard rate"), | |
| "bottle": ("7010.90", "Glass bottles", 0.0, "Standard rate"), | |
| "vase": ("7013.99", "Ceramic or glass vases", 0.0, "Standard rate"), | |
| "pan ": ("7323.93", "Steel cooking articles", 0.0, "Standard rate"), | |
| "pot ": ("7323.93", "Steel pots and pans", 0.0, "Standard rate"), | |
| "frying pan": ("7323.93", "Frying pans, steel", 0.0, "Standard rate"), | |
| "cooking pot": ("7323.93", "Cooking pots, steel", 0.0, "Standard rate"), | |
| "knife": ("8211.91", "Kitchen knives with fixed blades", 0.0, "Standard rate"), | |
| "kitchen knife": ("8211.91", "Kitchen knives with fixed blades", 0.0, "Standard rate"), | |
| "fork": ("8215.99", "Forks and spoons, steel", 0.0, "Standard rate"), | |
| "spoon": ("8215.99", "Spoons, steel", 0.0, "Standard rate"), | |
| "cutlery": ("8215.99", "Cutlery sets, steel", 0.0, "Standard rate"), | |
| "blender": ("8509.40", "Food grinders and blenders", 0.0, "ITA zero duty"), | |
| "toaster": ("8516.72", "Toasters", 0.0, "ITA zero duty"), | |
| "kettle": ("8516.10", "Electric water heaters", 0.0, "ITA zero duty"), | |
| "microwave": ("8516.50", "Microwave ovens", 0.0, "ITA zero duty"), | |
| "oven": ("8516.60", "Electric ovens", 0.0, "ITA zero duty"), | |
| "refrigerator": ("8418.10", "Refrigerators, combined", 0.0, "ITA zero duty"), | |
| "freezer": ("8418.30", "Freezers", 0.0, "ITA zero duty"), | |
| "washing machine": ("8450.11", "Fully-automatic washing machines", 0.0, "ITA zero duty"), | |
| "dryer": ("8451.29", "Drying machines", 0.0, "ITA zero duty"), | |
| "vacuum cleaner": ("8508.11", "Vacuum cleaners, power < 1500W", 0.0, "ITA zero duty"), | |
| "air conditioner": ("8415.10", "Window or wall type air conditioning machines", 0.0, "ITA zero duty"), | |
| "fan ": ("8414.51", "Table, floor or wall fans", 0.0, "ITA zero duty"), | |
| "heater": ("8516.29", "Electric space and soil heaters", 0.0, "ITA zero duty"), | |
| "iron ": ("8516.40", "Electric irons", 0.0, "ITA zero duty"), | |
| "hair dryer": ("8516.31", "Hair dryers", 0.0, "ITA zero duty"), | |
| "sewing machine": ("8452.21", "Sewing machines", 0.0, "ITA zero duty"), | |
| "luggage tag": ("4821.10", "Luggage labels, paper", 0.0, "Standard rate"), | |
| # ── Rubber & Plastics (Chapter 39-40) ──────────────────────── | |
| "rubber": ("4015.90", "Articles of vulcanised rubber", 0.065, "Standard rate"), | |
| "silicone": ("3926.90", "Plastic articles", 0.065, "Standard rate"), | |
| "plastic": ("3926.90", "Plastic articles", 0.065, "Standard rate"), | |
| "foam": ("3921.13", "Foam plastic articles", 0.065, "Standard rate"), | |
| "styrofoam": ("3921.13", "Polystyrene foam", 0.065, "Standard rate"), | |
| "pvc": ("3917.23", "PVC tubes and pipes", 0.065, "Standard rate"), | |
| "polyethylene": ("3917.23", "Plastic tubes and pipes", 0.065, "Standard rate"), | |
| "nitrile gloves": ("4015.90", "Rubber gloves", 0.065, "Standard rate"), | |
| "rubber band": ("4015.90", "Rubber bands", 0.065, "Standard rate"), | |
| "eraser": ("4015.90", "Rubber erasers", 0.065, "Standard rate"), | |
| "seal ": ("4016.93", "Rubber gaskets and seals", 0.065, "Standard rate"), | |
| "o-ring": ("4016.93", "O-rings, rubber", 0.065, "Standard rate"), | |
| # ── Paper & Stationery (Chapter 47-49) ─────────────────────── | |
| "paper": ("4819.10", "Cartons and boxes of paper", 0.0, "Standard rate"), | |
| "notebook": ("4820.10", "Notebooks and pads", 0.0, "Standard rate"), | |
| "pen ": ("9608.10", "Ball point pens", 0.0, "Standard rate"), | |
| "pencil": ("9609.10", "Pencils and crayons", 0.0, "Standard rate"), | |
| "marker": ("9608.20", "Felt-tipped and porous pens", 0.0, "Standard rate"), | |
| "stapler": ("8472.90", "Stapling machines", 0.0, "ITA zero duty"), | |
| "tape": ("3919.10", "Self-adhesive plastic tape", 0.065, "Standard rate"), | |
| "envelope": ("4817.10", "Envelopes, paper", 0.0, "Standard rate"), | |
| "calendar": ("4910.00", "Printed calendars", 0.0, "Standard rate"), | |
| "book ": ("4901.99", "Printed books, brochures", 0.0, "Standard rate"), | |
| "textbook": ("4901.99", "Textbooks and educational books", 0.0, "Standard rate"), | |
| "magazine": ("4902.10", "Newspapers and magazines", 0.0, "Standard rate"), | |
| "newspaper": ("4902.10", "Newspapers", 0.0, "Standard rate"), | |
| "brochure": ("4911.99", "Printed matter", 0.0, "Standard rate"), | |
| "poster": ("4911.99", "Printed posters", 0.0, "Standard rate"), | |
| "sticker": ("4911.91", "Printed stickers and labels", 0.0, "Standard rate"), | |
| "label": ("4821.10", "Printed labels", 0.0, "Standard rate"), | |
| # ── Beauty & Personal Care (Chapter 33-34) ─────────────────── | |
| "perfume": ("3303.00", "Perfumes and toilet waters", 0.0, "Standard rate"), | |
| "cologne": ("3303.00", "Perfumes", 0.0, "Standard rate"), | |
| "shampoo": ("3305.10", "Shampoos", 0.0, "Standard rate"), | |
| "conditioner": ("3305.90", "Hair preparations", 0.0, "Standard rate"), | |
| "soap": ("3401.11", "Toilet soap", 0.0, "Standard rate"), | |
| "lotion": ("3304.99", "Beauty preparations", 0.0, "Standard rate"), | |
| "moisturizer": ("3304.99", "Skin moisturizers", 0.0, "Standard rate"), | |
| "sunscreen": ("3304.99", "Sunscreen preparations", 0.0, "Standard rate"), | |
| "makeup": ("3304.91", "Lip and eye makeup", 0.0, "Standard rate"), | |
| "cosmetics": ("3304.99", "Cosmetic preparations", 0.0, "Standard rate"), | |
| "toothpaste": ("3306.10", "Toothpaste", 0.0, "Standard rate"), | |
| "toothbrush": ("9603.21", "Toothbrushes", 0.0, "Standard rate"), | |
| "razor": ("9615.11", "Razor blades", 0.0, "Standard rate"), | |
| "deodorant": ("3307.20", "Deodorants", 0.0, "Standard rate"), | |
| "candle": ("3406.00", "Candles and tapers", 0.0, "Standard rate"), | |
| "essential oil": ("3301.90", "Essential oils", 0.0, "Standard rate"), | |
| # ── Sports & Outdoor (Chapter 95) ──────────────────────────── | |
| "football": ("9506.62", "Inflatable balls", 0.0, "Standard rate"), | |
| "soccer ball": ("9506.62", "Inflatable balls", 0.0, "Standard rate"), | |
| "basketball": ("9506.62", "Basketballs", 0.0, "Standard rate"), | |
| "tennis": ("9506.40", "Tennis rackets", 0.0, "Standard rate"), | |
| "golf": ("9506.39", "Golf clubs and equipment", 0.0, "Standard rate"), | |
| "yoga mat": ("9506.99", "Sports equipment", 0.0, "Standard rate"), | |
| "gym equipment": ("9506.91", "Articles for gymnasium", 0.0, "Standard rate"), | |
| "dumbbell": ("9506.91", "Articles for gymnasium", 0.0, "Standard rate"), | |
| "bicycle": ("8712.00", "Bicycles", 0.14, "Standard rate"), | |
| "bike": ("8712.00", "Bicycles", 0.14, "Standard rate"), | |
| "helmet": ("6506.10", "Helmets for riders", 0.0, "Standard rate"), | |
| "fishing rod": ("9507.10", "Fishing rods", 0.0, "Standard rate"), | |
| "camping tent": ("6307.90", "Tent articles", 0.0, "Standard rate"), | |
| "sleeping bag": ("9404.30", "Sleeping bags", 0.0, "Standard rate"), | |
| "backpack outdoor": ("4202.92", "Backpacks", 0.08, "Standard rate"), | |
| "ski": ("9506.11", "Skis for snow", 0.0, "Standard rate"), | |
| "surfboard": ("9506.99", "Surf boards", 0.0, "Standard rate"), | |
| "swimming goggles": ("9506.99", "Swimming goggles", 0.0, "Standard rate"), | |
| "boxing gloves": ("9506.99", "Boxing gloves", 0.0, "Standard rate"), | |
| "badminton": ("9506.59", "Badminton rackets", 0.0, "Standard rate"), | |
| "ping pong": ("9506.40", "Table tennis equipment", 0.0, "Standard rate"), | |
| "billiard": ("9504.90", "Billiard equipment", 0.0, "Standard rate"), | |
| "pool cue": ("9504.90", "Billiard cues", 0.0, "Standard rate"), | |
| # ── Automotive Parts (Chapter 85-87) ───────────────────────── | |
| "brake pad": ("8708.30", "Brakes and servo-brakes", 0.025, "Standard rate"), | |
| "oil filter": ("8421.23", "Oil or fuel filters", 0.0, "ITA zero duty"), | |
| "air filter": ("8421.23", "Air filters", 0.0, "ITA zero duty"), | |
| "spark plug": ("8511.10", "Spark plugs", 0.0, "ITA zero duty"), | |
| "alternator": ("8511.20", "Alternators", 0.0, "ITA zero duty"), | |
| "starter motor": ("8511.40", "Starter motors", 0.0, "ITA zero duty"), | |
| "headlight": ("8512.20", "Lighting equipment for vehicles", 0.0, "ITA zero duty"), | |
| "taillight": ("8512.20", "Vehicle lighting equipment", 0.0, "ITA zero duty"), | |
| "wing mirror": ("8708.29", "Parts for vehicles", 0.025, "Standard rate"), | |
| "bumper": ("8708.10", "Bumpers and parts", 0.025, "Standard rate"), | |
| "windshield": ("7007.21", "Laminated safety glass", 0.0, "ITA zero duty"), | |
| "tyre": ("4011.10", "New pneumatic rubber tyres, cars", 0.045, "Standard rate"), | |
| "tire ": ("4011.10", "New pneumatic rubber tyres, cars", 0.045, "Standard rate"), | |
| "wheel": ("8708.70", "Wheels and parts", 0.025, "Standard rate"), | |
| "car battery": ("8507.10", "Lead-acid accumulators for vehicles", 0.0, "ITA zero duty"), | |
| "car seat cover": ("8708.99", "Parts for motor vehicles", 0.025, "Standard rate"), | |
| "floor mat car": ("8708.99", "Vehicle interior fittings", 0.025, "Standard rate"), | |
| # ── Jewelry & Watches (Chapter 71) ─────────────────────────── | |
| "ring ": ("7113.11", "Rings, silver", 0.025, "Standard rate"), | |
| "necklace": ("7113.19", "Necklaces, other precious metal", 0.025, "Standard rate"), | |
| "bracelet": ("7113.19", "Bracelets, precious metal", 0.025, "Standard rate"), | |
| "earring": ("7113.19", "Earrings, precious metal", 0.025, "Standard rate"), | |
| "watch": ("9101.19", "Wrist-watches with case of precious metal", 0.045, "Standard rate"), | |
| "pendant": ("7113.19", "Pendants, precious metal", 0.025, "Standard rate"), | |
| "brooch": ("7113.19", "Brooches, precious metal", 0.025, "Standard rate"), | |
| "anklet": ("7117.19", "Imitation jewellery, base metal", 0.04, "Standard rate"), | |
| "jewelry": ("7113.19", "Jewellery, precious metal", 0.025, "Standard rate"), | |
| # ── Building Materials (Chapter 68-73) ──────────────────────── | |
| "tile": ("6907.21", "Ceramic tiles", 0.0, "Standard rate"), | |
| "marble": ("6802.93", "Marble and articles", 0.0, "Standard rate"), | |
| "granite": ("6802.93", "Granite and articles", 0.0, "Standard rate"), | |
| "ceramic": ("6907.21", "Ceramic tiles", 0.0, "Standard rate"), | |
| "steel pipe": ("7304.31", "Seamless pipes, iron or steel", 0.0, "Standard rate"), | |
| "steel tube": ("7304.31", "Seamless tubes, iron or steel", 0.0, "Standard rate"), | |
| "aluminium": ("7604.21", "Aluminium tubes and pipes", 0.0, "Standard rate"), | |
| "cement": ("2523.29", "Portland cement", 0.0, "Standard rate"), | |
| "sand": ("2505.90", "Natural sands", 0.0, "Standard rate"), | |
| "gravel": ("2517.10", "Pebbles and gravel", 0.0, "Standard rate"), | |
| "brick": ("6904.10", "Ceramic building bricks", 0.0, "Standard rate"), | |
| "insulation": ("6808.00", "Panels of fibres and cement", 0.0, "Standard rate"), | |
| "paint": ("3208.90", "Paints and varnishes", 0.065, "Standard rate"), | |
| "varnish": ("3208.90", "Varnishes", 0.065, "Standard rate"), | |
| "adhesive": ("3506.99", "Prepared glues and adhesives", 0.0, "Standard rate"), | |
| "glue": ("3506.99", "Glues and adhesives", 0.0, "Standard rate"), | |
| "nail": ("7317.00", "Nails and tacks, iron or steel", 0.0, "Standard rate"), | |
| "screw": ("7318.15", "Screws and bolts, iron or steel", 0.0, "Standard rate"), | |
| "bolt": ("7318.15", "Bolts and screws, iron or steel", 0.0, "Standard rate"), | |
| "nut ": ("7318.16", "Nuts, iron or steel", 0.0, "Standard rate"), | |
| "washer": ("7318.22", "Washers, iron or steel", 0.0, "Standard rate"), | |
| "spring": ("7320.20", "Helical springs, iron or steel", 0.0, "Standard rate"), | |
| # ── Medical & Pharmaceutical (Chapter 30, 90) ──────────────── | |
| "mask": ("6307.90", "Face masks, textile", 0.0, "Standard rate"), | |
| "surgical mask": ("6307.90", "Surgical masks", 0.0, "Standard rate"), | |
| "glove medical": ("4015.90", "Medical examination gloves", 0.065, "Standard rate"), | |
| "bandage": ("3005.90", "Bandages and dressings", 0.0, "Standard rate"), | |
| "syringe": ("9018.31", "Syringes and needles", 0.0, "Standard rate"), | |
| " thermometer": ("9025.80", "Thermometers", 0.0, "ITA zero duty"), | |
| "stethoscope": ("9018.19", "Electro-diagnostic apparatus", 0.0, "ITA zero duty"), | |
| "hearing aid": ("9021.40", "Hearing aids", 0.0, "ITA zero duty"), | |
| "prosthetic": ("9021.39", "Artificial joints and other", 0.0, "ITA zero duty"), | |
| "wheelchair": ("8713.10", "Wheelchairs not mechanically propelled", 0.0, "ITA zero duty"), | |
| # ── Musical Instruments (Chapter 92) ────────────────────────── | |
| "guitar": ("9202.10", "String musical instruments (guitars)", 0.0, "Standard rate"), | |
| "piano": ("9201.10", "Grand pianos", 0.0, "Standard rate"), | |
| "keyboard musical": ("9207.10", "Keyboard instruments (electronic)", 0.0, "ITA zero duty"), | |
| "drum ": ("9206.00", "Percussion musical instruments", 0.0, "Standard rate"), | |
| "violin": ("9202.10", "Violins and string instruments", 0.0, "Standard rate"), | |
| "flute": ("9205.10", "Wind musical instruments", 0.0, "Standard rate"), | |
| "saxophone": ("9205.10", "Saxophones", 0.0, "Standard rate"), | |
| "trumpet": ("9205.10", "Trumpets", 0.0, "Standard rate"), | |
| "ukulele": ("9202.10", "Ukuleles", 0.0, "Standard rate"), | |
| "harmonica": ("9204.10", "Harmonicas", 0.0, "Standard rate"), | |
| "amplifier musical": ("8518.50", "Audio frequency amplifiers", 0.0, "ITA zero duty"), | |
| "guitar amp": ("8518.50", "Guitar amplifiers", 0.0, "ITA zero duty"), | |
| # ── Office Supplies ────────────────────────────────────────── | |
| "whiteboard": ("9504.90", "Board games and equipment", 0.0, "Standard rate"), | |
| "projector stand": ("9403.30", "Office furniture", 0.0, "Standard rate"), | |
| "laptop stand": ("8473.30", "Computer parts and accessories", 0.0, "ITA zero duty"), | |
| "monitor arm": ("7326.90", "Articles of iron or steel", 0.0, "Standard rate"), | |
| "desk lamp": ("9405.20", "Desk lamps", 0.0, "ITA zero duty"), | |
| "ergonomic chair": ("9401.30", "Swivel chairs", 0.0, "Standard rate"), | |
| "file holder": ("4821.10", "Labels and file holders", 0.0, "Standard rate"), | |
| "cable management": ("3926.90", "Plastic articles for cable management", 0.065, "Standard rate"), | |
| "wireless charger": ("8504.40", "Wireless chargers", 0.0, "ITA zero duty"), | |
| "magsafe": ("8504.40", "MagSafe chargers", 0.0, "ITA zero duty"), | |
| "dock": ("8473.30", "Computer docking stations", 0.0, "ITA zero duty"), | |
| "hub usb": ("8471.60", "USB hubs", 0.0, "ITA zero duty"), | |
| "ethernet cable": ("8544.42", "Electric conductors with connectors", 0.0, "ITA zero duty"), | |
| "hdmi cable": ("8544.42", "HDMI cables", 0.0, "ITA zero duty"), | |
| "power strip": ("8536.90", "Power strips and extension leads", 0.0, "ITA zero duty"), | |
| # ── Miscellaneous ──────────────────────────────────────────── | |
| "umbrella": ("6601.10", "Garden umbrellas and similar", 0.08, "Standard rate"), | |
| "decoration": ("9701.10", "Paintings, drawings and pastels", 0.0, "Standard rate"), | |
| "artwork": ("9701.10", "Original artworks", 0.0, "Standard rate"), | |
| "flower": ("0603.11", "Fresh cut roses", 0.0, "Standard rate"), | |
| "plant": ("0602.90", "Live plants", 0.0, "Standard rate"), | |
| "seed": ("1209.99", "Seeds for sowing", 0.0, "Standard rate"), | |
| "fertilizer": ("3105.20", "Mineral or chemical fertilizers", 0.0, "Standard rate"), | |
| "pet food": ("2309.10", "Dog or cat food", 0.0, "Standard rate"), | |
| "litter": ("2530.10", "Expanded minerals (cat litter)", 0.0, "Standard rate"), | |
| "aquarium": ("9306.90", "Other articles for aquariums", 0.0, "Standard rate"), | |
| "incense": ("3307.41", "Incense and宗教 articles", 0.0, "Standard rate"), | |
| "candle scented": ("3406.00", "Scented candles", 0.0, "Standard rate"), | |
| "photo frame": ("4414.90", "Frames for photographs", 0.0, "Standard rate"), | |
| "mirror": ("7009.92", "Glass mirrors, framed", 0.0, "Standard rate"), | |
| "binoculars": ("9005.80", "Binoculars", 0.0, "ITA zero duty"), | |
| "telescope": ("9005.80", "Telescopes", 0.0, "ITA zero duty"), | |
| "compass": ("9014.10", "Direction-finding compasses", 0.0, "ITA zero duty"), | |
| "scale": ("8423.10", "Weighing scales", 0.0, "ITA zero duty"), | |
| "thermos": ("9617.00", "Vacuum flasks", 0.0, "Standard rate"), | |
| "ice cream maker": ("8210.00", "Hand-operated food grinders", 0.0, "Standard rate"), | |
| "popcorn maker": ("8516.72", "Coffee or tea makers", 0.0, "ITA zero duty"), | |
| "pet bed": ("9404.21", "Mattress supports", 0.0, "Standard rate"), | |
| "dog house": ("4418.60", "Doors and windows, wood", 0.0, "Standard rate"), | |
| "bird cage": ("7326.20", "Articles of wire, iron or steel", 0.0, "Standard rate"), | |
| "smoke detector": ("8531.10", "Fire or smoke detectors", 0.0, "ITA zero duty"), | |
| "carbon monoxide detector": ("8531.10", "Gas detectors", 0.0, "ITA zero duty"), | |
| "flashlight": ("8513.10", "Hand-held electric torches", 0.0, "ITA zero duty"), | |
| "lantern": ("8513.10", "Electric lanterns", 0.0, "ITA zero duty"), | |
| "power tool": ("8467.21", "Electric drills", 0.0, "ITA zero duty"), | |
| "drill": ("8467.21", "Electric drills", 0.0, "ITA zero duty"), | |
| "saw": ("8467.22", "Electric saws", 0.0, "ITA zero duty"), | |
| "grinder": ("8467.81", "Grinding machines", 0.0, "ITA zero duty"), | |
| "sandpaper": ("6805.30", "Articles of paper with abrasive coating", 0.0, "Standard rate"), | |
| "paint brush": ("9603.30", "Artists' brushes and writing brushes", 0.0, "Standard rate"), | |
| "roller paint": ("9603.30", "Paint rollers", 0.0, "Standard rate"), | |
| "caulking gun": ("8467.81", "Hand tools, pneumatic", 0.0, "ITA zero duty"), | |
| "wrench": ("8204.11", "Hand-operated spanners and wrenches", 0.0, "Standard rate"), | |
| "screwdriver": ("8205.40", "Screwdrivers", 0.0, "Standard rate"), | |
| "pliers": ("8203.20", "Pliers, including cutting pliers", 0.0, "Standard rate"), | |
| "hammer": ("8205.20", "Hand hammers and sledge hammers", 0.0, "Standard rate"), | |
| "tape measure": ("9017.80", "Measuring tapes", 0.0, "ITA zero duty"), | |
| "level": ("9017.20", "Drawing and measuring instruments", 0.0, "ITA zero duty"), | |
| "multimeter": ("9030.33", "Multimeters", 0.0, "ITA zero duty"), | |
| "soldering iron": ("8515.11", "Soldering irons and guns", 0.0, "ITA zero duty"), | |
| "cable tester": ("9030.33", "Electrical measuring instruments", 0.0, "ITA zero duty"), | |
| "network tester": ("9030.33", "Instruments for testing electrical quantities", 0.0, "ITA zero duty"), | |
| "insulation tape": ("3919.10", "Self-adhesive plastic tape", 0.065, "Standard rate"), | |
| "duct tape": ("3919.10", "Self-adhesive tape", 0.065, "Standard rate"), | |
| "painters tape": ("4811.41", "Adhesive paper and tape", 0.0, "Standard rate"), | |
| "velcro": ("5807.90", "Labels and badges, textile", 0.12, "Textile rate"), | |
| "zipper": ("9607.11", "Slide fasteners, with chain of zinc", 0.0, "Standard rate"), | |
| "button": ("9606.21", "Buttons of plastics", 0.0, "Standard rate"), | |
| "snap": ("9606.30", "Button moulds and other parts", 0.0, "Standard rate"), | |
| "buckle": ("9607.20", "Slide fastener parts", 0.0, "Standard rate"), | |
| } | |
| def guess_hs_code(description: str) -> str: | |
| """Guess HS code from item description using keyword matching. | |
| Uses a comprehensive database of 300+ product categories. | |
| Returns (hs_code, matched_keyword) or ("9999.99", None) if no match. | |
| """ | |
| desc_lower = description.lower() | |
| # Try exact keyword matches first (most specific) | |
| best_match = None | |
| best_match_len = 0 | |
| for keyword, (hs_code, desc, duty, notes) in HS_CODE_DATABASE.items(): | |
| if keyword in desc_lower: | |
| # Prefer longer, more specific matches | |
| if len(keyword) > best_match_len: | |
| best_match = (hs_code, desc, duty, notes, keyword) | |
| best_match_len = len(keyword) | |
| if best_match: | |
| return best_match[0] | |
| # Default: unknown | |
| return "9999.99" | |
| async def classify_single_item(item: ItemInput, destination: str) -> ItemClassification: | |
| """Classify a single item with HS code and duty calculation.""" | |
| # Guess HS code from description | |
| hs_code = guess_hs_code(item.description) | |
| # Look up duty rate and description from database | |
| matched = None | |
| desc_lower = item.description.lower() | |
| for keyword, (code, desc, duty, notes) in HS_CODE_DATABASE.items(): | |
| if keyword in desc_lower and code == hs_code: | |
| matched = (code, desc, duty, notes) | |
| break | |
| if matched: | |
| taric_desc = matched[1] | |
| duty_rate = matched[2] | |
| notes = matched[3] | |
| else: | |
| # Unknown product — use TARIC API for description, default rate | |
| taric_info = await fetch_taric_description(hs_code) | |
| taric_desc = taric_info.get("description", "Unknown product") | |
| duty_rate = DEFAULT_DUTY_RATE | |
| notes = "Unknown product, using default duty rate" | |
| # Calculate values | |
| customs_value = item.quantity * item.unit_price_usd | |
| duty_amount = customs_value * duty_rate | |
| vat_rate = DEFAULT_VAT_RATE | |
| vat_amount = (customs_value + duty_amount) * vat_rate | |
| total_landed = customs_value + duty_amount + vat_amount | |
| return ItemClassification( | |
| description=item.description, | |
| hs_code=hs_code, | |
| taric_description=taric_desc[:100], | |
| origin=item.origin_country, | |
| customs_value=round(customs_value, 2), | |
| duty_rate=duty_rate, | |
| duty_amount=round(duty_amount, 2), | |
| vat_rate=vat_rate, | |
| vat_amount=round(vat_amount, 2), | |
| total_landed_cost=round(total_landed, 2), | |
| notes=notes, | |
| ) | |
| # ── API Endpoint ───────────────────────────────────────────────────── | |
| async def classify_items(request: ClassifyRequest) -> ClassifyResponse: | |
| """Classify items with HS codes and calculate duties. | |
| Accepts a list of items with descriptions, quantities, and prices. | |
| Returns HS code classifications, duty rates, and total landed costs. | |
| """ | |
| logger.info(f"Classifying {len(request.items)} items for {request.destination_country}") | |
| classified_items = [] | |
| for item in request.items: | |
| try: | |
| classified = await classify_single_item(item, request.destination_country) | |
| classified_items.append(classified) | |
| except Exception as e: | |
| logger.warning(f"Failed to classify item '{item.description}': {e}") | |
| # Return fallback classification | |
| customs_value = item.quantity * item.unit_price_usd | |
| classified_items.append(ItemClassification( | |
| description=item.description, | |
| hs_code="9999.99", | |
| taric_description="Classification failed", | |
| origin=item.origin_country, | |
| customs_value=round(customs_value, 2), | |
| duty_rate=0.15, | |
| duty_amount=round(customs_value * 0.15, 2), | |
| vat_rate=0.19, | |
| vat_amount=round(customs_value * 1.15 * 0.19, 2), | |
| total_landed_cost=round(customs_value * 1.15 * 1.19, 2), | |
| notes="Classification failed, using fallback rate", | |
| )) | |
| # Calculate summary | |
| total_customs = sum(item.customs_value for item in classified_items) | |
| total_duty = sum(item.duty_amount for item in classified_items) | |
| total_vat = sum(item.vat_amount for item in classified_items) | |
| shipping_cost = 2500.00 # Default shipping estimate | |
| summary = DutySummary( | |
| customs_value=round(total_customs, 2), | |
| total_duty=round(total_duty, 2), | |
| total_vat=round(total_vat, 2), | |
| shipping_cost=shipping_cost, | |
| total_taxes_fees=round(total_duty + total_vat, 2), | |
| total_landed_cost=round(sum(item.total_landed_cost for item in classified_items) + shipping_cost, 2), | |
| effective_rate=round((total_duty + total_vat) / total_customs * 100, 2) if total_customs > 0 else 0, | |
| ) | |
| return ClassifyResponse( | |
| status="completed", | |
| classified_at=datetime.now(timezone.utc).isoformat(), | |
| destination_country=request.destination_country, | |
| items=classified_items, | |
| summary=summary, | |
| ) | |