"""KB search bug fix: the search must be GLOBAL server-side (filter -> count -> order -> paginate), lenient for humans (distinct from the strict fiscal `kb.alias_match`), and find a product regardless of which page it would fall on. Never touches the fiscal auto-fill rule.""" from sqlalchemy import select from central.app.enrichment import kb from central.app.enrichment.observability import kb_search, kb_search_ids from central.tests.test_control_panel_pages import _panel_client from central.tests.test_product_enrichment_resolver import env # noqa: F401 from central.tests.test_rtc_security import _become, _post def seed_product(session, gtin, aliases, ncm=None, client="A"): p = kb.upsert_product(session, gtin, aliases[0]) for a in aliases[1:]: kb.add_alias(session, p, a) if ncm: kb.add_evidence(session, p, "ncm", ncm, "x", family=kb.CLIENT_FAMILY, client_label=client, lineage={"docs": 20, "years": {"2024": 20}}) session.commit() return p def gtin(body12): total = sum(int(d) * (3 if i % 2 == 0 else 1) for i, d in enumerate(reversed(body12))) return "0" + body12 + str((10 - total % 10) % 10) def test_search_is_global_not_limited_to_a_rendered_page(env): target = seed_product(env, gtin("789100050001"), ["COCA-COLA ORIGINAL LATA 350 ML"], ncm="22021000") for i in range(30): # unrelated noise: if search were page-limited, the target could fall off the visible slice seed_product(env, gtin(f"78920005{i:04d}"), [f"PRODUTO IRRELEVANTE {i} CAIXA 1 UN"]) ids = kb_search_ids(env, "COCA COLA LATA 350") # missing the unit "ML": would fail the strict fiscal alias_match assert target.id in ids def test_search_finds_product_on_first_middle_and_last_page(env): target = seed_product(env, gtin("789100050002"), ["COCA-COLA ORIGINAL LATA 350 ML"]) for i in range(25): seed_product(env, gtin(f"78920006{i:04d}"), [f"COCA-COLA ORIGINAL LATA 350 ML VARIANTE {i}"]) for page in (1, 2, 3): res = kb_search(env, "COCA COLA LATA 350", page=page, page_size=10) assert res["total"] == 26 and res["pages"] == 3 found_on_last_page = kb_search(env, "COCA COLA LATA 350", page=3, page_size=10) assert len(found_on_last_page["results"]) >= 1 def test_search_by_gtin_exact(env): key = gtin("789100050003") seed_product(env, key, ["COCA-COLA ORIGINAL LATA 350 ML"]) body = key[1:] assert kb_search_ids(env, body) and kb_search_ids(env, body)[0] == kb_search_ids(env, key)[0] assert kb_search_ids(env, "0000000000000") == [] def test_search_by_name_with_and_without_hyphen_and_accents(env): p = seed_product(env, gtin("789100050004"), ["ACAI ORIGINAL POLPA 100 G"]) for query in ("ACAI POLPA 100", "AÇAÍ POLPA 100", "acai polpa 100"): assert p.id in kb_search_ids(env, query), query def test_search_zero_results_for_unknown_product(env): seed_product(env, gtin("789100050005"), ["FEIJAO CARIOCA 1 KG"]) assert kb_search_ids(env, "PRODUTO QUE NAO EXISTE NA BASE") == [] def test_search_before_pagination_semantics(env): """Filter runs over the WHOLE table, THEN the result is paginated - not the other way round.""" matches = [seed_product(env, gtin(f"78910006{i:04d}"), [f"SABONETE LIQUIDO ERVA DOCE {i} 200 ML"]) for i in range(15)] for i in range(40): seed_product(env, gtin(f"78910007{i:04d}"), [f"OUTRO PRODUTO {i} QUALQUER"]) res = kb_search(env, "SABONETE LIQUIDO ERVA DOCE", page=2, page_size=10) assert res["total"] == 15 and res["page"] == 2 and len(res["results"]) == 5 found_ids = {r["gtin_key"] for r in kb_search(env, "SABONETE LIQUIDO ERVA DOCE", page=1, page_size=10)["results"]} | {r["gtin_key"] for r in res["results"]} assert found_ids == {p.gtin for p in matches} def test_conflict_candidates_all_visible_and_none_auto_confirmed(env): seed_product(env, gtin("789100050006"), ["COCA COLA LATA 350 ML"], ncm="22030000", client="RINCAO") p2 = seed_product(env, gtin("789100050006"), ["REFRIGERANTE COCA COLA LATA 350 ML"], ncm="22021000", client="UNIAO") # both aliases resolve to the SAME kb product (same GTIN key), so seeding into it twice just adds evidence ids = kb_search_ids(env, "COCA COLA LATA 350") assert p2.id in ids def test_admin_attest_button_authorization_end_to_end(): client, agent_id, _ = _panel_client() with client._session_factory() as s: from central.tests.test_enrichment_history import staging from central.tests.test_enrichment_history import run as seed_history from central.tests.test_product_enrichment_resolver import seed as seed_ncm_dataset seed_ncm_dataset(s) seed_history(s, [staging("RINCAO", "7891000500071", "19059090", years={2024: 900, 2025: 900}, desc="COCA LATA 350 ML"), staging("UNIAO", "7891000500071", "22021000", years={2024: 20, 2025: 13}, desc="REFRIGERANTE COCA COLA LATA 350 ML")]) _become(client, "PADRAO") page = client.get("/?kb_q=COCA COLA LATA 350").text assert "Confirmar este NCM" not in page # button hidden for non-admin _become(client, "ADMIN") page = client.get("/?kb_q=COCA COLA LATA 350").text assert "Confirmar este NCM" in page and "22021000" in page and "19059090" in page