feat: GTI Gerenciador as the single source of truth for clients; bump to 1.1.2
Tenant gains source (LOCAL|GTI_GERENCIADOR), external_client_id, external_code, active and synced_at (migration 0024). central/app/client_sync.py fetches from the panel's new GET /internal/fiscal/clients (dedicated bearer token, never MySQL credentials) and upserts Tenant rows, never touching a LOCAL row. /agents/new now offers only active GTI_GERENCIADOR tenants, with a client-side search box; the POST validates the same rule server-side, not just in the dropdown. central/scripts/sync_clients_from_gerenciador.py is the operator-run sync + reconciliation report. GTI_FISCAL_VERSION/AGENT_VERSION bumped to 1.1.2 (release/VERSION single source of truth), incorporating the installation_id persistence fix. Rebuilt the EXE installer trio at 1.1.2 (scripts/build_windows_installer.ps1). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
"""Administrative CLI: pull the client registry from GTI Gerenciador (the
|
||||
panel) and mirror it into Tenant rows (source='GTI_GERENCIADOR'). GTI
|
||||
Gerenciador is the single source of truth; the Fiscal Hub never gets MySQL
|
||||
credentials — this only calls the panel's read-only internal endpoint.
|
||||
|
||||
Usage (from inside the Hub container, or anywhere DATABASE_URL +
|
||||
GERENCIADOR_INTERNAL_URL + FISCAL_INTERNAL_API_TOKEN are reachable):
|
||||
|
||||
python central/scripts/sync_clients_from_gerenciador.py
|
||||
|
||||
Prints a reconciliation summary; never prints the bearer token.
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT / "central"))
|
||||
|
||||
from sqlalchemy.orm import Session # noqa: E402
|
||||
|
||||
from app import client_sync # noqa: E402
|
||||
from app.db import engine # noqa: E402
|
||||
|
||||
|
||||
def main():
|
||||
clients = client_sync.fetch_from_gerenciador()
|
||||
with Session(engine) as session:
|
||||
result = client_sync.sync_from_gerenciador(session, clients)
|
||||
session.commit()
|
||||
print(f"CLIENT_SYNC=ok fetched={result.fetched} created={result.created} updated={result.updated} unchanged={result.unchanged}")
|
||||
print(f"TOTAL_CLIENTS_GERENCIADOR={result.fetched} ACTIVE_CLIENTS_GERENCIADOR={result.active} INACTIVE_CLIENTS_GERENCIADOR={result.inactive}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except client_sync.ClientSyncUnavailable as error:
|
||||
print(f"CLIENT_SYNC=unavailable reason={error}")
|
||||
raise SystemExit(1)
|
||||
Reference in New Issue
Block a user