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

@@ -41,10 +41,32 @@ window.renderSidebar = function(modulesOverride) {
function itemAllowed(id) {
if (role === 'owner' || role === 'admin') return true;
if (role === 'workshop' || role === 'mechanic') {
return id === 'workshop';
// Taller siempre visible; el resto depende de los permisos asignados.
var allowed = ['workshop'];
var permMap = {
'customers.view': 'customers',
'inventory.view': 'inventory',
'catalog.view': 'catalog',
'pos.sell': 'pos',
'pos.view': 'pos',
'pos.remission': 'remission_notes',
'invoicing.view': 'invoicing',
'quotations.view': 'quotations',
'accounting.view': 'accounting',
'reports.view': 'reports'
};
for (var p in permMap) {
if (perms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) {
allowed.push(permMap[p]);
}
}
return allowed.indexOf(id) !== -1;
}
if (role === 'counter') {
return ['pos','catalog','inventory','customers','workshop','remission_notes','reports'].indexOf(id) !== -1;
}
if (role === 'cashier') {
return ['dashboard','pos','catalog','inventory','customers'].indexOf(id) !== -1;
return ['pos','catalog','inventory','customers','workshop','remission_notes','invoicing','reports'].indexOf(id) !== -1;
}
return true;
}
@@ -58,6 +80,7 @@ window.renderSidebar = function(modulesOverride) {
].filter(Boolean).filter(function(i){ return itemAllowed(i.id); })},
{ label: _t('nav_management'), items: [
{ id: 'customers', name: _t('customers'), href: '/pos/customers', icon: '<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.87M16 3.13a4 4 0 0 1 0 7.75"/>' },
{ id: 'remission_notes', name: _t('remission_notes'), href: '/pos/remission-notes', icon: '<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"/>' },
{ id: 'workshop', name: 'Taller', href: '/pos/workshop', icon: '<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>' },
{ id: 'quotations', name: 'Cotizaciones', href: '/pos/quotations', icon: '<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="9" y1="15" x2="15" y2="15"/><line x1="12" y1="12" x2="12" y2="18"/>' },
moduleEnabled('marketplace') ? { id: 'marketplace', name: 'Marketplace', href: '/pos/marketplace', icon: '<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>' } : null,
@@ -65,7 +88,6 @@ window.renderSidebar = function(modulesOverride) {
{ id: 'invoicing', name: _t('invoicing'), href: '/pos/invoicing', icon: '<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"/>' },
{ id: 'accounting', name: _t('accounting'), href: '/pos/accounting', icon: '<line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>' },
{ id: 'reports', name: _t('reports'), href: '/pos/reports', icon: '<line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/>' },
hasPerm('fleet.view') ? { id: 'fleet', name: _t('fleet'), href: '/pos/fleet', icon: '<path d="M1 13h22M1 13l2-6h6l2 6M9 7h6l2 6M15 13l2-6M5 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4zM19 17a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/>' } : null,
moduleEnabled('whatsapp') ? { id: 'whatsapp', name: _t('whatsapp'), href: '/pos/whatsapp', icon: '<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>' } : null,
].filter(Boolean).filter(function(i){ return itemAllowed(i.id); })},
{ label: _t('nav_system'), items: [
@@ -132,14 +154,14 @@ window.renderSidebar = function(modulesOverride) {
+ '</div>';
// Replace existing sidebar
var existing = document.querySelector('aside.sidebar, .sidebar, #sidebar');
var existing = document.querySelector('.pos-sidebar, aside.sidebar, .sidebar, #sidebar');
if (existing) {
existing.className = 'pos-sidebar';
existing.className = 'pos-sidebar sidebar';
existing.innerHTML = sidebarHtml;
existing.removeAttribute('style');
} else {
var el = document.createElement('aside');
el.className = 'pos-sidebar';
el.className = 'pos-sidebar sidebar';
el.innerHTML = sidebarHtml;
document.body.insertBefore(el, document.body.firstChild);
}