Add workshop module toggle in Modules & Integrations settings
This commit is contained in:
@@ -1066,6 +1066,7 @@ def get_modules():
|
||||
'marketplace': _bool('module_marketplace'),
|
||||
'meli': _bool('module_meli'),
|
||||
'catalog': _bool('module_catalog'),
|
||||
'workshop': _bool('module_workshop'),
|
||||
})
|
||||
|
||||
|
||||
@@ -1082,6 +1083,7 @@ def update_modules():
|
||||
'module_marketplace': 'true' if data.get('marketplace') else 'false',
|
||||
'module_meli': 'true' if data.get('meli') else 'false',
|
||||
'module_catalog': 'true' if data.get('catalog') else 'false',
|
||||
'module_workshop': 'true' if data.get('workshop') else 'false',
|
||||
}
|
||||
|
||||
for key, value in settings.items():
|
||||
@@ -1098,6 +1100,8 @@ def update_modules():
|
||||
'whatsapp': data.get('whatsapp'),
|
||||
'marketplace': data.get('marketplace'),
|
||||
'meli': data.get('meli'),
|
||||
'catalog': data.get('catalog'),
|
||||
'workshop': data.get('workshop'),
|
||||
}})
|
||||
|
||||
|
||||
|
||||
@@ -183,13 +183,20 @@
|
||||
};
|
||||
|
||||
// ─── Page guard based on role + permissions ───
|
||||
function moduleEnabled(key) {
|
||||
try {
|
||||
var modules = JSON.parse(localStorage.getItem('pos_modules') || '{}');
|
||||
return modules[key] !== false;
|
||||
} catch(e) { return true; }
|
||||
}
|
||||
|
||||
function isPageAllowed(pagePath, userRole, userPerms) {
|
||||
if (userRole === 'owner' || userRole === 'admin') return true;
|
||||
|
||||
// Restricted roles (workshop/mechanic/counter/cashier) see modules based on permissions.
|
||||
if (['workshop', 'mechanic', 'counter', 'cashier'].indexOf(userRole) !== -1) {
|
||||
var allowed = [];
|
||||
if (userRole === 'workshop' || userRole === 'mechanic') {
|
||||
if ((userRole === 'workshop' || userRole === 'mechanic') && moduleEnabled('workshop')) {
|
||||
allowed = ['/pos/workshop'];
|
||||
}
|
||||
var permMap = {
|
||||
@@ -208,6 +215,8 @@
|
||||
};
|
||||
for (var p in permMap) {
|
||||
if (userPerms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) {
|
||||
// Hide workshop if its module is disabled
|
||||
if (permMap[p] === '/pos/workshop' && !moduleEnabled('workshop')) continue;
|
||||
allowed.push(permMap[p]);
|
||||
}
|
||||
}
|
||||
@@ -229,7 +238,9 @@
|
||||
fallback = '/pos/dashboard';
|
||||
} else if (['workshop', 'mechanic', 'counter', 'cashier'].indexOf(userRole) !== -1) {
|
||||
var allowed = [];
|
||||
if (userRole === 'workshop' || userRole === 'mechanic') allowed = ['/pos/workshop'];
|
||||
if ((userRole === 'workshop' || userRole === 'mechanic') && moduleEnabled('workshop')) {
|
||||
allowed = ['/pos/workshop'];
|
||||
}
|
||||
var permMap = {
|
||||
'pos.sell': '/pos/sale',
|
||||
'pos.view': '/pos/sale',
|
||||
@@ -246,6 +257,7 @@
|
||||
};
|
||||
for (var p in permMap) {
|
||||
if (userPerms.indexOf(p) !== -1 && allowed.indexOf(permMap[p]) === -1) {
|
||||
if (permMap[p] === '/pos/workshop' && !moduleEnabled('workshop')) continue;
|
||||
allowed.push(permMap[p]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -956,10 +956,12 @@ const Config = (() => {
|
||||
var cbMp = document.getElementById('cfg-module-marketplace');
|
||||
var cbMeli = document.getElementById('cfg-module-meli');
|
||||
var cbCat = document.getElementById('cfg-module-catalog');
|
||||
var cbWork = document.getElementById('cfg-module-workshop');
|
||||
if (cbWa) cbWa.checked = data.whatsapp !== false;
|
||||
if (cbMp) cbMp.checked = data.marketplace !== false;
|
||||
if (cbMeli) cbMeli.checked = data.meli !== false;
|
||||
if (cbCat) cbCat.checked = data.catalog !== false;
|
||||
if (cbWork) cbWork.checked = data.workshop !== false;
|
||||
localStorage.setItem('pos_modules', JSON.stringify(data));
|
||||
} catch (e) {
|
||||
console.error('Config.loadModules:', e);
|
||||
@@ -980,14 +982,16 @@ const Config = (() => {
|
||||
var cbMp = document.getElementById('cfg-module-marketplace');
|
||||
var cbMeli = document.getElementById('cfg-module-meli');
|
||||
var cbCat = document.getElementById('cfg-module-catalog');
|
||||
var cbWork = document.getElementById('cfg-module-workshop');
|
||||
var cbCr = document.getElementById('cfg-module-counter-remission');
|
||||
if (!cbWa && !cbMp && !cbMeli && !cbCat && !cbCr) return;
|
||||
if (!cbWa && !cbMp && !cbMeli && !cbCat && !cbWork && !cbCr) return;
|
||||
try {
|
||||
var data = {
|
||||
whatsapp: cbWa ? cbWa.checked : true,
|
||||
marketplace: cbMp ? cbMp.checked : true,
|
||||
meli: cbMeli ? cbMeli.checked : true,
|
||||
catalog: cbCat ? cbCat.checked : true,
|
||||
workshop: cbWork ? cbWork.checked : true,
|
||||
};
|
||||
var res = await fetch(API + '/modules', {
|
||||
method: 'PUT',
|
||||
|
||||
@@ -34,6 +34,7 @@ const POS = (() => {
|
||||
let counterRemissionEnabled = false;
|
||||
let allowZeroPriceSales = true;
|
||||
let allowNegativeStock = false;
|
||||
let workshopModuleEnabled = true;
|
||||
let currentPerms = [];
|
||||
let receiptConfig = {};
|
||||
let couriers = [];
|
||||
@@ -93,7 +94,7 @@ const POS = (() => {
|
||||
}
|
||||
if (!canDiscount) hide('[onclick="POS.applyDiscount()"]');
|
||||
if (!canEditPrice) hide('[onclick="POS.modifyPrice()"]');
|
||||
if (!canCreateWorkshopOrder) {
|
||||
if (!canCreateWorkshopOrder || !workshopModuleEnabled) {
|
||||
hide('[onclick="POS.createServiceOrder()"]');
|
||||
hide('[title="Orden de servicio"]');
|
||||
}
|
||||
@@ -153,6 +154,14 @@ const POS = (() => {
|
||||
allowZeroPriceSales = true;
|
||||
allowNegativeStock = false;
|
||||
}
|
||||
// Module toggles (from app-init preloaded modules)
|
||||
try {
|
||||
var modules = window.POS_USER && window.POS_USER.modules;
|
||||
if (!modules) modules = JSON.parse(localStorage.getItem('pos_modules') || '{}');
|
||||
workshopModuleEnabled = modules.workshop !== false;
|
||||
} catch (e) {
|
||||
workshopModuleEnabled = true;
|
||||
}
|
||||
// Counter remission workflow applies only to the counter role.
|
||||
canCreateRemission = counterRemissionEnabled && employeeRole === 'counter' && perms.includes('pos.remission');
|
||||
|
||||
@@ -1390,6 +1399,7 @@ const POS = (() => {
|
||||
|
||||
// ─── Service Order from POS ──────────
|
||||
function createServiceOrder() {
|
||||
if (!workshopModuleEnabled) { showToast('El módulo de taller no está habilitado'); return; }
|
||||
if (!canCreateWorkshopOrder) { showToast('No tienes permiso para ordenes de taller'); return; }
|
||||
if (cart.length === 0) { showToast('Carrito vacio'); return; }
|
||||
const zeroItem = findZeroPriceItem();
|
||||
|
||||
@@ -80,7 +80,7 @@ window.renderSidebar = function(modulesOverride) {
|
||||
{ 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"/>' },
|
||||
moduleEnabled('workshop') ? { 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"/>' } : null,
|
||||
{ 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,
|
||||
moduleEnabled('meli') ? { id: 'meli', name: 'MercadoLibre', href: '/pos/marketplace-external', icon: '<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>' } : null,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// The fetch handler normalizes static asset URLs (strips ?v= query strings)
|
||||
// so templates can use cache-busting query params freely.
|
||||
|
||||
const VERSION = 45;
|
||||
const VERSION = 46;
|
||||
const CACHE_NAME = 'nexus-pos-v' + VERSION;
|
||||
|
||||
const APP_SHELL = [
|
||||
|
||||
@@ -421,6 +421,16 @@
|
||||
<span class="toggle__slider"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<div class="toggle-row__info">
|
||||
<span class="toggle-row__label">Taller / Servicio</span>
|
||||
<span class="toggle-row__desc">Mostrar el módulo de órdenes de servicio y taller</span>
|
||||
</div>
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="cfg-module-workshop" checked />
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user