diff --git a/Tool/pages.py b/Tool/pages.py index be930a6..c5e72ef 100644 --- a/Tool/pages.py +++ b/Tool/pages.py @@ -6,8 +6,9 @@ from .queries import pec as q_pec from .queries import logs as q_logs from .queries import report as q_report from .queries import documenti as q_documenti -from .queries import iscrizioni as q_iscrizioni -from .queries import email as q_email +from .queries import iscrizioni as q_iscrizioni +from .queries import api_iscrizioni as q_api_iscrizioni +from .queries import email as q_email def _load_data(db_path: str) -> dict: @@ -58,7 +59,7 @@ def _page_dashboard(db_path: str) -> str: ) section_middle = ( '
' - '

📋 Corsi Intraziendali

' + '

📋 RPA Steps

' f'
{cards_middle}
' '
' '
' @@ -175,7 +176,15 @@ def _page_iscrizioni(db_path: str) -> str: content = _tmpl('iscrizioni.html').substitute( tbl_iscrizioni=q_iscrizioni.render_table(rows), ) - return _base('Corsi Intraziendali', content, 'nav_iscrizioni', db_path, _page_css('iscrizioni'), _page_js('iscrizioni')) + return _base('RPA Steps', content, 'nav_iscrizioni', db_path, _page_css('iscrizioni'), _page_js('iscrizioni')) + + +def _page_api_iscrizioni(db_path: str) -> str: + rows = q_api_iscrizioni.get_iscrizioni(db_path) + content = _tmpl('api_iscrizioni.html').substitute( + tbl_api_iscrizioni=q_api_iscrizioni.render_table(rows), + ) + return _base('Iscrizioni', content, 'nav_api_iscrizioni', db_path, _page_css('api_iscrizioni'), _page_js('api_iscrizioni')) def _page_email(db_path: str) -> str: diff --git a/Tool/queries/api_iscrizioni.py b/Tool/queries/api_iscrizioni.py new file mode 100644 index 0000000..d48a95f --- /dev/null +++ b/Tool/queries/api_iscrizioni.py @@ -0,0 +1,88 @@ +"""queries/api_iscrizioni.py — rpa_intra_api_iscrizione (Intraz)""" + +from .db import query, count, e, dt, badge + + +def get_iscrizioni(db_path: str) -> list: + return query(db_path, """ + SELECT + i.id, + i.rpa_process_id, + m.ragione_sociale AS sorgente, + i.sessione_id, + i.iscritto_nome, + i.iscritto_cognome, + i.iscritto_azienda, + i.iscritto_cf, + i.odv_numero, + i.stato_iscrizione, + i.stato_odv, + i.persona_inserita_only1, + i.note, + i.created_at, + i.updated_at + FROM rpa_intra_api_iscrizione i + LEFT JOIN rpa_mapping_aziende m ON m.id = i.azienda_sorgente_id + ORDER BY i.id DESC + LIMIT 500 + """) + + +def get_stats(db_path: str) -> dict: + return { + 'api_isc_total': count(db_path, "SELECT COUNT(*) AS n FROM rpa_intra_api_iscrizione"), + 'api_isc_ok': count(db_path, "SELECT COUNT(*) AS n FROM rpa_intra_api_iscrizione WHERE stato_iscrizione='ok' AND stato_odv='ok'"), + 'api_isc_errore': count(db_path, "SELECT COUNT(*) AS n FROM rpa_intra_api_iscrizione WHERE stato_iscrizione='errore' OR stato_odv='errore'"), + 'api_isc_pending': count(db_path, "SELECT COUNT(*) AS n FROM rpa_intra_api_iscrizione WHERE stato_iscrizione='pending' OR stato_odv='pending'"), + } + + +def _stato_row(r: dict) -> str: + si, so = r.get('stato_iscrizione'), r.get('stato_odv') + if si == 'errore' or so == 'errore': + return 'errore' + if si == 'ok' and so == 'ok': + return 'ok' + return 'pending' + + +def _badge_stato(v: str) -> str: + if v == 'ok': return badge('ok', 'ok') + if v == 'errore': return badge('err', 'errore') + return badge('warn', 'pending') + + +def render_table(rows: list) -> str: + if not rows: + return '

Nessuna iscrizione trovata.

' + + trs = ''.join( + f'' + f'{e(r.get("id"))}' + f'{e(r.get("rpa_process_id"))}' + f'{e(r.get("sorgente"))}' + f'{e(r.get("sessione_id"))}' + f'{e(r.get("iscritto_cognome"))} {e(r.get("iscritto_nome"))}' + f'{e(r.get("iscritto_azienda"))}' + f'{e(r.get("iscritto_cf"))}' + f'{e(r.get("odv_numero"))}' + f'{"✓" if r.get("persona_inserita_only1") else ""}' + f'{_badge_stato(r.get("stato_iscrizione"))}' + f'{_badge_stato(r.get("stato_odv"))}' + f'{e(r.get("note"))}' + f'{dt(r.get("updated_at"))}' + f'' + for r in rows + ) + return ( + '' + '' + '' + '' + f'{trs}
#RunSorgenteSessioneIscrittoAziendaCFODV N.NuovaIscrizioneODVNoteAggiornato
' + ) diff --git a/Tool/renderer.py b/Tool/renderer.py index cbc42ef..e2a9579 100644 --- a/Tool/renderer.py +++ b/Tool/renderer.py @@ -55,10 +55,11 @@ def _base(title: str, content: str, active: str, db_path: str, page_css: str = ' if db_type == DbType.INTRAZ: cls = 'active' if active == 'nav_iscrizioni' else '' - nav_step_link = f'Corsi Intraziendali' + nav_step_link = f'RPA Steps' + cls_api_isc = 'active' if active == 'nav_api_iscrizioni' else '' + nav_report_link = f'Iscrizioni' cls_email = 'active' if active == 'nav_email' else '' nav_pec_link = f'Email' - nav_report_link = '' else: cls = 'active' if active == 'nav_documenti' else '' nav_step_link = f'Documenti' diff --git a/Tool/server.py b/Tool/server.py index 8ff4332..ab7b9b0 100644 --- a/Tool/server.py +++ b/Tool/server.py @@ -8,7 +8,7 @@ from .config import _state, _access_log, DbType from .db_finder import _find_db, _pick_db_file from .pages import ( _page_dashboard, _page_runs, _page_pec, _page_logs, - _page_report, _page_documenti, _page_iscrizioni, _page_email, _page_server_logs, + _page_report, _page_documenti, _page_iscrizioni, _page_api_iscrizioni, _page_email, _page_server_logs, ) from .queries.db import e as _e, query as _query, detect_db as _detect_db from .queries import documenti as q_documenti @@ -113,8 +113,9 @@ def make_handler(db_path: str): '/server-logs': lambda: _page_server_logs(db_path), } if db_type == DbType.INTRAZ: - routes['/iscrizioni'] = lambda: _page_iscrizioni(db_path) - routes['/email'] = lambda: _page_email(db_path) + routes['/steps'] = lambda: _page_iscrizioni(db_path) + routes['/iscrizioni-api'] = lambda: _page_api_iscrizioni(db_path) + routes['/email'] = lambda: _page_email(db_path) else: routes['/report'] = lambda: _page_report(db_path) routes['/documenti'] = lambda: _page_documenti(db_path) @@ -143,7 +144,8 @@ def run_server(db_path: str, host: str = 'localhost', port: int = 8080): print(f" Dashboard : http://localhost:{port}/") print(f" Processi : http://localhost:{port}/runs") if db_type == DbType.INTRAZ: - print(f" Iscrizioni : http://localhost:{port}/iscrizioni") + print(f" RPA Steps : http://localhost:{port}/steps") + print(f" Iscr. API : http://localhost:{port}/iscrizioni-api") print(f" Email : http://localhost:{port}/email") else: print(f" PEC : http://localhost:{port}/pec") diff --git a/static/js/api_iscrizioni.js b/static/js/api_iscrizioni.js new file mode 100644 index 0000000..b81153f --- /dev/null +++ b/static/js/api_iscrizioni.js @@ -0,0 +1,16 @@ +(function(){ + function applyFilter() { + var active = {}; + document.querySelectorAll('.api-isc-filter input[type="checkbox"]').forEach(function(chk) { + active[chk.getAttribute('data-filter-stato')] = chk.checked; + }); + document.querySelectorAll('tbody tr[data-stato]').forEach(function(tr) { + var stato = tr.getAttribute('data-stato'); + var show = (stato in active) ? active[stato] : true; + tr.style.display = show ? '' : 'none'; + }); + } + document.querySelectorAll('.api-isc-filter input[type="checkbox"]').forEach(function(chk) { + chk.addEventListener('change', applyFilter); + }); +})(); diff --git a/static/pages/api_iscrizioni.css b/static/pages/api_iscrizioni.css new file mode 100644 index 0000000..387e739 --- /dev/null +++ b/static/pages/api_iscrizioni.css @@ -0,0 +1,36 @@ +/* api_iscrizioni.css */ + +.api-isc-header { + display: flex; + align-items: center; + gap: 1.5rem; + flex-wrap: wrap; + margin-bottom: .5rem; +} +.api-isc-header h2 { margin: 0; } + +.api-isc-filter { + display: flex; + gap: 1rem; + align-items: center; + flex-wrap: wrap; +} +.api-isc-filter .filter-group-label { + font-size: .85rem; + color: #64748b; + font-weight: 600; +} +.api-isc-filter label { + display: flex; + align-items: center; + gap: .35rem; + font-size: .9rem; + cursor: pointer; + user-select: none; +} +.api-isc-filter input[type="checkbox"] { + width: 1rem; + height: 1rem; + cursor: pointer; + accent-color: #2563eb; +} diff --git a/templates/api_iscrizioni.html b/templates/api_iscrizioni.html new file mode 100644 index 0000000..6685d18 --- /dev/null +++ b/templates/api_iscrizioni.html @@ -0,0 +1,24 @@ + +
+
${tbl_api_iscrizioni}
+