Add 'fiscal/' from commit '102ba84500dbd9655a0471288c3e278652593ca9'

git-subtree-dir: fiscal
git-subtree-mainline: d95165fc8f
git-subtree-split: 102ba84500
This commit is contained in:
gti
2026-09-29 14:43:23 -03:00
868 changed files with 566394 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
"""Build docs/SGV_PRODUCT_FISCAL_UI_MAP_V1.json from the SGV form definition (Delphi DFM inside SGV.exe) — READ-ONLY.
Evidence hierarchy per UI control:
1. DFM binding: data-aware control on form Tfrmproduto whose DataSource is dsproduto2 (dataset qrproduto =
'select * from c000025') and whose DataField names the column; the on-screen caption/position matches the label.
2. Column type/domain compatibility (live schema + live values).
3. Optional operator UI diff (docs/SGV_PRODUCT_FISCAL_UI_DIFF_SESSION_V1.json), which can only confirm/upgrade.
Classes: CONFIRMED_STRONG | PROBABLE | AMBIGUOUS | NO_MATCH.
"""
import json
import os
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "agent" / "src"))
from gti_fiscal_agent.firebird_reader import _connect # noqa: E402
for line in (ROOT / ".env").read_text(encoding="utf-8").splitlines():
if "=" in line and not line.startswith("#"):
k, _, v = line.partition("=")
os.environ.setdefault(k.strip(), v.strip())
DFM_JSON = ROOT / "docs" / "runs" / "sgv_product_form_bindings.json"
SESSION = ROOT / "docs" / "SGV_PRODUCT_FISCAL_UI_DIFF_SESSION_V1.json"
dfm = next(f for f in json.loads(DFM_JSON.read_text(encoding="utf-8")) if f["form_class"] == "Tfrmproduto")
bound = {c["DataField"]: c for c in dfm["controls"] if c.get("DataField") and c.get("DataSource") == "dsproduto2"}
by_label = {}
if SESSION.exists():
for r in json.loads(SESSION.read_text(encoding="utf-8")).get("results", []):
by_label[r["ui_label"]] = r
# ui_label, screen area, column (None = no column), direction, semantic, expected control name, notes
UI = [
("NCM", "Aba Estoque > Posição do Estoque/Informações", "CLASSIFICACAO_FISCAL", "n/a", "NCM canônico (8 dígitos); C000025.NCM is not on the screen", "DBEdit14", "NCM lookup control; column NCM (C000025.NCM) has no control."),
("CFOP (Nota Fiscal de Entrada)", "Config. Impostos > Nota Fiscal de Entrada", "CFOP_ENTRADA", "entrada", "CFOP padrão de entrada", "DBEdit72", "Column is empty (0/521) but the screen writes it."),
("CST de ICMS (Nota Fiscal de Entrada)", "Config. Impostos > Nota Fiscal de Entrada", "CST_ENTRADA", "entrada", "CST ICMS de entrada", "DBEdit73", "Column is empty (0/521) but the screen writes it."),
("CFOP (Nota Fiscal de Saída)", "Config. Impostos > Nota Fiscal de Saída GRUPO DE ICMS", "CFOP", "saída", "CFOP padrão de saída", "DbEdit71", ""),
("CST de ICMS (Nota Fiscal de Saída)", "Config. Impostos > Nota Fiscal de Saída GRUPO DE ICMS", "CST", "saída", "CST ICMS 3 dígitos (origem+CST)", "dbedit13", "CRT=1 emission uses CSOSN."),
("Aliq. ICMS", "Config. Impostos > Nota Fiscal de Saída GRUPO DE ICMS", "ALIQUOTA", "saída", "alíquota ICMS %", "ealiq", "Binding proven; emitted NFC-e values differ from this default (see earlier missions)."),
("CEST", "Config. Impostos > Nota Fiscal de Saída GRUPO DE ICMS", "CEST", "n/a", "CEST (7 dígitos)", "DBEdit74", ""),
("Seletor ao lado do CEST (T/I/N/S)", "Config. Impostos > Nota Fiscal de Saída GRUPO DE ICMS", "SITUACAO_TRIBUTARIA", "saída", "situação tributária do produto: T=Tributado, I=Isento, N=Não Tributado, S=Substituição Tributária", "wwDBComboBox2", "Hint of the control lists the domain; 'S' is the ERP's own ST flag."),
("Cofins Entrada", "Config. Impostos > CST PIS/COFINS", "COD_ENTRADA_COFINS", "entrada", "CST COFINS de entrada", "RzDBButtonEdit3", ""),
("Cofins Saída", "Config. Impostos > CST PIS/COFINS", "COD_SAIDA_COFINS", "saída", "CST COFINS de saída", "RzDBButtonEdit1", ""),
("Alíquota (Cofins)", "Config. Impostos > CST PIS/COFINS", "ALIQ_COFINS", "saída", "alíquota COFINS (texto)", "RzDBEdit4", ""),
("Pis Entrada", "Config. Impostos > CST PIS/COFINS", "COD_ENTRADA_PIS", "entrada", "CST PIS de entrada", "RzDBButtonEdit5", ""),
("Pis Saída", "Config. Impostos > CST PIS/COFINS", "COD_SAIDA_PIS", "saída", "CST PIS de saída", "RzDBButtonEdit2", ""),
("Alíquota (Pis)", "Config. Impostos > CST PIS/COFINS", "ALIQ_PIS", "saída", "alíquota PIS (texto)", "RzDBEdit3", ""),
("CSOSN Classificação", "Config. Impostos > CSOSN", "CSOSN", "saída", "CSOSN (código)", "DBEdit75", ""),
("CSOSN Informações - Significados", "Config. Impostos > CSOSN", None, "n/a", "descrição do CSOSN (apoio visual)", "ComboBox1", "Plain TComboBox, not data-aware: presentation helper, no column."),
("Alíquota IPI %", "Config. Impostos > IPI", "IPI", "saída", "alíquota IPI %", "RzDBEdit2", "Cálculo Preço tab has other IPI/PIS/COFINS controls bound to C000026 (price calculation), not fiscal defaults."),
("CST IPI", "Config. Impostos > IPI", "CST_IPI", "saída", "CST do IPI", "RzDBEdit1", ""),
("Código da origem da Mercadoria (0/1/2)", "Config. Impostos", "COD_ORIGEM_MERCADORIA", "n/a", "origem da mercadoria (0 Nacional, 1 Estrangeira-Importação Direta, 2 Estrangeira-Mercado Interno)", "CodOrigemMercadoria",
"Radio group RgOrigemMercadoria is not data-aware; a hidden data-aware edit bound to COD_ORIGEM_MERCADORIA sits beside it. The radio->edit copy lives in event code."),
("IAT", "Config. Impostos", "IAT", "n/a", "arredondamento/truncamento (A/T)", "wwDBComboBox3", ""),
("Incidência", "Config. Impostos", "INCIDENCIA_PISCOFINS", "n/a", "tipo de incidência PIS/COFINS", "wwDBComboBox1", ""),
("PIS/COFINS (combo)", "Config. Impostos", "PISCOFINS", "n/a", "flag PIS/COFINS (N/S)", "ecombo_piscofins", ""),
("IPPT", "Config. Impostos", "IPPT", "n/a", "produção própria/terceiros (P/T)", "wwDBComboBox4", ""),
]
cur = _connect(os.environ).cursor()
cur.execute("select trim(rf.RDB$FIELD_NAME), f.RDB$FIELD_TYPE, coalesce(f.RDB$CHARACTER_LENGTH,f.RDB$FIELD_LENGTH), f.RDB$FIELD_SCALE from RDB$RELATION_FIELDS rf join RDB$FIELDS f on f.RDB$FIELD_NAME=rf.RDB$FIELD_SOURCE where rf.RDB$RELATION_NAME='C000025'")
TN = {7: "SMALLINT", 8: "INTEGER", 14: "CHAR", 37: "VARCHAR", 27: "DOUBLE PRECISION", 16: "NUMERIC", 10: "FLOAT", 35: "TIMESTAMP", 12: "DATE"}
meta = {}
for n, t, ln, sc in cur.fetchall():
meta[n] = f"{TN.get(t, t)}({ln})" if t in (14, 37) else (f"NUMERIC(*,{-sc})" if t == 16 and sc else TN.get(t, str(t)))
def stats(col):
cur.execute(f'select "{col}", count(*) from C000025 group by "{col}" order by 2 desc')
vals = [(None if v is None else str(v).strip(), n) for v, n in cur.fetchall()]
return sum(n for v, n in vals if v not in (None, "")), [v for v, _ in vals[:5]]
entries = []
for label, area, col, direction, sem, ctrl, notes in UI:
diff = by_label.get(label)
if col is None:
entries.append({"ui_label": label, "screen_area": area, "table": "C000025", "field": None, "db_type": None, "direction": direction, "semantic": sem, "before": None, "after": None,
"confirmed_by_ui_diff": False, "classification": "NO_MATCH", "confidence": "HIGH", "binding_type": "NOT_DATA_AWARE", "evidence_basis": f"DFM: {ctrl} is not data-aware",
"write_target": False, "current_population": None, "sample_values": [], "notes": notes})
continue
c = bound.get(col)
dfm_ok = bool(c) and c["name"] == ctrl and col in meta
pop, samples = stats(col) if col in meta else (None, [])
if not dfm_ok:
klass, binding, basis = "NO_MATCH", "NO_DFM_BINDING", f"expected control {ctrl} bound to {col} not found in DFM"
elif ctrl == "CodOrigemMercadoria":
klass, binding, basis = "CONFIRMED_STRONG", "DFM_RADIO_ONCLICK_HIDDEN_EDIT", "DFM: RgOrigemMercadoria (TRadioGroup, no DataField, OnClick=RgOrigemMercadoriaClick) + hidden data-aware TDBEdit CodOrigemMercadoria bound to COD_ORIGEM_MERCADORIA in the same tab, the only origin-bound control of the form; the handler and both symbols exist in the executable; values 0/1/2 observed in 5 databases"
else:
klass, binding = "CONFIRMED_STRONG", "DFM_DATAFIELD"
basis = f"DFM: {c['class']} {c['name']} DataField={col} DataSource=dsproduto2 (qrproduto = select * from c000025)"
ui_diff = bool(diff and diff.get("binding_type") == "DIRECT_BINDING" and col in diff.get("db_fields_changed", []))
if ui_diff:
klass, binding = "CONFIRMED_STRONG", "DFM_DATAFIELD+UI_DIFF"
entries.append({"ui_label": label, "screen_area": area, "table": "C000025", "field": col, "db_type": meta.get(col), "direction": direction, "semantic": sem, "before": None, "after": None,
"confirmed_by_ui_diff": ui_diff, "classification": klass, "confidence": "HIGH" if klass == "CONFIRMED_STRONG" else "MEDIUM", "binding_type": binding, "evidence_basis": basis,
"dfm_control": {"class": c["class"], "name": c["name"], "left": c.get("Left"), "top": c.get("Top"), "container_path": [p.split(":")[1] for p in c["path"][-3:]]} if c else None,
"write_target": klass == "CONFIRMED_STRONG", "current_population": pop, "sample_values": samples, "notes": notes})
cur.connection.close()
not_on_screen = [f for f in ("ORIGEM", "GRUPO_ICMS", "MARGEM_AGREGADA", "CFOP_CUPOM", "NCM") if f not in bound]
cnt = lambda k: sum(1 for e in entries if e["classification"] == k) # noqa: E731
doc = {"artifact": "SGV_PRODUCT_FISCAL_UI_MAP_V1", "product_table": "C000025", "company_table": "C000004", "company_fields": {"CRT": "C000004.CRT", "UF": "C000004.UF"},
"evidence_source": "Delphi DFM of form Tfrmproduto extracted from SGV_5.0.6.124.exe (docs/runs/sgv_product_form_bindings.json); dsproduto2 -> qrproduto = 'select * from c000025'",
"architecture_rule": "GTI Fiscal writes ONLY the canonical product record (C000025). Transactional/historical tables are evidence only.",
"transactional_table_writes_allowed": False,
"forbidden_write_tables": ["NFCE", "NFCE_ITENS", "C000032", "C000061", "C000062", "C000088", "INVENTARIO", "C000026 (price calculation)", "any historical/document/item table"],
"columns_with_no_screen_control": [f for f in not_on_screen],
"summary": {"ui_fields_total": len(entries), "CONFIRMED_STRONG": cnt("CONFIRMED_STRONG"), "PROBABLE": cnt("PROBABLE"), "AMBIGUOUS": cnt("AMBIGUOUS"), "NO_MATCH": cnt("NO_MATCH"),
"write_target_fields": [e["field"] for e in entries if e["write_target"]],
"fields_requiring_manual_ui_diff": [e["ui_label"] for e in entries if e["classification"] in ("PROBABLE", "AMBIGUOUS")],
"unidentified_controls": ["Panel1.ealiquota -> CODALIQUOTA (data-aware, not visible in the supplied screenshots; column empty 0/521)"]},
"fields": entries}
(ROOT / "docs" / "SGV_PRODUCT_FISCAL_UI_MAP_V1.json").write_text(json.dumps(doc, ensure_ascii=False, indent=1), encoding="utf-8")
print(json.dumps(doc["summary"], ensure_ascii=False))