Art4Hotel Hub: código + documentación extensiva

ERP a la medida (Python stdlib + SQLite + vanilla JS SPA).
Incluye server.py, index.html, utilidades y documentación:
README, MODELO_DATOS, API, INSTALACION, CONTEXTO, NEGOCIO,
WEB, ONBOARDING, VALOR_SISTEMA, CLAUDE.

Secretos y datos (art4hotel.db, secret.key, ACCESOS.html,
uploads/, backups/) excluidos vía .gitignore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
consultoria-as
2026-06-09 00:10:07 -07:00
commit c2ae140078
16 changed files with 12675 additions and 0 deletions

37
fix_dup.py Normal file
View File

@@ -0,0 +1,37 @@
"""One-time: renumber duplicate orden_ids. Keep oldest row (lowest id) with original,
rename later rows to MAX+1, MAX+2, ... Does NOT touch uploads/ folders — files stay
attached to the original (lowest id) pedido, which is the desired behavior."""
import sqlite3, sys
DB = 'art4hotel.db'
c = sqlite3.connect(DB)
c.row_factory = sqlite3.Row
dups = [r['orden_id'] for r in c.execute(
"SELECT orden_id FROM ordenes WHERE orden_id GLOB 'ORD-2026-[0-9][0-9][0-9]' "
"GROUP BY orden_id HAVING COUNT(*)>1")]
print(f'Duplicados encontrados: {len(dups)}')
max_num = c.execute(
"SELECT MAX(CAST(SUBSTR(orden_id,10,3) AS INTEGER)) FROM ordenes "
"WHERE orden_id GLOB 'ORD-2026-[0-9][0-9][0-9]'").fetchone()[0] or 0
next_num = max_num + 1
renames = []
for oid in dups:
rows = c.execute("SELECT id, cliente, producto FROM ordenes WHERE orden_id=? ORDER BY id", (oid,)).fetchall()
keep = rows[0]
print(f"\n {oid} KEEP id={keep['id']} ({keep['cliente']} - {keep['producto']})")
for r in rows[1:]:
new_oid = f'ORD-2026-{next_num:03d}'
next_num += 1
print(f" id={r['id']} ({r['cliente']} - {r['producto']}) → {new_oid}")
renames.append((new_oid, r['id']))
if '--apply' in sys.argv:
for new_oid, rid in renames:
c.execute("UPDATE ordenes SET orden_id=? WHERE id=?", (new_oid, rid))
c.commit()
print(f'\nAplicado: {len(renames)} renombrados.')
else:
print(f'\n(dry-run — corre con --apply para aplicar {len(renames)} cambios)')