feat: cashier/counter reports, service-order & remission flows, Rached migration utils
- 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:
@@ -182,10 +182,85 @@
|
||||
permissions: payload.permissions || []
|
||||
};
|
||||
|
||||
// ─── Restrict workshop/mechanic users to the workshop view only ───
|
||||
if ((role === 'workshop' || role === 'mechanic') && window.location.pathname !== '/pos/workshop') {
|
||||
window.location.replace('/pos/workshop');
|
||||
return;
|
||||
// ─── Page guard based on role + permissions ───
|
||||
function isPageAllowed(pagePath, userRole, userPerms) {
|
||||
if (userRole === 'owner' || userRole === 'admin') return true;
|
||||
|
||||
// Workshop/mechanic accounts always see Taller; extra modules depend on permissions.
|
||||
if (userRole === 'workshop' || userRole === 'mechanic') {
|
||||
var allowed = ['/pos/workshop'];
|
||||
var permMap = {
|
||||
'customers.view': '/pos/customers',
|
||||
'inventory.view': '/pos/inventory',
|
||||
'catalog.view': '/pos/catalog',
|
||||
'pos.sell': '/pos/sale',
|
||||
'pos.view': '/pos/sale',
|
||||
'pos.remission': '/pos/remission-notes',
|
||||
'invoicing.view': '/pos/invoicing',
|
||||
'quotations.view': '/pos/quotations',
|
||||
'accounting.view': '/pos/accounting',
|
||||
'reports.view': '/pos/reports',
|
||||
'config.view': '/pos/config',
|
||||
'config.edit': '/pos/config'
|
||||
};
|
||||
for (var p in permMap) {
|
||||
if (userPerms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) {
|
||||
allowed.push(permMap[p]);
|
||||
}
|
||||
}
|
||||
return allowed.indexOf(pagePath) !== -1;
|
||||
}
|
||||
|
||||
// Counter: fixed module set (no dashboard).
|
||||
if (userRole === 'counter') {
|
||||
return ['/pos/sale','/pos/catalog','/pos/inventory','/pos/customers','/pos/workshop','/pos/remission-notes','/pos/reports'].indexOf(pagePath) !== -1;
|
||||
}
|
||||
|
||||
// Cashier: fixed module set (no dashboard).
|
||||
if (userRole === 'cashier') {
|
||||
return ['/pos/sale','/pos/catalog','/pos/inventory','/pos/customers','/pos/workshop','/pos/remission-notes','/pos/invoicing','/pos/reports'].indexOf(pagePath) !== -1;
|
||||
}
|
||||
|
||||
// Any other role (accountant, warehouse, sales, etc.) keeps the previous permissive behavior.
|
||||
return true;
|
||||
}
|
||||
|
||||
function enforcePageGuard(userRole, userPerms) {
|
||||
if (isPageAllowed(path, userRole, userPerms)) return true;
|
||||
var fallback = '/pos/catalog';
|
||||
if (userRole === 'counter' || userRole === 'cashier') fallback = '/pos/sale';
|
||||
else if (userRole === 'workshop' || userRole === 'mechanic') fallback = '/pos/workshop';
|
||||
window.location.replace(fallback);
|
||||
return false;
|
||||
}
|
||||
|
||||
// ─── Refresh permissions/token from server before enforcing the guard ───
|
||||
// This makes permission changes effective without requiring a full re-login.
|
||||
try {
|
||||
fetch('/pos/api/auth/refresh', {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Bearer ' + token }
|
||||
}).then(function(r) {
|
||||
if (r.ok) return r.json();
|
||||
return null;
|
||||
}).then(function(data) {
|
||||
if (data && data.token) {
|
||||
localStorage.setItem('pos_token', data.token);
|
||||
localStorage.setItem('pos_employee', JSON.stringify(data.employee));
|
||||
token = data.token;
|
||||
window.POS_USER.token = data.token;
|
||||
window.POS_USER.permissions = data.permissions || [];
|
||||
window.POS_USER.branchId = data.employee.branch_id;
|
||||
}
|
||||
if (!enforcePageGuard(window.POS_USER.role, window.POS_USER.permissions)) return;
|
||||
if (typeof window.renderSidebar === 'function') {
|
||||
window.renderSidebar(window.POS_USER.modules || JSON.parse(localStorage.getItem('pos_modules') || '{}'));
|
||||
}
|
||||
}).catch(function() {
|
||||
enforcePageGuard(role, payload.permissions || []);
|
||||
});
|
||||
} catch(e) {
|
||||
enforcePageGuard(role, payload.permissions || []);
|
||||
}
|
||||
|
||||
// ─── Preload enabled modules for sidebar filtering ───
|
||||
|
||||
Reference in New Issue
Block a user