File size: 9,111 Bytes
f817912
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env python3
"""modutech_v30.json → modutech_v30_1.json — แพตช์ก่อน launch prototype เท่านั้น

แก้แค่สองอย่าง ไม่ใช่ v31

  1. เติม specifications.notes ของ 8 รุ่นที่ว่างเปล่าใน v30 ทั้งที่เล่มพิมพ์หมายเหตุไว้ครบ
     ดึงจาก PDF ตรง ๆ ตัดคำนำหน้า "- " ออกอย่างเดียว ไม่เรียบเรียงใหม่
     ทำไมต้องเติม: catalogue_increment_status() อ่าน specifications.notes เท่านั้น
     ถ้า notes ว่าง gate จะตรวจค่า "เพิ่มทีละ" ของรุ่นนั้นไม่ได้เลย

  2. ตั้ง temperature_trust = "unconfirmed" ให้ variant md254-rr--pph-pph ตัวเดียว
     พร้อมข้อความเตือนใน temperature_unconfirmed_th
     บอทยังตอบ 93 °C (ค่าที่เข้มกว่า) แต่แนบคำเตือนไปด้วย แทนที่จะตอบเหมือนเป็นค่ายืนยันแล้ว

ไม่แตะ: ค่าตัวเลขทุกตัว · width_effective · temperature_effective · answering · จำนวนนับ

รัน: python patch_v30_1.py modutech_v30.json <path ของ PDF> [modutech_v30_1.json]
"""
from __future__ import annotations

import copy
import hashlib
import json
import re
import sys

# ── สิ่งที่ตั้งใจจะแก้ ประกาศไว้ล่วงหน้าเพื่อให้ shadow copy ตรวจได้ ──
NOTES_PAGES = {
    "SM127 C": 75, "HC127 C": 67, "EC254 GT": 133, "MD254 FG-RT": 157,
    "MD254 GT": 163, "MD254 RR": 165, "XP254 C": 113, "XP254 PR22%": 117,
}

UNCONFIRMED_VARIANT = "md254-rr--pph-pph"
UNCONFIRMED_TH = (
    "ค่าสูงสุด 93 °C ยังไม่ยืนยัน — แคตตาล็อกหน้า 165 พิมพ์ +5/+93 °C คู่กับ +40/+230 °F "
    "ซึ่ง 230 °F เท่ากับ 110 °C ไม่ใช่ 93 °C และ 93 °C เป็นค่าเดียวกับเกรด POM ที่พิมพ์อยู่สามแถวเหนือขึ้นไป "
    "ในเล่มเดียวกันเกรด PPH ของรุ่น HC508 PR22 ระบุ 110 °C และ HP508 RR (ผิว Raised Rib เหมือนกัน) ระบุ 118 °C "
    "ระบบเลือกใช้ค่าที่เข้มกว่าคือ 93 °C ไว้ก่อน ถ้างานจริงต้องเกิน 93 °C ต้องยืนยันกับฝ่ายเทคนิคก่อนเสนอ"
)


def fingerprint(obj) -> str:
    return hashlib.sha256(
        json.dumps(obj, ensure_ascii=False, sort_keys=True, default=str).encode()
    ).hexdigest()


def notes_from_page(doc, page: int) -> list[str]:
    """บรรทัดใต้หัวข้อ Important Notes ที่ขึ้นต้นด้วย '-' ติดกัน หยุดที่บรรทัดแรกที่ไม่ขึ้นต้นด้วย '-'"""
    lines = doc[page - 1].get_text().split("\n")
    try:
        i = next(k for k, l in enumerate(lines) if l.strip() == "Important Notes")
    except StopIteration:
        raise SystemExit(f"หน้า {page}: ไม่พบหัวข้อ Important Notes — หยุด ไม่เดา")
    out = []
    for l in lines[i + 1:]:
        s = l.strip()
        if not s:
            continue
        if not s.startswith("-"):
            break
        out.append(s.lstrip("- ").strip())
    if not out:
        raise SystemExit(f"หน้า {page}: อ่านหมายเหตุไม่ได้สักบรรทัด — หยุด")
    return out


def scrub(doc: dict) -> dict:
    """ลบเฉพาะฟิลด์ที่ตั้งใจจะแก้ออกจากทั้งสองฝั่ง เพื่อให้ที่เหลือต้องเหมือนกันเป๊ะ"""
    d = copy.deepcopy(doc)
    for p in d.get("products", []):
        if p.get("belt_code") in NOTES_PAGES:
            p.get("specifications", {}).pop("notes", None)
        for v in p.get("specifications", {}).get("variants") or []:
            if v.get("variant_id") == UNCONFIRMED_VARIANT:
                v.pop("temperature_trust", None)
                v.pop("temperature_unconfirmed_th", None)
    return d


def main() -> int:
    if len(sys.argv) < 3:
        print(__doc__)
        return 2
    src, pdf = sys.argv[1], sys.argv[2]
    dst = sys.argv[3] if len(sys.argv) > 3 else "modutech_v30_1.json"

    import pymupdf
    doc = pymupdf.open(pdf)

    with open(src, encoding="utf-8") as f:
        data = json.load(f)
    shadow = copy.deepcopy(data)          # ของดิบไว้เทียบ

    by_code = {p.get("belt_code"): p for p in data.get("products", [])}

    print("1) เติม specifications.notes")
    for code, page in NOTES_PAGES.items():
        p = by_code.get(code)
        if p is None:
            raise SystemExit(f"ไม่พบรุ่น {code} ในไฟล์ — หยุด")
        spec = p.setdefault("specifications", {})
        if spec.get("page") != page:
            raise SystemExit(f"{code}: ไฟล์ระบุหน้า {spec.get('page')} แต่สคริปต์ตั้งไว้ {page} — หยุด")
        if spec.get("notes"):
            raise SystemExit(f"{code}: notes ไม่ว่าง ({len(spec['notes'])} บรรทัด) — หยุด ไม่ทับของเดิม")
        notes = notes_from_page(doc, page)
        spec["notes"] = notes
        m = re.search(r"(?<!Non-)Standard\s*b\s?elt\s*increme\s?nts?\s*([\d,\.]+)",
                      " | ".join(notes), re.IGNORECASE)
        printed = float(m.group(1).replace(",", ".").rstrip(".")) if m else None
        table = (spec.get("width_effective") or {}).get("increment_mm")
        flag = "ตรงกัน" if (printed is not None and table is not None
                            and abs(printed - table) < 0.05) else "⚠️ ไม่ตรง"
        print(f"   {code:<14} p{page}  {len(notes)} บรรทัด · เล่ม={printed} ตาราง={table} {flag}")

    print("\n2) ตั้ง temperature_trust = unconfirmed")
    hits = 0
    for p in data.get("products", []):
        for v in p.get("specifications", {}).get("variants") or []:
            if v.get("variant_id") != UNCONFIRMED_VARIANT:
                continue
            if v.get("temperature_trust") != "ok":
                raise SystemExit(f"{UNCONFIRMED_VARIANT}: temperature_trust เดิมคือ "
                                 f"{v.get('temperature_trust')!r} ไม่ใช่ 'ok' — หยุด")
            v["temperature_trust"] = "unconfirmed"
            v["temperature_unconfirmed_th"] = UNCONFIRMED_TH
            hits += 1
    if hits != 1:
        raise SystemExit(f"เจอ variant {UNCONFIRMED_VARIANT} {hits} ตัว ต้องเป็น 1 — หยุด")
    print(f"   {UNCONFIRMED_VARIANT} · ok → unconfirmed (ค่าตัวเลขไม่เปลี่ยน)")

    print("\n3) เทียบกับ shadow copy")
    a, b = fingerprint(scrub(shadow)), fingerprint(scrub(data))
    if a != b:
        raise SystemExit("❌ มีอย่างอื่นเปลี่ยนนอกเหนือจากที่ประกาศไว้ — ไม่เขียนไฟล์")
    print("   ✅ นอกจากฟิลด์ที่ประกาศไว้ ไม่มีอะไรเปลี่ยน")

    print("\n4) จำนวนนับต้องเท่าเดิม")
    n_prod = len(data["products"])
    n_var = sum(len(p.get("specifications", {}).get("variants") or []) for p in data["products"])
    n_app = sum(len(a.get("applications") or [])
                for p in data["products"] for a in p.get("industries") or [])
    n_pair = sum(len(p.get("industries") or []) for p in data["products"])
    print(f"   สินค้า {n_prod} · คู่สายพาน-อุตสาหกรรม {n_pair} · การใช้งาน {n_app} · variant {n_var}")
    if (n_prod, n_pair, n_app) != (68, 211, 651):
        raise SystemExit("❌ จำนวนนับเปลี่ยน — ไม่เขียนไฟล์")

    with open(dst, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=1)
    print(f"\nเขียน {dst} แล้ว · {src} ไม่ถูกแตะต้อง")
    return 0


if __name__ == "__main__":
    sys.exit(main())