feat: plantilla base workspace SaaS
Some checks failed
Build Producción & Push a Harbor / test (push) Failing after 3s
Build Producción & Push a Harbor / build (push) Has been skipped
Aduanasoft/plantillas-proyectos/pipeline/head There was a failure building this commit

This commit is contained in:
2026-07-21 13:59:00 -05:00
commit bdd089954b
470 changed files with 70022 additions and 0 deletions

View File

@@ -0,0 +1,358 @@
#!/usr/bin/env python3
"""Fusiona bloques csv_upload en messages/en.json y messages/es.json y vuelca a src/lib/i18n/csv-upload-messages.*.json.
La fuente de verdad del copy CSV es `messages/{en,es}.json` (alineado con sidebar, dashboard, facturas).
Si editas solo esos JSON, sincroniza con:
node -e "const fs=require('fs'),p=require('path'),r='.../frontend';for(const l of['en','es']){const j=JSON.parse(fs.readFileSync(p.join(r,'messages',l+'.json'),'utf8'));fs.writeFileSync(p.join(r,'src/lib/i18n','csv-upload-messages.'+l+'.json'),JSON.stringify(j.csv_upload,null,'\\t')+'\\n')}"
Ejecutar desde frontend/: python scripts/merge_csv_upload_i18n.py
"""
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
MESSAGES = ROOT / "messages"
EN_CSV = {
"page_title": "CSV import",
"intro_help": "Left-click: upload CSV file. Right-click: download template.",
"tab_catalogos": "Catalogs",
"tab_transportes": "Transportation",
"tab_importacion": "Import",
"tab_exportacion": "Export",
"section_catalogs": "General Catalogs",
"section_transport": "Transportation",
"section_import": "Import operations",
"section_export": "Export operations",
"params_header": "Global parameters",
"config_prefix": "Settings",
"soon": "Coming soon",
"drop_here": "Drop the file!",
"groups": {
"permisos": "Permissions",
"impo_temp": "Temporary import",
"impo_def": "Definitive import",
"cmex": "Mexican purchases",
"expo_def": "Definitive export / regime change",
"expo_rep": "Export replenishment",
"manifest": "Manifest",
},
"items": {
"customs_brokers": "Customs Brokers",
"clients_providers": "Clients and Providers",
"exchange_rates": "Exchange Rates",
"material_classes": "Classes",
"part_numbers": "Parts",
"boms": "BOMs",
"items": "Lines (permissions)",
"headers": "Headers (permissions)",
"historical_fractions": "Historical tariff fractions",
"pedimentos": "Pedimentos",
"transporters": "Carriers",
"transports": "Vehicles",
"drivers": "Drivers",
"trailers": "Trailers",
"imp_temp_header": "Header",
"imp_temp_details": "Lines",
"imp_temp_series": "Serial numbers",
"imp_def_header": "Header",
"imp_def_details": "Lines",
"imp_def_series": "Serial numbers",
"comp_mex_header": "Header",
"comp_mex_details": "Lines",
"comp_mex_series": "Serial numbers",
"exp_def_header": "Header",
"exp_def_details": "Lines",
"exp_def_series": "Serial numbers",
"exp_def_nodes": "NODES",
"exp_rep_header": "Header",
"exp_rep_details": "Lines",
"exp_rep_series": "Serial numbers",
"manifest_header": "Header",
},
"params": {
"load_mode": "Load mode",
"date_format": "Date format",
"weight_unit": "Weight unit",
"autonumber_series": "Autonumber lines/series",
"load_subpartidas": "Load sub-lines",
"recalculate_pedimento_date": "Recalculate pedimento date",
"autonumber_remesas": "Autonumber consignments",
"recalculate_dates": "Recalculate dates",
"invoice_type": "Invoice type",
"is_regime_change": "Regime change",
},
"options": {
"update": "Update",
"replace": "Replace",
"yes": "Yes",
"no": "No",
"kgs": "Kilograms (kg)",
"lbs": "Pounds (lb)",
"date_dd_mm": "DD/MM/YYYY",
"date_mm_dd": "MM/DD/YYYY",
"date_iso": "YYYY-MM-DD",
"afi": "AFIJO",
"normal": "NORMAL",
},
"progress": {
"upload": "Uploading CSV file",
"scan": "Validating records on the server",
"commit": "Saving records to the database",
"upload_known": "Uploading file…",
"upload_unknown": "Uploading file (unknown size in browser)…",
"in_progress": "In progress…",
"resume_hint": "Resuming import saved in this tab…",
"rows_file": "File: ~{n} data row(s) — uploading (not yet validated on server)…",
"rows_scan": "Records processed: {current} / {total}",
"rows_commit": "Records saved: {current} / {total}",
"rows_commit_fallback": "Saving to database… ({current} / {total} using last known total)",
},
"toast": {
"invalid_csv": "Invalid format. Only .csv files are allowed.",
"download_loading": "Downloading template…",
"download_ok": "Template downloaded.",
"download_err": "Could not download the template.",
"upload_err": "Could not upload the file.",
"upload_err_generic": "Unexpected error uploading the file.",
"scan_done": "Scan complete. Review the results.",
"import_done": "Import completed. Review the record list.",
"import_maybe_done": "Import may have completed. Review the record list.",
"stale_job": "This import is no longer available (session expired or job removed). You can start a new upload.",
"poll_err": "Could not fetch status",
"commit_err": "Could not start import",
"scan_alt": "Scan finished. If you do not see the modal, check the record list.",
"finished_none": "No records inserted. Review the errors below.",
"commit_warning_ok": "{inserted} inserted, {updated} updated. {skipped} rejected.",
"commit_warning_none": "No records inserted or updated. {skipped} rejected.",
"success_counts": "Import completed: {msg}",
"warn_skipped": "{n} records rejected or skipped",
"error_processing": "Processing error: {msg}",
},
"pending": {
"badge": "Pending",
"title": "Imports pending confirmation",
"description": "Scans ready to save to the database. Expired jobs disappear when you refresh.",
"refresh": "Refresh",
"empty": "No pending imports for this company.",
"checking": "Checking with the server…",
"total_rows": "Total rows",
"valid_rows": "Valid",
"resume": "Resume",
"remove": "Remove",
"profiles": {
"customs_brokers": "Customs Brokers",
"clients_providers": "Clients and Providers",
"exchange_rates": "Exchange Rates",
"pedimentos": "Pedimentos",
"material_classes": "Classes",
"vehicles": "Vehicles",
"drivers": "Drivers",
"trailers": "Trailers",
"transporters": "Carriers",
"part_numbers": "Parts",
"boms": "BOMs",
"exportacion": "Export operations",
"imports": "Import operations",
},
},
"modal": {
"title_pending": "Import validation",
"title_success": "Import successful",
"title_warning": "Import with remarks",
"desc_pending": "Review the preliminary analysis before confirming.",
"desc_done": "The import process has finished.",
"total_rows": "Total rows",
"valid_rows": "Valid",
"invalid_rows": "Invalid",
},
}
ES_CSV = {
"page_title": "Importación CSV",
"intro_help": "Clic izquierdo: cargar archivo CSV. Clic derecho: descargar plantilla.",
"tab_catalogos": "Catálogos",
"tab_transportes": "Transportes",
"tab_importacion": "Importación",
"tab_exportacion": "Exportación",
"section_catalogs": "Catalogos Generales",
"section_transport": "Transportes",
"section_import": "Operaciones de importación",
"section_export": "Operaciones de exportación",
"params_header": "Parámetros globales",
"config_prefix": "Configuración",
"soon": "Próximamente",
"drop_here": "¡Suelta el archivo!",
"groups": {
"permisos": "Permisos",
"impo_temp": "Impo. temp.",
"impo_def": "Impo. def.",
"cmex": "Compras mex.",
"expo_def": "Expo. def./Cam. reg.",
"expo_rep": "Expo. rep.",
"manifest": "Manifiesto",
},
"items": {
"customs_brokers": "Agentes Aduanales",
"clients_providers": "Clientes y Proveedores",
"exchange_rates": "Tipos de cambio",
"material_classes": "Clases",
"part_numbers": "Partes",
"boms": "BOMs",
"items": "Partidas (permisos)",
"headers": "Encabezados (permisos)",
"historical_fractions": "Fracciones históricas",
"pedimentos": "Pedimentos",
"transporters": "Transportistas",
"transports": "Vehículos",
"drivers": "Conductores",
"trailers": "Trailers",
"imp_temp_header": "Encabezado",
"imp_temp_details": "Partidas",
"imp_temp_series": "Series",
"imp_def_header": "Encabezado",
"imp_def_details": "Partidas",
"imp_def_series": "Series",
"comp_mex_header": "Encabezado",
"comp_mex_details": "Partidas",
"comp_mex_series": "Series",
"exp_def_header": "Encabezado",
"exp_def_details": "Partidas",
"exp_def_series": "Series",
"exp_def_nodes": "NODES",
"exp_rep_header": "Encabezado",
"exp_rep_details": "Partidas",
"exp_rep_series": "Series",
"manifest_header": "Encabezado",
},
"params": {
"load_mode": "Modo de carga",
"date_format": "Formato de fecha",
"weight_unit": "Unidad de peso",
"autonumber_series": "Autonumerar partidas/series",
"load_subpartidas": "Levantar subpartidas",
"recalculate_pedimento_date": "Recalcular fecha pedimento",
"autonumber_remesas": "Autonumerar remesas",
"recalculate_dates": "Recalcular fechas",
"invoice_type": "Tipo de factura",
"is_regime_change": "Es cambio de régimen",
},
"options": {
"update": "Actualizar",
"replace": "Reemplazar",
"yes": "",
"no": "No",
"kgs": "Kilos (kg)",
"lbs": "Libras (lb)",
"date_dd_mm": "DD/MM/YYYY",
"date_mm_dd": "MM/DD/YYYY",
"date_iso": "YYYY-MM-DD",
"afi": "AFIJO",
"normal": "NORMAL",
},
"progress": {
"upload": "Subiendo archivo CSV",
"scan": "Validando registros en el servidor",
"commit": "Grabando registros en base de datos",
"upload_known": "Subiendo archivo…",
"upload_unknown": "Subiendo archivo (tamaño desconocido en el navegador)…",
"in_progress": "En proceso…",
"resume_hint": "Reanudando la importación guardada en esta pestaña…",
"rows_file": "Archivo: ~{n} fila(s) de datos — subiendo (aún no se validan registros en servidor)…",
"rows_scan": "Registros procesados: {current} / {total}",
"rows_commit": "Registros grabados: {current} / {total}",
"rows_commit_fallback": "Grabando en base de datos… ({current} / {total} según último total conocido)",
},
"toast": {
"invalid_csv": "Formato inválido. Solo se permiten archivos .csv",
"download_loading": "Descargando plantilla…",
"download_ok": "Plantilla descargada.",
"download_err": "Error al descargar la plantilla",
"upload_err": "Error al subir el archivo",
"upload_err_generic": "Error inesperado al subir el archivo",
"scan_done": "Escaneo completado. Revisa los resultados.",
"import_done": "Importación completada. Revisa el listado de registros.",
"import_maybe_done": "La importación pudo completarse. Revisa el listado de registros.",
"stale_job": "Esta importación ya no está disponible (sesión expirada o trabajo eliminado). Puedes iniciar una nueva carga.",
"poll_err": "Error al consultar el estado",
"commit_err": "Error al iniciar la importación",
"scan_alt": "El escaneo terminó. Si no ves el modal, revisa el listado de registros.",
"finished_none": "No se insertaron registros. Revisa los errores a continuación.",
"commit_warning_ok": "{inserted} insertados, {updated} actualizados. {skipped} rechazados.",
"commit_warning_none": "No se insertaron ni actualizaron registros. {skipped} rechazados.",
"success_counts": "Importación completada: {msg}",
"warn_skipped": "{n} registros fueron rechazados u omitidos",
"error_processing": "Error en el procesamiento: {msg}",
},
"pending": {
"badge": "Pendientes",
"title": "Importaciones pendientes de confirmar",
"description": "Escaneos listos para insertar en base de datos. Si el trabajo ya expiró en el servidor, desaparecerán al actualizar.",
"refresh": "Actualizar",
"empty": "No hay importaciones pendientes para esta empresa.",
"checking": "Comprobando con el servidor…",
"total_rows": "Total filas",
"valid_rows": "Válidas",
"resume": "Reanudar",
"remove": "Quitar",
"profiles": {
"customs_brokers": "Agentes Aduanales",
"clients_providers": "Clientes y Proveedores",
"exchange_rates": "Tipos de cambio",
"pedimentos": "Pedimentos",
"material_classes": "Clases",
"vehicles": "Vehículos",
"drivers": "Conductores",
"trailers": "Trailers",
"transporters": "Transportistas",
"part_numbers": "Partes",
"boms": "BOMs",
"exportacion": "Exportación (operaciones)",
"imports": "Importación (operaciones)",
},
},
"modal": {
"title_pending": "Validación de importación",
"title_success": "Importación exitosa",
"title_warning": "Importación con observaciones",
"desc_pending": "Revise el análisis preliminar antes de confirmar la carga de datos.",
"desc_done": "El proceso de importación ha finalizado.",
"total_rows": "Total filas",
"valid_rows": "Válidos",
"invalid_rows": "Inválidos",
},
}
def merge_locale(filename: str, csv_obj: dict) -> None:
path = MESSAGES / filename
data = json.loads(path.read_text(encoding="utf-8"))
data["csv_upload"] = csv_obj
path.write_text(json.dumps(data, ensure_ascii=False, indent="\t") + "\n", encoding="utf-8")
def extract_csv_upload_to_lib() -> None:
"""Copia `csv_upload` a src/lib/i18n/csv-upload-messages.*.json (lo que importa csv-msg.ts)."""
dest_dir = ROOT / "src/lib/i18n"
for filename, suffix in (("en.json", "en"), ("es.json", "es")):
path = MESSAGES / filename
data = json.loads(path.read_text(encoding="utf-8"))
cu = data.get("csv_upload")
if cu is None:
raise SystemExit(f"merge_csv_upload_i18n: falta csv_upload en {filename}")
out = dest_dir / f"csv-upload-messages.{suffix}.json"
out.write_text(json.dumps(cu, ensure_ascii=False, indent="\t") + "\n", encoding="utf-8")
print(f"Wrote {out.relative_to(ROOT)}")
def main() -> None:
merge_locale("en.json", EN_CSV)
merge_locale("es.json", ES_CSV)
print("Merged csv_upload into en.json and es.json")
extract_csv_upload_to_lib()
if __name__ == "__main__":
main()