fix(permissions): honor module permissions for cashier/counter in sidebar and page guard
Some checks failed
CI / lint-and-test (3.11) (push) Has been cancelled
CI / lint-and-test (3.13) (push) Has been cancelled

This commit is contained in:
2026-07-03 08:10:22 +00:00
parent e270e848d7
commit 0bd5ee8ee8
19 changed files with 69 additions and 87 deletions

View File

@@ -186,22 +186,24 @@
function isPageAllowed(pagePath, userRole, userPerms) { function isPageAllowed(pagePath, userRole, userPerms) {
if (userRole === 'owner' || userRole === 'admin') return true; if (userRole === 'owner' || userRole === 'admin') return true;
// Workshop/mechanic accounts always see Taller; extra modules depend on permissions. // Restricted roles (workshop/mechanic/counter/cashier) see modules based on permissions.
if (userRole === 'workshop' || userRole === 'mechanic') { if (['workshop', 'mechanic', 'counter', 'cashier'].indexOf(userRole) !== -1) {
var allowed = ['/pos/workshop']; var allowed = [];
if (userRole === 'workshop' || userRole === 'mechanic') {
allowed = ['/pos/workshop'];
}
var permMap = { var permMap = {
'customers.view': '/pos/customers',
'inventory.view': '/pos/inventory',
'catalog.view': '/pos/catalog',
'pos.sell': '/pos/sale', 'pos.sell': '/pos/sale',
'pos.view': '/pos/sale', 'pos.view': '/pos/sale',
'catalog.view': '/pos/catalog',
'inventory.view': '/pos/inventory',
'customers.view': '/pos/customers',
'workshop.view': '/pos/workshop',
'pos.remission': '/pos/remission-notes', 'pos.remission': '/pos/remission-notes',
'invoicing.view': '/pos/invoicing', 'invoicing.view': '/pos/invoicing',
'quotations.view': '/pos/quotations', 'quotations.view': '/pos/quotations',
'accounting.view': '/pos/accounting', 'accounting.view': '/pos/accounting',
'reports.view': '/pos/reports', 'reports.view': '/pos/reports',
'config.view': '/pos/config',
'config.edit': '/pos/config',
'dashboard.view': '/pos/dashboard' 'dashboard.view': '/pos/dashboard'
}; };
for (var p in permMap) { for (var p in permMap) {
@@ -212,20 +214,6 @@
return allowed.indexOf(pagePath) !== -1; return allowed.indexOf(pagePath) !== -1;
} }
// Counter: fixed module set. Dashboard only if explicitly granted.
if (userRole === 'counter') {
var allowed = ['/pos/sale','/pos/catalog','/pos/inventory','/pos/customers','/pos/workshop','/pos/remission-notes','/pos/reports'];
if (userPerms.indexOf('dashboard.view') !== -1) allowed.push('/pos/dashboard');
return allowed.indexOf(pagePath) !== -1;
}
// Cashier: fixed module set. Dashboard only if explicitly granted.
if (userRole === 'cashier') {
var allowed = ['/pos/sale','/pos/catalog','/pos/inventory','/pos/customers','/pos/workshop','/pos/remission-notes','/pos/invoicing','/pos/reports'];
if (userPerms.indexOf('dashboard.view') !== -1) allowed.push('/pos/dashboard');
return allowed.indexOf(pagePath) !== -1;
}
// Always allow login/logout pages so users can sign out without hitting the guard. // Always allow login/logout pages so users can sign out without hitting the guard.
if (pagePath === '/pos/login' || pagePath === '/pos/logout') return true; if (pagePath === '/pos/login' || pagePath === '/pos/logout') return true;

View File

@@ -37,43 +37,37 @@ window.renderSidebar = function(modulesOverride) {
} }
// Role-based section filtering. Owner/admin bypasses; other roles get // Role-based section filtering. Owner/admin bypasses; other roles get
// only the sections relevant to their job. // only the sections allowed by their permissions.
function itemAllowed(id) { function itemAllowed(id) {
if (role === 'owner' || role === 'admin') return true; if (role === 'owner' || role === 'admin') return true;
var base = [];
if (role === 'workshop' || role === 'mechanic') { if (role === 'workshop' || role === 'mechanic') {
// Taller siempre visible; el resto depende de los permisos asignados. base = ['workshop'];
var allowed = ['workshop']; }
var permMap = {
'customers.view': 'customers', var permMap = {
'inventory.view': 'inventory', 'pos.sell': 'pos',
'catalog.view': 'catalog', 'pos.view': 'pos',
'pos.sell': 'pos', 'catalog.view': 'catalog',
'pos.view': 'pos', 'inventory.view': 'inventory',
'pos.remission': 'remission_notes', 'customers.view': 'customers',
'invoicing.view': 'invoicing', 'workshop.view': 'workshop',
'quotations.view': 'quotations', 'pos.remission': 'remission_notes',
'accounting.view': 'accounting', 'invoicing.view': 'invoicing',
'reports.view': 'reports', 'quotations.view': 'quotations',
'dashboard.view': 'dashboard' 'accounting.view': 'accounting',
}; 'reports.view': 'reports',
for (var p in permMap) { 'dashboard.view': 'dashboard'
if (perms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) { };
allowed.push(permMap[p]);
} var allowed = base.slice();
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 allowed.indexOf(id) !== -1;
var allowed = ['pos','catalog','inventory','customers','workshop','remission_notes','reports'];
if (hasPerm('dashboard.view')) allowed.push('dashboard');
return allowed.indexOf(id) !== -1;
}
if (role === 'cashier') {
var allowed = ['pos','catalog','inventory','customers','workshop','remission_notes','invoicing','reports'];
if (hasPerm('dashboard.view')) allowed.push('dashboard');
return allowed.indexOf(id) !== -1;
}
return true;
} }
var navSections = [ var navSections = [

View File

@@ -493,10 +493,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/accounting.v9.js?v=33" defer></script> <script src="/pos/static/js/accounting.v9.js?v=33" defer></script>
<script src="/pos/static/js/sync-engine.js" 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>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>

View File

@@ -316,10 +316,10 @@
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script> <script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/catalog.js?v=33" defer></script> <script src="/pos/static/js/catalog.js?v=33" defer></script>
<script src="/pos/static/js/offline-banner.js" defer></script> <script src="/pos/static/js/offline-banner.js" defer></script>
<script src="/pos/static/js/chat.js" defer></script> <script src="/pos/static/js/chat.js" defer></script>

View File

@@ -1033,10 +1033,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script> <script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/config.js?v=41" defer></script> <script src="/pos/static/js/config.js?v=41" defer></script>
<script src="/pos/static/js/sync-engine.js" defer></script> <script src="/pos/static/js/sync-engine.js" defer></script>

View File

@@ -651,10 +651,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/virtual-scroll.js" defer></script> <script src="/pos/static/js/virtual-scroll.js" defer></script>
<script src="/pos/static/js/customers.js?v=35" defer></script> <script src="/pos/static/js/customers.js?v=35" defer></script>
<script src="/pos/static/js/offline-banner.js" defer></script> <script src="/pos/static/js/offline-banner.js" defer></script>

View File

@@ -606,10 +606,10 @@
<script src="/pos/static/js/chart.umd.min.js" defer></script> <script src="/pos/static/js/chart.umd.min.js" defer></script>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/dashboard-stats.js?v=33" defer></script> <script src="/pos/static/js/dashboard-stats.js?v=33" defer></script>
<script src="/pos/static/js/dashboard.js?v=33" defer></script> <script src="/pos/static/js/dashboard.js?v=33" defer></script>
<script src="/pos/static/js/sync-engine.js" defer></script> <script src="/pos/static/js/sync-engine.js" defer></script>

View File

@@ -150,10 +150,10 @@
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script> <script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/diagrams.js" defer></script> <script src="/pos/static/js/diagrams.js" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</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> <script src="/pos/static/js/pwa-install.js" defer></script>

View File

@@ -303,10 +303,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/fleet.js" defer></script> <script src="/pos/static/js/fleet.js" defer></script>
<script src="/pos/static/js/offline-banner.js" defer></script> <script src="/pos/static/js/offline-banner.js" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script> <script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>

View File

@@ -1062,10 +1062,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/virtual-scroll.js?v=33" defer></script> <script src="/pos/static/js/virtual-scroll.js?v=33" defer></script>
<script src="/pos/static/js/inventory.js?v=38" defer></script> <script src="/pos/static/js/inventory.js?v=38" defer></script>
<script src="/pos/static/js/offline-banner.js" defer></script> <script src="/pos/static/js/offline-banner.js" defer></script>

View File

@@ -1064,10 +1064,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/invoicing.js?v=33" defer></script> <script src="/pos/static/js/invoicing.js?v=33" defer></script>
<script src="/pos/static/js/sync-engine.js" 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>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>

View File

@@ -343,10 +343,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/marketplace_external.js?v=33" defer></script> <script src="/pos/static/js/marketplace_external.js?v=33" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script> <script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
</body> </body>

View File

@@ -729,7 +729,7 @@
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/kiosk.js" defer></script> <script src="/pos/static/js/kiosk.js" defer></script>
<script src="/pos/static/js/pos-utils.js?v=33" defer></script> <script src="/pos/static/js/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" defer></script> <script src="/pos/static/js/splash-loader.js?v=33" defer></script>
<script src="/pos/static/js/push.js" defer></script> <script src="/pos/static/js/push.js" defer></script>
<script src="/pos/static/js/printer.js" defer></script> <script src="/pos/static/js/printer.js" defer></script>

View File

@@ -15,9 +15,9 @@
<body> <body>
<script src="/pos/static/js/pos-utils.js?v=33" defer></script> <script src="/pos/static/js/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" defer></script> <script src="/pos/static/js/splash-loader.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<div class="page"> <div class="page">
<h1 class="page-title">Cotizaciones</h1> <h1 class="page-title">Cotizaciones</h1>

View File

@@ -227,8 +227,8 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script> <script>
const token = localStorage.getItem('pos_token') || ''; const token = localStorage.getItem('pos_token') || '';

View File

@@ -406,10 +406,10 @@
<!-- End app-shell --> <!-- End app-shell -->
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/reports.js?v=35" defer></script> <script src="/pos/static/js/reports.js?v=35" defer></script>
<script src="/pos/static/js/sync-engine.js" 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>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>

View File

@@ -126,8 +126,8 @@
</div> </div>
</div> </div>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/supplier_catalog.js?v=33" defer></script> <script src="/pos/static/js/supplier_catalog.js?v=33" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script> <script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
</body> </body>

View File

@@ -132,11 +132,11 @@ function posLogout(){localStorage.removeItem('pos_token');window.location.href='
<!-- Sidebar --> <!-- Sidebar -->
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" defer></script> <script src="/pos/static/js/splash-loader.js?v=33" defer></script>
<script src="/pos/static/js/whatsapp2.js?v=33" defer></script> <script src="/pos/static/js/whatsapp2.js?v=33" defer></script>
<script src="/pos/static/js/pos-utils.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=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/chat.js" defer></script> <script src="/pos/static/js/chat.js" defer></script>
</body> </body>

View File

@@ -494,10 +494,10 @@
</div> </div>
<script src="/pos/static/js/i18n.js?v=39" defer></script> <script src="/pos/static/js/i18n.js?v=39" defer></script>
<script src="/pos/static/js/app-init.js?v=7" defer></script> <script src="/pos/static/js/app-init.js?v=8" defer></script>
<script src="/pos/static/js/splash-loader.js?v=33" 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/pos-utils.js?v=33" defer></script>
<script src="/pos/static/js/sidebar.js?v=45" defer></script> <script src="/pos/static/js/sidebar.js?v=46" defer></script>
<script src="/pos/static/js/offline-banner.js" defer></script> <script src="/pos/static/js/offline-banner.js" defer></script>
<script src="/pos/static/js/workshop.js?v=57" defer></script> <script src="/pos/static/js/workshop.js?v=57" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script> <script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>