File size: 3,575 Bytes
74bb5fe
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# app/catalog.py
from __future__ import annotations
import json, os
from typing import Dict, Any, List, Optional

_CATALOG: Dict[str, Any] | None = None

def get_catalog_path() -> str:
    here = os.path.dirname(os.path.abspath(__file__))
    root = os.path.dirname(here)
    return os.path.join(root, "data", "menu_catalog.json")

def load_catalog() -> Dict[str, Any]:
    global _CATALOG
    if _CATALOG is not None:
        return _CATALOG
    path = get_catalog_path()
    with open(path, "r", encoding="utf-8") as f:
        _CATALOG = json.load(f)
    return _CATALOG

def find_item_by_name(name: str) -> Optional[Dict[str, Any]]:
    c = load_catalog()
    name_l = (name or "").strip().lower()
    for it in c["items"]:
        if it["name"].lower() == name_l:
            return it
        # lightweight alias match
        if name_l in it["name"].lower():
            return it
    return None

def find_item_by_sku(sku: str) -> Optional[Dict[str, Any]]:
    c = load_catalog()
    for it in c["items"]:
        if it["sku"] == sku:
            return it
    return None

def required_fields_for_category(category: str) -> List[str]:
    c = load_catalog()
    schema = c["schema"].get(category) or {}
    return list(schema.get("required_fields") or [])

def optional_fields_for_category(category: str) -> List[str]:
    c = load_catalog()
    schema = c["schema"].get(category) or {}
    return list(schema.get("optional_fields") or [])

def compute_missing_fields(order_item: Dict[str, Any]) -> List[str]:
    """
    order_item: {"name": "...", "sku": optional, "qty": int, "<opts>": ...}
    Uses catalog schema to see which fields are missing.
    """
    it = None
    if "sku" in order_item:
        it = find_item_by_sku(order_item["sku"])
    if not it and "name" in order_item:
        it = find_item_by_name(order_item["name"])
    if not it:
        return ["name"]  # we don’t even know the item yet

    category = it["category"]
    req = set(required_fields_for_category(category))
    present = set([k for k in order_item.keys() if k in req or k == "qty" or k == "name" or k == "sku"])

    # qty normalization: consider qty present if >=1
    if "qty" in req and (order_item.get("qty") is None or int(order_item.get("qty", 0)) < 1):
        # keep qty “missing”
        pass
    else:
        present.add("qty")

    missing = [f for f in req if f not in present]
    return missing

def friendly_requirements_prompt(order_item: Dict[str, Any]) -> str:
    it = None
    if "sku" in order_item:
        it = find_item_by_sku(order_item["sku"])
    if not it and "name" in order_item:
        it = find_item_by_name(order_item["name"])
    if not it:
        return "Which item would you like to order?"

    category = it["category"]
    req = required_fields_for_category(category)
    opt = optional_fields_for_category(category)

    parts = []
    opt_txt = ""
    if opt:
        opt_txt = f" Optional: {', '.join(opt)}."
    if req:
        parts.append(f"I need {', '.join(req)} for {it['name']}.{opt_txt}")
    else:
        parts.append(f"Please specify quantity for {it['name']}.{opt_txt}")

    # Also list choices for required options
    # e.g., size choices
    opts = it.get("options") or {}
    choice_bits = []
    for k, spec in opts.items():
        if spec.get("required"):
            choices = spec.get("choices") or []
            if choices:
                choice_bits.append(f"{k}: {', '.join(choices)}")
    if choice_bits:
        parts.append("Choices → " + " | ".join(choice_bits))
    return " ".join(parts)