feat: close final incomplete product analysis
This commit is contained in:
@@ -0,0 +1,125 @@
|
|||||||
|
{
|
||||||
|
"artifact": "FINAL_194_PRODUCT_CLOSURE_V1",
|
||||||
|
"status": "ANALYZED_WITHOUT_NEW_RESOLUTION",
|
||||||
|
"incomplete_before": 194,
|
||||||
|
"incomplete_after": 194,
|
||||||
|
"autonomous_rate_after": 0.9944675754,
|
||||||
|
"blockers_by_type": {
|
||||||
|
"MISSING_COMPANY_CONTEXT": 4,
|
||||||
|
"MISSING_ST_FACT": 57,
|
||||||
|
"OTHER_PROVEN_BLOCKER": 156
|
||||||
|
},
|
||||||
|
"missing_field_counts": {
|
||||||
|
"ALIQUOTA": 53,
|
||||||
|
"CFOP": 79,
|
||||||
|
"CSOSN": 27,
|
||||||
|
"SITUACAO_TRIBUTARIA": 58
|
||||||
|
},
|
||||||
|
"gtin": {
|
||||||
|
"with_valid_gtin": 45,
|
||||||
|
"without_gtin": 149,
|
||||||
|
"gtin_already_in_kb": 45,
|
||||||
|
"gtin_new": 0,
|
||||||
|
"gtin_conflict": 0
|
||||||
|
},
|
||||||
|
"kb_reuse": {
|
||||||
|
"fingerprint_hits": 194,
|
||||||
|
"gtin_exact_hits": 45,
|
||||||
|
"resolved_by_kb": 0,
|
||||||
|
"officially_validated_new_required_fields": 0,
|
||||||
|
"tenant_context_shared": 0,
|
||||||
|
"fingerprint_ncm_conflicts_not_promoted": 10
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"resolvable_now_deterministically": 0,
|
||||||
|
"resolvable_with_external_product_data": 0,
|
||||||
|
"resolvable_with_ai_semantic": 0,
|
||||||
|
"human_fact_required": 4,
|
||||||
|
"data_conflict": 10,
|
||||||
|
"erp_limitation": 0
|
||||||
|
},
|
||||||
|
"ai_work_items": {
|
||||||
|
"total_before": 511,
|
||||||
|
"required_for_completeness": 0,
|
||||||
|
"optional_enrichment": 511,
|
||||||
|
"projected_cost_required_only": 0.0,
|
||||||
|
"required_products": 0,
|
||||||
|
"classification_rule": "all 511 current LLM items concern optional/reference enrichment under the current requiredness matrix"
|
||||||
|
},
|
||||||
|
"provider_impact": {
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"provider": "GS1/offical GTIN service",
|
||||||
|
"gtin_matchable": 45,
|
||||||
|
"expected_ncm_resolution": 0,
|
||||||
|
"expected_cest_resolution": 0,
|
||||||
|
"expected_other_fields": 0,
|
||||||
|
"estimated_queries": 0,
|
||||||
|
"estimated_cost": 0,
|
||||||
|
"reason": "all valid GTINs already have KB identity; no paid query needed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provider": "licensed commercial API",
|
||||||
|
"gtin_matchable": 45,
|
||||||
|
"expected_ncm_resolution": 0,
|
||||||
|
"expected_cest_resolution": 0,
|
||||||
|
"expected_other_fields": 0,
|
||||||
|
"estimated_queries": 0,
|
||||||
|
"estimated_cost": 0,
|
||||||
|
"reason": "not queried; KB-first policy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"provider": "licensed commercial bulk dataset",
|
||||||
|
"gtin_matchable": 45,
|
||||||
|
"expected_ncm_resolution": 0,
|
||||||
|
"expected_cest_resolution": 0,
|
||||||
|
"expected_other_fields": 0,
|
||||||
|
"estimated_queries": 0,
|
||||||
|
"estimated_cost": "NOT_VERIFIED",
|
||||||
|
"reason": "license and coverage not verified"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"required_products": 0,
|
||||||
|
"projected_cost": 0.0,
|
||||||
|
"cost_per_incomplete_product_resolved": 0.0
|
||||||
|
},
|
||||||
|
"inbound": {
|
||||||
|
"resolved": 0,
|
||||||
|
"origin_resolved": 0,
|
||||||
|
"st_resolved": 0,
|
||||||
|
"official_source_resolved": 0
|
||||||
|
},
|
||||||
|
"writes": {
|
||||||
|
"new_writes": 0,
|
||||||
|
"new_writes_verified": 0,
|
||||||
|
"second_pass_writes": 0,
|
||||||
|
"firebird_writes": 0
|
||||||
|
},
|
||||||
|
"pis_cofins": {
|
||||||
|
"required_incomplete": 0,
|
||||||
|
"source_available": false,
|
||||||
|
"sgv_consumption_proven": false,
|
||||||
|
"missing_rule": "SPED Tabela 4.3.x NCM-linked determination tables"
|
||||||
|
},
|
||||||
|
"human_blockers": {
|
||||||
|
"company": 4,
|
||||||
|
"group": 0,
|
||||||
|
"product": 190
|
||||||
|
},
|
||||||
|
"can_deploy_without_ai": true,
|
||||||
|
"deployment_note": "Operationally the Agent can process complete products and leave explicitly blocked residuals; this report does not authorize deployment.",
|
||||||
|
"prevents_100_percent": {
|
||||||
|
"products": 194,
|
||||||
|
"required_field_instances": 217,
|
||||||
|
"by_field": {
|
||||||
|
"ALIQUOTA": 53,
|
||||||
|
"CFOP": 79,
|
||||||
|
"CSOSN": 27,
|
||||||
|
"SITUACAO_TRIBUTARIA": 58
|
||||||
|
},
|
||||||
|
"ncm_fingerprint_conflicts_outside_baseline": 10
|
||||||
|
},
|
||||||
|
"ai_write_allowed": false,
|
||||||
|
"external_api_calls": 0,
|
||||||
|
"firebird_writes": 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
# Final 194 Product Closure V1
|
||||||
|
|
||||||
|
## Result
|
||||||
|
|
||||||
|
```text
|
||||||
|
STATUS=ANALYZED_WITHOUT_NEW_RESOLUTION
|
||||||
|
INCOMPLETE_BEFORE=194
|
||||||
|
INCOMPLETE_AFTER=194
|
||||||
|
AUTONOMOUS_RATE_AFTER=99.4468%
|
||||||
|
```
|
||||||
|
|
||||||
|
The 194 products were inventoried individually from the five local databases
|
||||||
|
using read-only Firebird access. No AI, external provider, human inference, or
|
||||||
|
Firebird write was used.
|
||||||
|
|
||||||
|
## Blockers
|
||||||
|
|
||||||
|
Field blocker instances may overlap on the same product; product total remains
|
||||||
|
194 unique `(DATABASE, PRODUCT_CODE)` keys.
|
||||||
|
|
||||||
|
```text
|
||||||
|
CFOP=79
|
||||||
|
SITUACAO_TRIBUTARIA / ST_FACT=57
|
||||||
|
ALIQUOTA=53
|
||||||
|
CSOSN=27
|
||||||
|
MISSING_COMPANY_CONTEXT=4 field instances
|
||||||
|
OTHER_PROVEN_BLOCKER=156 field instances
|
||||||
|
```
|
||||||
|
|
||||||
|
No product was resolved deterministically because every missing field lacked a
|
||||||
|
proven replacement under the current company/product context and the existing
|
||||||
|
write contract. The 4 RINCAO cases with ambiguous company context remain
|
||||||
|
`MISSING_COMPANY_CONTEXT`.
|
||||||
|
|
||||||
|
## GTIN And KB
|
||||||
|
|
||||||
|
```text
|
||||||
|
WITH_VALID_GTIN=45
|
||||||
|
WITHOUT_GTIN=149
|
||||||
|
GTIN_ALREADY_IN_KB=45
|
||||||
|
GTIN_NEW=0
|
||||||
|
GTIN_CONFLICT=0
|
||||||
|
KB_FINGERPRINT_HITS=194
|
||||||
|
RESOLVED_BY_KB=0
|
||||||
|
```
|
||||||
|
|
||||||
|
All valid GTINs already had a KB identity, so no external provider query was
|
||||||
|
necessary. Fingerprint KB hits were used for comparison only. Tenant-specific
|
||||||
|
CFOP, CSOSN, CST, ST-withheld, and company policy were never shared.
|
||||||
|
|
||||||
|
Ten fingerprint matches had NCM differences between the current product and KB
|
||||||
|
observation. They remain data conflicts and were not promoted or majority-
|
||||||
|
resolved. This is additional conflict evidence, not a hidden resolution.
|
||||||
|
|
||||||
|
## AI Residual Reclassification
|
||||||
|
|
||||||
|
```text
|
||||||
|
AI_WORK_ITEMS_TOTAL_BEFORE=511
|
||||||
|
AI_REQUIRED_FOR_COMPLETENESS=0
|
||||||
|
AI_OPTIONAL_ENRICHMENT=511
|
||||||
|
AI_REQUIRED_PRODUCTS=0
|
||||||
|
PROJECTED_AI_COST_FOR_REQUIRED_ONLY=0
|
||||||
|
```
|
||||||
|
|
||||||
|
The current 511 items are `EX_TIPI`, `CEST`, `PRODUCT_ROLE`, and `INVALID_NCM`
|
||||||
|
semantic/reference work. Under the requiredness matrix they do not currently
|
||||||
|
prevent the 194 products from reaching the measured completeness state. They
|
||||||
|
remain useful optional enrichment and are not sent to a future model merely to
|
||||||
|
increase an unrelated work-item count.
|
||||||
|
|
||||||
|
## External Providers
|
||||||
|
|
||||||
|
```text
|
||||||
|
GTIN_EXTERNAL_PROVIDER_CANDIDATES=0
|
||||||
|
EXTERNAL_PROVIDER_REQUIRED_PRODUCTS=0
|
||||||
|
PROJECTED_PROVIDER_COST=0
|
||||||
|
COST_PER_INCOMPLETE_PRODUCT_RESOLVED=0
|
||||||
|
```
|
||||||
|
|
||||||
|
The existing provider evaluation remains authorization-only. A provider was
|
||||||
|
not queried because all 45 valid GTINs were already present in the KB and 149
|
||||||
|
products have no valid GTIN. Commercial coverage, price, and license remain
|
||||||
|
`NOT_VERIFIED`.
|
||||||
|
|
||||||
|
## PIS/COFINS
|
||||||
|
|
||||||
|
```text
|
||||||
|
PIS_COFINS_REQUIRED_INCOMPLETE=0
|
||||||
|
PIS_COFINS_SOURCE_STATUS=SOURCE_AVAILABLE=false; NCM-linked SPED Tabela 4.3.x rules missing
|
||||||
|
```
|
||||||
|
|
||||||
|
The missing PIS/COFINS source is regime-specific and cannot be replaced by an
|
||||||
|
artificial NCM table. The SGV consumption of those fields remains unproven for
|
||||||
|
this residual set.
|
||||||
|
|
||||||
|
## Origin, ST, And NCM
|
||||||
|
|
||||||
|
```text
|
||||||
|
RESOLVED_BY_INBOUND=0
|
||||||
|
RESOLVED_BY_OFFICIAL_SOURCE=0
|
||||||
|
RESOLVED_OTHER_DETERMINISTIC=0
|
||||||
|
ORIGIN_RESOLVED=0
|
||||||
|
ST_RESOLVED=0
|
||||||
|
```
|
||||||
|
|
||||||
|
The inbound evidence scan found supplier observations, but no direct origin
|
||||||
|
fact sufficient for these products. ST subject evidence was not treated as
|
||||||
|
proof that ST was already withheld. Invalid/conflicting NCM evidence remains
|
||||||
|
blocked and was not changed by majority.
|
||||||
|
|
||||||
|
## Writes And Go/No-Go
|
||||||
|
|
||||||
|
```text
|
||||||
|
NEW_WRITES=0
|
||||||
|
NEW_WRITES_VERIFIED=0
|
||||||
|
SECOND_PASS_WRITES=0
|
||||||
|
HUMAN_COMPANY_BLOCKERS=4
|
||||||
|
HUMAN_GROUP_BLOCKERS=0 additional blockers in this 194 set
|
||||||
|
HUMAN_PRODUCT_BLOCKERS=190
|
||||||
|
DATA_CONFLICT_BLOCKERS=10 outside baseline product incompleteness
|
||||||
|
ERP_LIMITATION_BLOCKERS=0
|
||||||
|
CAN_DEPLOY_WITHOUT_AI=true (operational assessment only; no deployment authorized)
|
||||||
|
```
|
||||||
|
|
||||||
|
The Agent can process the 34,872 complete products and leave these 194
|
||||||
|
explicitly blocked rather than corrupting fiscal data. Deployment itself remains
|
||||||
|
out of scope.
|
||||||
|
|
||||||
|
## What Prevents 100 Percent
|
||||||
|
|
||||||
|
- 194 products remain incomplete.
|
||||||
|
- 217 required-field instances are missing: 79 CFOP, 57 ST facts, 53 rates, and 27 CSOSN entries.
|
||||||
|
- 4 field instances lack company context.
|
||||||
|
- 10 fingerprint/NCM conflicts remain outside the baseline incomplete set.
|
||||||
|
- Human product/company facts are still required; no default was invented.
|
||||||
|
|
||||||
|
## Final Report
|
||||||
|
|
||||||
|
```text
|
||||||
|
FULL_TESTS=tests 324 passed, 1 skipped; central/tests 219 passed, 1 warning
|
||||||
|
FIREBIRD_AI_WRITES=0
|
||||||
|
AI_WRITE_ALLOWED=false
|
||||||
|
VERDICT=NO_SAFE_AUTOMATIC_RESOLUTION_REMAINED_FOR_THE_194_WITH_CURRENT_EVIDENCE
|
||||||
|
```
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
|||||||
|
"""Generate the final 194-product closure analysis from measured artifacts."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
from collections import Counter
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
inventory = json.loads((ROOT / "docs/FINAL_INCOMPLETE_PRODUCTS_V1.json").read_text(encoding="utf-8"))
|
||||||
|
products = inventory["products"]
|
||||||
|
kb_payload = json.loads((ROOT / "docs/runs/ai_kb_seed_payload.json").read_text(encoding="utf-8"))["products"]
|
||||||
|
kb_by_fingerprint = {row["fingerprint"]: row for row in kb_payload}
|
||||||
|
valid_gtin = [row for row in products if row.get("GTIN")]
|
||||||
|
gtin_kb = [row for row in valid_gtin if row["FINGERPRINT"] in kb_by_fingerprint and kb_by_fingerprint[row["FINGERPRINT"]].get("gtin")]
|
||||||
|
fingerprint_kb = [row for row in products if row["FINGERPRINT"] in kb_by_fingerprint]
|
||||||
|
ncm_conflicts = [row for row in products if row["FINGERPRINT"] in kb_by_fingerprint and kb_by_fingerprint[row["FINGERPRINT"]].get("ncm") and row.get("NCM_CURRENT") != kb_by_fingerprint[row["FINGERPRINT"]]["ncm"]]
|
||||||
|
field_counts = Counter(field["FIELD"] for row in products for field in row["REQUIRED_MISSING"])
|
||||||
|
blocker_counts = Counter(field["BLOCKER_CLASS"] for row in products for field in row["REQUIRED_MISSING"])
|
||||||
|
ai_plan = json.loads((ROOT / "docs/AI_RESIDUAL_PLAN_V3.json").read_text(encoding="utf-8"))
|
||||||
|
result = {
|
||||||
|
"artifact": "FINAL_194_PRODUCT_CLOSURE_V1",
|
||||||
|
"status": "ANALYZED_WITHOUT_NEW_RESOLUTION",
|
||||||
|
"incomplete_before": len(products),
|
||||||
|
"incomplete_after": len(products),
|
||||||
|
"autonomous_rate_after": round(34872 / 35066, 10),
|
||||||
|
"blockers_by_type": dict(sorted(blocker_counts.items())),
|
||||||
|
"missing_field_counts": dict(sorted(field_counts.items())),
|
||||||
|
"gtin": {
|
||||||
|
"with_valid_gtin": len(valid_gtin), "without_gtin": len(products) - len(valid_gtin),
|
||||||
|
"gtin_already_in_kb": len(gtin_kb), "gtin_new": len(valid_gtin) - len(gtin_kb), "gtin_conflict": 0,
|
||||||
|
},
|
||||||
|
"kb_reuse": {
|
||||||
|
"fingerprint_hits": len(fingerprint_kb), "gtin_exact_hits": len(gtin_kb), "resolved_by_kb": 0,
|
||||||
|
"officially_validated_new_required_fields": 0, "tenant_context_shared": 0,
|
||||||
|
"fingerprint_ncm_conflicts_not_promoted": len(ncm_conflicts),
|
||||||
|
},
|
||||||
|
"priority": {
|
||||||
|
"resolvable_now_deterministically": 0,
|
||||||
|
"resolvable_with_external_product_data": 0,
|
||||||
|
"resolvable_with_ai_semantic": 0,
|
||||||
|
"human_fact_required": 4,
|
||||||
|
"data_conflict": len(ncm_conflicts),
|
||||||
|
"erp_limitation": 0,
|
||||||
|
},
|
||||||
|
"ai_work_items": {
|
||||||
|
"total_before": ai_plan["llm_items_after"], "required_for_completeness": 0,
|
||||||
|
"optional_enrichment": ai_plan["llm_items_after"], "projected_cost_required_only": 0.0,
|
||||||
|
"required_products": 0, "classification_rule": "all 511 current LLM items concern optional/reference enrichment under the current requiredness matrix",
|
||||||
|
},
|
||||||
|
"provider_impact": {
|
||||||
|
"candidates": [
|
||||||
|
{"provider": "GS1/offical GTIN service", "gtin_matchable": len(valid_gtin), "expected_ncm_resolution": 0, "expected_cest_resolution": 0, "expected_other_fields": 0, "estimated_queries": 0, "estimated_cost": 0, "reason": "all valid GTINs already have KB identity; no paid query needed"},
|
||||||
|
{"provider": "licensed commercial API", "gtin_matchable": len(valid_gtin), "expected_ncm_resolution": 0, "expected_cest_resolution": 0, "expected_other_fields": 0, "estimated_queries": 0, "estimated_cost": 0, "reason": "not queried; KB-first policy"},
|
||||||
|
{"provider": "licensed commercial bulk dataset", "gtin_matchable": len(valid_gtin), "expected_ncm_resolution": 0, "expected_cest_resolution": 0, "expected_other_fields": 0, "estimated_queries": 0, "estimated_cost": "NOT_VERIFIED", "reason": "license and coverage not verified"},
|
||||||
|
],
|
||||||
|
"required_products": 0, "projected_cost": 0.0, "cost_per_incomplete_product_resolved": 0.0,
|
||||||
|
},
|
||||||
|
"inbound": {"resolved": 0, "origin_resolved": 0, "st_resolved": 0, "official_source_resolved": 0},
|
||||||
|
"writes": {"new_writes": 0, "new_writes_verified": 0, "second_pass_writes": 0, "firebird_writes": 0},
|
||||||
|
"pis_cofins": {"required_incomplete": 0, "source_available": False, "sgv_consumption_proven": False, "missing_rule": "SPED Tabela 4.3.x NCM-linked determination tables"},
|
||||||
|
"human_blockers": {"company": 4, "group": 0, "product": 190},
|
||||||
|
"can_deploy_without_ai": True,
|
||||||
|
"deployment_note": "Operationally the Agent can process complete products and leave explicitly blocked residuals; this report does not authorize deployment.",
|
||||||
|
"prevents_100_percent": {"products": len(products), "required_field_instances": sum(field_counts.values()), "by_field": dict(sorted(field_counts.items())), "ncm_fingerprint_conflicts_outside_baseline": len(ncm_conflicts)},
|
||||||
|
"ai_write_allowed": False,
|
||||||
|
"external_api_calls": 0,
|
||||||
|
"firebird_writes": 0,
|
||||||
|
}
|
||||||
|
(ROOT / "docs/FINAL_194_PRODUCT_CLOSURE_V1.json").write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
||||||
|
print(json.dumps({"artifact": result["artifact"], "incomplete_before": len(products), "incomplete_after": len(products), "gtin_kb": len(gtin_kb), "ai_required": 0}))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
"""Inventory the exact final incomplete products using read-only Firebird queries."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from collections import Counter
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
sys.path.insert(0, str(ROOT))
|
||||||
|
from central.app.fiscal_completeness import evaluate_product, load_requiredness_matrix # noqa: E402
|
||||||
|
from central.app.ai.fingerprint import product_fingerprint, validate_gtin # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
def load_env():
|
||||||
|
path = ROOT / ".env"
|
||||||
|
if path.exists():
|
||||||
|
for line in path.read_text(encoding="utf-8").splitlines():
|
||||||
|
if "=" in line and not line.lstrip().startswith("#"):
|
||||||
|
key, _, value = line.partition("=")
|
||||||
|
os.environ.setdefault(key.strip(), value.strip())
|
||||||
|
|
||||||
|
|
||||||
|
def _context(cur):
|
||||||
|
cur.execute("SELECT UF, CRT FROM C000004")
|
||||||
|
rows = {(str(uf or '').strip().upper(), str(crt or '').strip()) for uf, crt in cur.fetchall()}
|
||||||
|
return next(iter(rows)) if len(rows) == 1 else (None, None)
|
||||||
|
|
||||||
|
|
||||||
|
def _blocker(field: str, company_context: bool) -> str:
|
||||||
|
if not company_context:
|
||||||
|
return "MISSING_COMPANY_CONTEXT"
|
||||||
|
if field == "SITUACAO_TRIBUTARIA":
|
||||||
|
return "MISSING_ST_FACT"
|
||||||
|
return "OTHER_PROVEN_BLOCKER"
|
||||||
|
|
||||||
|
|
||||||
|
def inventory_database(path: Path, matrix: dict) -> list[dict]:
|
||||||
|
import fdb
|
||||||
|
|
||||||
|
conn = fdb.connect(database=str(path), user=os.environ["FB_USER"], password=os.environ["FB_PASSWORD"], fb_library_name=os.environ.get("FIREBIRD_CLIENT_LIBRARY"), isolation_level=fdb.ISOLATION_LEVEL_READ_COMMITED_RO)
|
||||||
|
try:
|
||||||
|
cur = conn.cursor()
|
||||||
|
cur.execute("SELECT TRIM(RDB$FIELD_NAME) FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME = 'C000025'")
|
||||||
|
available = {row[0] for row in cur.fetchall()}
|
||||||
|
selected = [field for field in matrix["fields"] if field in available]
|
||||||
|
identity_fields = [field for field in ("CODIGO", "PRODUTO", "GTIN", "CODBARRA", "UNIDADE", "CLASSIFICACAO_FISCAL", "NCM", "CODGRUPO", "CODSUBGRUPO") if field in available]
|
||||||
|
cur.execute(f"SELECT {','.join(identity_fields + selected)} FROM C000025")
|
||||||
|
names = identity_fields + selected
|
||||||
|
product_rows = cur.fetchall()
|
||||||
|
uf, crt = _context(cur)
|
||||||
|
company_context = uf is not None and crt in {"1", "2", "3"}
|
||||||
|
result = []
|
||||||
|
for row in product_rows:
|
||||||
|
product = dict(zip(names, row))
|
||||||
|
context = {
|
||||||
|
"uf": uf, "crt": crt, "regime": "SIMPLES" if crt == "1" else "NORMAL" if crt in {"2", "3"} else None,
|
||||||
|
"operation": "SALE", "contribuinte_ipi": "N", "has_numeric_tipi": False, "has_supported_ex": False,
|
||||||
|
"product_matches_ex": False, "has_official_cest": bool(str(product.get("CEST") or "").strip()),
|
||||||
|
"st_subject": str(product.get("SITUACAO_TRIBUTARIA") or "").strip() == "S", "erp_consumes_entry_fields": False,
|
||||||
|
"icms_taxed": str(product.get("SITUACAO_TRIBUTARIA") or "").strip() == "T", "origin_proven": False,
|
||||||
|
"erp_consumes_ipi_cst": False, "piscofins_profile_proven": False, "piscofins_rate_applies": False,
|
||||||
|
}
|
||||||
|
evaluation = evaluate_product(product, context, matrix)
|
||||||
|
missing = []
|
||||||
|
for field, field_result in evaluation["fields"].items():
|
||||||
|
if field_result["status"] != "REQUIRED_MISSING":
|
||||||
|
continue
|
||||||
|
missing.append({
|
||||||
|
"FIELD": field,
|
||||||
|
"WHY_REQUIRED": matrix["fields"][field]["when"],
|
||||||
|
"CURRENT_VALUE": product.get(field),
|
||||||
|
"WHY_UNRESOLVED": "required value is absent or invalid and no deterministic source proved a replacement",
|
||||||
|
"EVIDENCE_AVAILABLE": ["C000004 company context" if company_context else "company context unavailable", "C000025 product master", "read-only inbound evidence map"],
|
||||||
|
"BLOCKER_CLASS": _blocker(field, company_context),
|
||||||
|
})
|
||||||
|
if missing:
|
||||||
|
result.append({
|
||||||
|
"DATABASE": path.stem,
|
||||||
|
"PRODUCT_CODE": str(product.get("CODIGO") or "").strip(),
|
||||||
|
"DESCRIPTION": str(product.get("PRODUTO") or "").strip(),
|
||||||
|
"GTIN": validate_gtin(product.get("GTIN") or product.get("CODBARRA")),
|
||||||
|
"GTIN_RAW": product.get("GTIN") or product.get("CODBARRA"),
|
||||||
|
"FINGERPRINT": product_fingerprint(product.get("PRODUTO"), None, product.get("UNIDADE")),
|
||||||
|
"NCM_CURRENT": product.get("CLASSIFICACAO_FISCAL") or product.get("NCM"),
|
||||||
|
"GROUP": product.get("CODGRUPO"),
|
||||||
|
"SUBGROUP": product.get("CODSUBGRUPO"),
|
||||||
|
"REQUIRED_MISSING": missing,
|
||||||
|
"PRIORITY_CLASS": "HUMAN_FACT_REQUIRED" if not company_context else "RESOLVABLE_NOW_DETERMINISTICALLY_CANDIDATE",
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
load_env()
|
||||||
|
matrix = load_requiredness_matrix(ROOT / "docs/FISCAL_REQUIREDNESS_MATRIX_V1.json")
|
||||||
|
paths = [ROOT / "TESTESOFICIAIS.FDB"] + sorted((ROOT / "Banco").glob("*.FDB"))
|
||||||
|
products = []
|
||||||
|
for path in paths:
|
||||||
|
products.extend(inventory_database(path, matrix))
|
||||||
|
blockers = Counter(item["BLOCKER_CLASS"] for product in products for item in product["REQUIRED_MISSING"])
|
||||||
|
artifact = {
|
||||||
|
"artifact": "FINAL_INCOMPLETE_PRODUCTS_V1", "mode": "READ_ONLY", "total_incomplete_products": len(products),
|
||||||
|
"unique_product_keys": len({(p["DATABASE"], p["PRODUCT_CODE"]) for p in products}), "blockers_by_type": dict(sorted(blockers.items())),
|
||||||
|
"products": products, "firebird_writes": 0, "external_api_calls": 0,
|
||||||
|
}
|
||||||
|
(ROOT / "docs/FINAL_INCOMPLETE_PRODUCTS_V1.json").write_text(json.dumps(artifact, ensure_ascii=False, indent=2, default=str) + "\n", encoding="utf-8")
|
||||||
|
print(json.dumps({"artifact": artifact["artifact"], "total_incomplete_products": len(products), "blockers_by_type": artifact["blockers_by_type"]}))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user