feat: cashier/counter reports, service-order & remission flows, Rached migration utils
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

- Add "Mis cortes de caja" report for cashiers/counters with sales detail.
- Cash register history scoped to own cuts for non-admin roles; new /register/<id>/sales endpoint.
- Remove dashboard from cashier menu; add Reports to cashier/counter.
- Service orders: assign mechanic, budget field, invoice flag, counter/cashier can add items/remissions, convert to remission.
- Remission notes module (UI, CSS, courier, counter remissions).
- Customer hard-delete and vehicle/customer linkage in workshop.
- POS: always show search results, compact payment grid, credit validation, tier pricing (5%/10%), ticket with customer/folio.
- Inventory: CSV template with sku_secondary, alias import.
- Rached migration scripts and DB migrations.
- Version-bump cached JS/CSS query strings.

Excludes local Rached session tokens/captures (rached_*.json / rached_*.txt).
This commit is contained in:
2026-07-02 12:51:56 +00:00
parent 483498cfcc
commit f42910f4f6
71 changed files with 5388 additions and 626 deletions

View File

@@ -15,7 +15,39 @@
<meta name="theme-color" content="#F5A623" />
<link rel="shortcut icon" type="image/png" href="/pos/static/pwa/icon-192.png" />
<link rel="stylesheet" href="/pos/static/css/config.css?v=33"></head>
<link rel="stylesheet" href="/pos/static/css/config.css?v=34">
<style>
.cfg-tabs {
display: flex;
gap: var(--space-2);
padding: var(--space-3) var(--space-4);
border-bottom: 1px solid var(--color-border);
background: var(--color-surface-1);
position: sticky;
top: 0;
z-index: 10;
flex-wrap: wrap;
}
.cfg-tab-btn {
padding: var(--space-2) var(--space-4);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
background: var(--color-surface-2);
color: var(--color-text-secondary);
cursor: pointer;
font-size: var(--text-body-sm);
font-weight: var(--font-weight-medium);
}
.cfg-tab-btn:hover { background: var(--color-surface-3); }
.cfg-tab-btn.active {
background: var(--color-accent);
color: #fff;
border-color: var(--color-accent);
}
.settings-section[data-tab] { display: none !important; }
.settings-section[data-tab].active { display: block !important; }
</style>
</head>
<body>
@@ -138,11 +170,20 @@
<!-- Scrollable Content -->
<div class="content-scroll">
<!-- Config tabs -->
<div class="cfg-tabs" id="configTabs">
<button class="cfg-tab-btn active" data-tab="general" onclick="Config.switchTab('general')">General</button>
<button class="cfg-tab-btn" data-tab="fiscal" onclick="Config.switchTab('fiscal')">Fiscal</button>
<button class="cfg-tab-btn" data-tab="catalog" onclick="Config.switchTab('catalog')">Catálogo</button>
<button class="cfg-tab-btn" data-tab="employees" onclick="Config.switchTab('employees')">Empleados</button>
<button class="cfg-tab-btn cfg-tab-btn--permissions" data-tab="permissions" onclick="Config.switchTab('permissions')" style="display:none;">Permisos</button>
</div>
<!-- ===============================================================
SECTION 1: APARIENCIA / TEMA
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
@@ -205,7 +246,7 @@
<!-- ===============================================================
SECTION 2: DATOS DE LA EMPRESA
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
@@ -256,7 +297,7 @@
<!-- ===============================================================
SECTION 3: PERSONALIZACIÓN DE TICKET
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
@@ -328,7 +369,7 @@
<!-- ===============================================================
SECTION 4: MÓDULOS E INTEGRACIONES
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/></svg>
@@ -380,6 +421,16 @@
<span class="toggle__slider"></span>
</label>
</div>
<div class="toggle-row">
<div class="toggle-row__info">
<span class="toggle-row__label">Notas de remisión en mostrador</span>
<span class="toggle-row__desc">Permite generar notas de remisión desde el POS para cobrar posteriormente en caja</span>
</div>
<label class="toggle">
<input type="checkbox" id="cfg-module-counter-remission" />
<span class="toggle__slider"></span>
</label>
</div>
<div style="margin-top:var(--space-4);text-align:right;">
<button class="btn btn--primary" onclick="Config.saveModules()">Guardar módulos</button>
</div>
@@ -389,13 +440,13 @@
<!-- ===============================================================
SECTION 4: USUARIOS Y PERMISOS
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="employees">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
</div>
<div>
<div class="settings-section__title">Usuarios y Permisos</div>
<div class="settings-section__title">Empleados</div>
<div class="settings-section__desc">Gestiona quién accede al sistema y qué puede hacer</div>
</div>
</div>
@@ -432,7 +483,7 @@
<!-- ===============================================================
SECTION 4: IMPRESORAS
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg>
@@ -458,7 +509,7 @@
<!-- ===============================================================
SECTION 5: SUCURSALES
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="fiscal">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
@@ -477,7 +528,7 @@
<!-- ===============================================================
SECTION 6: PARÁMETROS FISCALES
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="fiscal">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
@@ -613,7 +664,7 @@
<!-- ===============================================================
SECTION 7: PREFERENCIAS DEL SISTEMA
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="general">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
@@ -691,7 +742,7 @@
<!-- ===============================================================
SECTION 8: VEHICLE COMPATIBILITY SOURCE
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="catalog">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg>
@@ -724,7 +775,7 @@
<!-- ===============================================================
SECTION 9: MARCAS DE PARTES PERMITIDAS
=============================================================== -->
<div class="settings-section">
<div class="settings-section" data-tab="catalog">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><polyline points="2 17 12 22 22 17"/></svg>
@@ -785,6 +836,47 @@
</div>
</div>
<!-- ===============================================================
SECTION: PERMISOS POR ROL
=============================================================== -->
<div class="settings-section" data-tab="permissions">
<div class="settings-section__header">
<div class="settings-section__icon">
<svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<div>
<div class="settings-section__title">Permisos por Rol</div>
<div class="settings-section__desc">Define los permisos predeterminados para cada rol del sistema</div>
</div>
</div>
<div class="settings-card">
<div class="form-group" style="max-width:320px;">
<label class="form-label">Rol</label>
<select class="form-input" id="cfg-perm-role" onchange="Config.renderRolePermissions()">
<option value="">Selecciona un rol</option>
<option value="admin">Administrador</option>
<option value="cashier">Cajero</option>
<option value="counter">Mostrador</option>
<option value="warehouse">Almacén</option>
<option value="accountant">Contador</option>
<option value="workshop">Taller</option>
<option value="mechanic">Mecánico</option>
</select>
</div>
<div id="role-permissions-container" style="margin-top:var(--space-4);">
<p style="color:var(--color-text-muted);">Selecciona un rol para ver y editar sus permisos.</p>
</div>
<div style="margin-top:var(--space-4);">
<button class="btn btn--primary" id="btn-save-role-permissions" onclick="Config.saveRolePermissions()">Guardar permisos del rol</button>
<span id="role-permissions-status" style="font-size:var(--text-caption);color:var(--color-text-muted);margin-left:var(--space-3);"></span>
</div>
</div>
</div>
</div><!-- /content-scroll -->
</main>
</div><!-- /app-shell -->
@@ -893,6 +985,7 @@
<option value="">-- Seleccionar --</option>
<option value="admin">Administrador</option>
<option value="cashier">Cajero</option>
<option value="counter">Mostrador</option>
<option value="warehouse">Almacenista</option>
<option value="accountant">Contador</option>
<option value="workshop">Taller</option>
@@ -922,13 +1015,13 @@
</div>
</div>
<script src="/pos/static/js/i18n.js?v=36" defer></script>
<script src="/pos/static/js/app-init.js?v=2" defer></script>
<script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=5" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" defer></script>
<script src="/pos/static/js/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=36" defer></script>
<script src="/pos/static/js/sidebar.js?v=44" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/config.js?v=35" defer></script>
<script src="/pos/static/js/config.js?v=39" defer></script>
<script src="/pos/static/js/sync-engine.js" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
<script src="/pos/static/js/pwa-install.js" defer></script>