diff --git a/pos/config.py b/pos/config.py index 71c46aa..a94f89f 100644 --- a/pos/config.py +++ b/pos/config.py @@ -36,3 +36,7 @@ SMTP_FROM = os.environ.get('SMTP_FROM', 'noreply@nexusautoparts.com') WHATSAPP_TOKEN = os.environ.get("WHATSAPP_TOKEN", "") WHATSAPP_PHONE_ID = os.environ.get("WHATSAPP_PHONE_ID", "") WHATSAPP_VERIFY_TOKEN = os.environ.get("WHATSAPP_VERIFY_TOKEN", "nexus-wa-verify-2026") + +# Multi-currency +DEFAULT_CURRENCY = os.environ.get('DEFAULT_CURRENCY', 'MXN') +EXCHANGE_RATE_USD_MXN = float(os.environ.get('EXCHANGE_RATE_USD_MXN', '17.5')) diff --git a/pos/services/currency.py b/pos/services/currency.py new file mode 100644 index 0000000..e258c3d --- /dev/null +++ b/pos/services/currency.py @@ -0,0 +1,55 @@ +"""Multi-currency support for border refaccionarias. + +Supports MXN and USD with configurable exchange rate. +""" + +from config import DEFAULT_CURRENCY, EXCHANGE_RATE_USD_MXN + +CURRENCIES = { + 'MXN': {'symbol': '$', 'name': 'Peso Mexicano', 'name_en': 'Mexican Peso', 'decimals': 2}, + 'USD': {'symbol': 'US$', 'name': 'Dolar Estadounidense', 'name_en': 'US Dollar', 'decimals': 2}, +} + + +def convert(amount, from_currency, to_currency, rate=None): + """Convert an amount between currencies. + + Args: + amount: The numeric amount to convert. + from_currency: Source currency code ('MXN' or 'USD'). + to_currency: Target currency code ('MXN' or 'USD'). + rate: Optional custom exchange rate (USD->MXN). Defaults to config value. + + Returns: + The converted amount, rounded to 2 decimals. + """ + if from_currency == to_currency: + return amount + if rate is None: + rate = EXCHANGE_RATE_USD_MXN + if from_currency == 'USD' and to_currency == 'MXN': + return round(amount * rate, 2) + if from_currency == 'MXN' and to_currency == 'USD': + return round(amount / rate, 2) + return amount + + +def format_currency(amount, currency='MXN'): + """Format an amount with the appropriate currency symbol. + + Args: + amount: Numeric value. + currency: Currency code. + + Returns: + Formatted string like '$1,234.56' or 'US$1,234.56'. + """ + info = CURRENCIES.get(currency, CURRENCIES['MXN']) + return f"{info['symbol']}{amount:,.{info['decimals']}f}" + + +def get_currency_info(code=None): + """Return currency metadata dict. If code is None, return all.""" + if code: + return CURRENCIES.get(code) + return CURRENCIES diff --git a/pos/static/js/app-init.js b/pos/static/js/app-init.js index 755d276..97f2a05 100644 --- a/pos/static/js/app-init.js +++ b/pos/static/js/app-init.js @@ -40,9 +40,10 @@ var name = employee.name || payload.name || 'Usuario'; var role = employee.role || payload.role || ''; + var _t = typeof window.t === 'function' ? window.t : function(k) { return k; }; var roleLabels = { - 'owner': 'Dueño', 'admin': 'Administrador', 'cashier': 'Cajero', - 'warehouse': 'Almacén', 'accountant': 'Contador' + 'owner': _t('role_owner'), 'admin': _t('role_admin'), 'cashier': _t('role_cashier'), + 'warehouse': _t('role_warehouse'), 'accountant': _t('role_accountant') }; var roleLabel = roleLabels[role] || role; var initials = name.split(' ').map(function(p) { return p[0]; }).join('').toUpperCase().substring(0, 2); diff --git a/pos/static/js/config.js b/pos/static/js/config.js index 1d686b6..2659a74 100644 --- a/pos/static/js/config.js +++ b/pos/static/js/config.js @@ -416,6 +416,68 @@ const Config = (() => { }); } + // ------------------------------------------------------------------------- + // Currency + // ------------------------------------------------------------------------- + async function loadCurrency() { + try { + var res = await fetch(API + '/currency', { headers: headers() }); + if (!res.ok) return; + var d = await res.json(); + var selCurrency = document.getElementById('cfg-currency'); + var inpRate = document.getElementById('cfg-exchange-rate'); + if (selCurrency) selCurrency.value = d.currency || 'MXN'; + if (inpRate) inpRate.value = d.exchange_rate || 17.5; + // Store in localStorage for POS fmt() to pick up + localStorage.setItem('pos_currency', d.currency || 'MXN'); + localStorage.setItem('pos_exchange_rate', d.exchange_rate || 17.5); + } catch (e) { + console.error('Config.loadCurrency:', e); + } + } + + async function saveCurrency() { + var selCurrency = document.getElementById('cfg-currency'); + var inpRate = document.getElementById('cfg-exchange-rate'); + var statusEl = document.getElementById('currency-status'); + var btn = document.getElementById('btn-save-currency'); + + if (!selCurrency || !inpRate) return; + + var currency = selCurrency.value; + var rate = parseFloat(inpRate.value); + + if (!rate || rate <= 0) { + toast('Tipo de cambio invalido', 'error'); + return; + } + + if (btn) { btn.disabled = true; btn.textContent = 'Guardando...'; } + + try { + var res = await fetch(API + '/currency', { + method: 'PUT', + headers: headers(), + body: JSON.stringify({ currency: currency, exchange_rate: rate }) + }); + if (!res.ok) { + var err = await res.json().catch(function() { return { error: res.statusText }; }); + throw new Error(err.error || 'Save failed'); + } + localStorage.setItem('pos_currency', currency); + localStorage.setItem('pos_exchange_rate', rate); + toast('Moneda actualizada'); + if (statusEl) statusEl.textContent = currency + ' — TC: ' + rate; + } catch (e) { + toast(e.message, 'error'); + } finally { + if (btn) { + btn.disabled = false; + btn.textContent = 'Guardar Moneda'; + } + } + } + // ------------------------------------------------------------------------- // Init // ------------------------------------------------------------------------- @@ -441,6 +503,7 @@ const Config = (() => { loadBranches(); loadEmployees(); loadBusiness(); + loadCurrency(); } document.addEventListener('DOMContentLoaded', init); @@ -448,6 +511,7 @@ const Config = (() => { return { init, setTheme, selectThemeOption, loadBranches, loadEmployees, saveBranch, saveEmployee, + loadCurrency, saveCurrency, openModal, closeModal }; })(); diff --git a/pos/static/js/i18n.js b/pos/static/js/i18n.js new file mode 100644 index 0000000..eec20a9 --- /dev/null +++ b/pos/static/js/i18n.js @@ -0,0 +1,342 @@ +/** + * i18n.js — Simple internationalization for Nexus Autoparts POS + * Supports: es (Spanish/Mexico) and en (English/USA) + */ +var I18N = { + es: { + // Sidebar nav + 'dashboard': 'Dashboard', + 'pos': 'Punto de Venta', + 'catalog': 'Catalogo', + 'inventory': 'Inventario', + 'customers': 'Clientes', + 'invoicing': 'Facturacion', + 'accounting': 'Contabilidad', + 'reports': 'Reportes', + 'fleet': 'Flotillas', + 'whatsapp': 'WhatsApp', + 'config': 'Configuracion', + // Sidebar sections + 'nav_main': 'Principal', + 'nav_management': 'Gestion', + 'nav_system': 'Sistema', + // Common actions + 'search': 'Buscar', + 'save': 'Guardar', + 'cancel': 'Cancelar', + 'delete': 'Eliminar', + 'edit': 'Editar', + 'new': 'Nuevo', + 'close': 'Cerrar', + 'confirm': 'Confirmar', + 'back': 'Regresar', + 'next': 'Siguiente', + 'print': 'Imprimir', + 'export': 'Exportar', + 'import': 'Importar', + 'refresh': 'Actualizar', + 'loading': 'Cargando...', + 'no_results': 'Sin resultados', + 'error': 'Error', + 'success': 'Exito', + 'warning': 'Advertencia', + // Financial + 'total': 'Total', + 'subtotal': 'Subtotal', + 'tax': 'IVA', + 'price': 'Precio', + 'unit_price': 'Precio Unitario', + 'cost': 'Costo', + 'discount': 'Descuento', + 'margin': 'Margen', + 'profit': 'Utilidad', + 'balance': 'Saldo', + 'amount': 'Monto', + // Inventory + 'quantity': 'Cantidad', + 'stock': 'Existencias', + 'min_stock': 'Minimo', + 'max_stock': 'Maximo', + 'sku': 'SKU', + 'barcode': 'Codigo de Barras', + 'brand': 'Marca', + 'category': 'Categoria', + 'description': 'Descripcion', + 'location': 'Ubicacion', + // Table headers + 'name': 'Nombre', + 'date': 'Fecha', + 'status': 'Estado', + 'actions': 'Acciones', + 'id': 'ID', + 'type': 'Tipo', + 'notes': 'Notas', + // POS + 'charge': 'Cobrar', + 'quote': 'Cotizacion', + 'layaway': 'Apartado', + 'credit': 'Credito', + 'cash': 'Efectivo', + 'transfer': 'Transferencia', + 'card': 'Tarjeta', + 'mixed': 'Mixto', + 'change': 'Cambio', + 'customer': 'Cliente', + 'general_public': 'Publico General', + 'sale': 'Venta', + 'sales': 'Ventas', + 'ticket': 'Ticket', + 'receipt': 'Recibo', + 'payment': 'Pago', + 'payment_method': 'Metodo de Pago', + 'add_to_cart': 'Agregar', + 'clear_cart': 'Limpiar Carrito', + 'hold_sale': 'Pausar Venta', + 'recall_sale': 'Retomar Venta', + 'cancel_sale': 'Cancelar Venta', + 'confirm_payment': 'Confirmar Pago', + 'cash_received': 'Efectivo Recibido', + 'amount_due': 'Total a Pagar', + 'remaining': 'Faltante', + // Customers + 'phone': 'Telefono', + 'email': 'Correo', + 'address': 'Direccion', + 'rfc': 'RFC', + 'credit_limit': 'Limite de Credito', + 'credit_balance': 'Saldo de Credito', + 'price_tier': 'Nivel de Precio', + // Invoicing + 'invoice': 'Factura', + 'cfdi': 'CFDI', + 'stamp': 'Timbrar', + 'cancel_invoice': 'Cancelar Factura', + // Config + 'appearance': 'Apariencia', + 'business_data': 'Datos de la Empresa', + 'employees': 'Empleados', + 'printers': 'Impresoras', + 'branches': 'Sucursales', + 'fiscal_params': 'Parametros Fiscales', + 'system_prefs': 'Preferencias del Sistema', + 'currency_config': 'Moneda', + 'language': 'Idioma', + 'theme': 'Tema', + 'dark_theme': 'Tema oscuro', + 'light_theme': 'Tema claro', + 'logout': 'Cerrar sesion', + // Currency + 'currency': 'Moneda', + 'exchange_rate': 'Tipo de Cambio', + 'default_currency': 'Moneda Predeterminada', + 'mxn': 'Peso Mexicano', + 'usd': 'Dolar Estadounidense', + // Roles + 'role_owner': 'Dueno', + 'role_admin': 'Administrador', + 'role_cashier': 'Cajero', + 'role_warehouse': 'Almacen', + 'role_accountant': 'Contador', + // Reports + 'daily_sales': 'Ventas del Dia', + 'weekly_sales': 'Ventas de la Semana', + 'monthly_sales': 'Ventas del Mes', + 'top_products': 'Productos Mas Vendidos', + 'low_stock': 'Bajo Stock', + // Fleet + 'vehicle': 'Vehiculo', + 'plate': 'Placa', + 'vin': 'VIN', + 'mileage': 'Kilometraje', + // Misc + 'yes': 'Si', + 'no': 'No', + 'all': 'Todos', + 'active': 'Activo', + 'inactive': 'Inactivo', + 'pending': 'Pendiente', + 'completed': 'Completado', + 'cancelled': 'Cancelado', + }, + en: { + // Sidebar nav + 'dashboard': 'Dashboard', + 'pos': 'Point of Sale', + 'catalog': 'Catalog', + 'inventory': 'Inventory', + 'customers': 'Customers', + 'invoicing': 'Invoicing', + 'accounting': 'Accounting', + 'reports': 'Reports', + 'fleet': 'Fleet', + 'whatsapp': 'WhatsApp', + 'config': 'Settings', + // Sidebar sections + 'nav_main': 'Main', + 'nav_management': 'Management', + 'nav_system': 'System', + // Common actions + 'search': 'Search', + 'save': 'Save', + 'cancel': 'Cancel', + 'delete': 'Delete', + 'edit': 'Edit', + 'new': 'New', + 'close': 'Close', + 'confirm': 'Confirm', + 'back': 'Back', + 'next': 'Next', + 'print': 'Print', + 'export': 'Export', + 'import': 'Import', + 'refresh': 'Refresh', + 'loading': 'Loading...', + 'no_results': 'No results', + 'error': 'Error', + 'success': 'Success', + 'warning': 'Warning', + // Financial + 'total': 'Total', + 'subtotal': 'Subtotal', + 'tax': 'Tax', + 'price': 'Price', + 'unit_price': 'Unit Price', + 'cost': 'Cost', + 'discount': 'Discount', + 'margin': 'Margin', + 'profit': 'Profit', + 'balance': 'Balance', + 'amount': 'Amount', + // Inventory + 'quantity': 'Quantity', + 'stock': 'Stock', + 'min_stock': 'Minimum', + 'max_stock': 'Maximum', + 'sku': 'SKU', + 'barcode': 'Barcode', + 'brand': 'Brand', + 'category': 'Category', + 'description': 'Description', + 'location': 'Location', + // Table headers + 'name': 'Name', + 'date': 'Date', + 'status': 'Status', + 'actions': 'Actions', + 'id': 'ID', + 'type': 'Type', + 'notes': 'Notes', + // POS + 'charge': 'Charge', + 'quote': 'Quote', + 'layaway': 'Layaway', + 'credit': 'Credit', + 'cash': 'Cash', + 'transfer': 'Transfer', + 'card': 'Card', + 'mixed': 'Mixed', + 'change': 'Change', + 'customer': 'Customer', + 'general_public': 'Walk-in Customer', + 'sale': 'Sale', + 'sales': 'Sales', + 'ticket': 'Ticket', + 'receipt': 'Receipt', + 'payment': 'Payment', + 'payment_method': 'Payment Method', + 'add_to_cart': 'Add', + 'clear_cart': 'Clear Cart', + 'hold_sale': 'Hold Sale', + 'recall_sale': 'Recall Sale', + 'cancel_sale': 'Cancel Sale', + 'confirm_payment': 'Confirm Payment', + 'cash_received': 'Cash Received', + 'amount_due': 'Amount Due', + 'remaining': 'Remaining', + // Customers + 'phone': 'Phone', + 'email': 'Email', + 'address': 'Address', + 'rfc': 'Tax ID (RFC)', + 'credit_limit': 'Credit Limit', + 'credit_balance': 'Credit Balance', + 'price_tier': 'Price Tier', + // Invoicing + 'invoice': 'Invoice', + 'cfdi': 'CFDI', + 'stamp': 'Stamp', + 'cancel_invoice': 'Cancel Invoice', + // Config + 'appearance': 'Appearance', + 'business_data': 'Business Info', + 'employees': 'Employees', + 'printers': 'Printers', + 'branches': 'Branches', + 'fiscal_params': 'Tax Settings', + 'system_prefs': 'System Preferences', + 'currency_config': 'Currency', + 'language': 'Language', + 'theme': 'Theme', + 'dark_theme': 'Dark theme', + 'light_theme': 'Light theme', + 'logout': 'Log out', + // Currency + 'currency': 'Currency', + 'exchange_rate': 'Exchange Rate', + 'default_currency': 'Default Currency', + 'mxn': 'Mexican Peso', + 'usd': 'US Dollar', + // Roles + 'role_owner': 'Owner', + 'role_admin': 'Administrator', + 'role_cashier': 'Cashier', + 'role_warehouse': 'Warehouse', + 'role_accountant': 'Accountant', + // Reports + 'daily_sales': 'Daily Sales', + 'weekly_sales': 'Weekly Sales', + 'monthly_sales': 'Monthly Sales', + 'top_products': 'Top Products', + 'low_stock': 'Low Stock', + // Fleet + 'vehicle': 'Vehicle', + 'plate': 'Plate', + 'vin': 'VIN', + 'mileage': 'Mileage', + // Misc + 'yes': 'Yes', + 'no': 'No', + 'all': 'All', + 'active': 'Active', + 'inactive': 'Inactive', + 'pending': 'Pending', + 'completed': 'Completed', + 'cancelled': 'Cancelled', + } +}; + +var currentLang = localStorage.getItem('pos_lang') || 'es'; + +/** + * Translate a key to the current language. + * Falls back to Spanish, then to the raw key. + */ +window.t = function(key) { + return (I18N[currentLang] && I18N[currentLang][key]) || (I18N['es'] && I18N['es'][key]) || key; +}; + +/** + * Switch the UI language and reload. + */ +window.setLang = function(lang) { + currentLang = lang; + localStorage.setItem('pos_lang', lang); + location.reload(); +}; + +/** + * Get the current language code. + */ +window.getLang = function() { + return currentLang; +}; diff --git a/pos/static/js/sidebar.js b/pos/static/js/sidebar.js index 1445d80..d418502 100644 --- a/pos/static/js/sidebar.js +++ b/pos/static/js/sidebar.js @@ -1,34 +1,39 @@ /** * sidebar.js — Shared sidebar matching the design system style * Replaces existing sidebar in each page with a consistent, themed version. + * Uses i18n t() for all labels when available. */ (function() { 'use strict'; + // i18n helper — falls back to raw string if i18n.js not loaded + var _t = typeof window.t === 'function' ? window.t : function(k) { return k; }; + var u = window.POS_USER || {}; var name = u.name || 'Usuario'; var roleLabel = u.roleLabel || ''; var initials = u.initials || '?'; var currentPath = window.location.pathname; var currentTheme = localStorage.getItem('pos_theme') || 'industrial'; + var currentLang = localStorage.getItem('pos_lang') || 'es'; var navSections = [ - { label: 'Principal', items: [ - { name: 'Dashboard', href: '/pos/dashboard', icon: '' }, - { name: 'POS', href: '/pos/sale', icon: '' }, - { name: 'Catálogo', href: '/pos/catalog', icon: '' }, - { name: 'Inventario', href: '/pos/inventory', icon: '' }, + { label: _t('nav_main'), items: [ + { name: _t('dashboard'), href: '/pos/dashboard', icon: '' }, + { name: _t('pos'), href: '/pos/sale', icon: '' }, + { name: _t('catalog'), href: '/pos/catalog', icon: '' }, + { name: _t('inventory'), href: '/pos/inventory', icon: '' }, ]}, - { label: 'Gestión', items: [ - { name: 'Clientes', href: '/pos/customers', icon: '' }, - { name: 'Facturación', href: '/pos/invoicing', icon: '' }, - { name: 'Contabilidad', href: '/pos/accounting', icon: '' }, - { name: 'Reportes', href: '/pos/reports', icon: '' }, - { name: 'Flotillas', href: '/pos/fleet', icon: '' }, - { name: 'WhatsApp', href: '/pos/whatsapp', icon: '' }, + { label: _t('nav_management'), items: [ + { name: _t('customers'), href: '/pos/customers', icon: '' }, + { name: _t('invoicing'), href: '/pos/invoicing', icon: '' }, + { name: _t('accounting'), href: '/pos/accounting', icon: '' }, + { name: _t('reports'), href: '/pos/reports', icon: '' }, + { name: _t('fleet'), href: '/pos/fleet', icon: '' }, + { name: _t('whatsapp'), href: '/pos/whatsapp', icon: '' }, ]}, - { label: 'Sistema', items: [ - { name: 'Configuración', href: '/pos/config', icon: '' }, + { label: _t('nav_system'), items: [ + { name: _t('config'), href: '/pos/config', icon: '' }, ]}, ]; @@ -51,14 +56,24 @@ // Theme toggle buttons var themeHtml = ''; + // Language toggle buttons + var langHtml = ''; + window.updateThemeButtons = function() { var t = localStorage.getItem('pos_theme') || 'industrial'; document.querySelectorAll('.theme-toggle-btn').forEach(function(b, i) { @@ -76,13 +91,14 @@ + '' + '' + themeHtml + + langHtml + ''; @@ -110,10 +126,11 @@ '.nav-item__icon{width:18px;height:18px;flex-shrink:0;opacity:0.7}', '.nav-item.is-active .nav-item__icon{opacity:1}', - '.sidebar__theme-toggle{display:flex;gap:4px;padding:8px 16px;border-top:1px solid var(--color-border)}', - '.theme-toggle-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:6px;border:1px solid var(--color-border);border-radius:var(--radius-sm,4px);background:none;color:var(--color-text-muted);cursor:pointer;transition:all 0.15s;font-size:0.75rem}', - '.theme-toggle-btn:hover{color:var(--color-text-primary);background:var(--color-surface-2,rgba(255,255,255,0.04))}', - '.theme-toggle-btn.is-active{background:var(--color-primary-muted,rgba(245,166,35,0.12));color:var(--color-primary);border-color:var(--color-primary)}', + '.sidebar__theme-toggle,.sidebar__lang-toggle{display:flex;gap:4px;padding:8px 16px;border-top:1px solid var(--color-border)}', + '.theme-toggle-btn,.lang-toggle-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:6px;border:1px solid var(--color-border);border-radius:var(--radius-sm,4px);background:none;color:var(--color-text-muted);cursor:pointer;transition:all 0.15s;font-size:0.75rem}', + '.theme-toggle-btn:hover,.lang-toggle-btn:hover{color:var(--color-text-primary);background:var(--color-surface-2,rgba(255,255,255,0.04))}', + '.theme-toggle-btn.is-active,.lang-toggle-btn.is-active{background:var(--color-primary-muted,rgba(245,166,35,0.12));color:var(--color-primary);border-color:var(--color-primary)}', + '.lang-flag{font-weight:700;font-size:0.625rem;letter-spacing:0.04em}', '.sidebar__footer{padding:var(--space-3,12px) var(--space-4,16px);border-top:1px solid var(--color-border);display:flex;align-items:center;gap:var(--space-2,8px)}', '.sidebar__user-avatar{width:28px;height:28px;border-radius:50%;background:var(--color-primary);color:var(--color-text-inverse,#fff);display:flex;align-items:center;justify-content:center;font-size:0.6875rem;font-weight:700;flex-shrink:0}', @@ -124,7 +141,7 @@ '.sidebar__logout-btn:hover{color:var(--color-error,#F85149);border-color:var(--color-error,#F85149)}', '.pos-main-offset{margin-left:260px}', - '@media(max-width:768px){.pos-sidebar{width:56px}.brand-name,.nav-item span,.sidebar__user-info,.nav-section-label,.sidebar__theme-toggle{display:none}.sidebar__brand{justify-content:center;padding:12px 8px}.sidebar__footer{flex-direction:column;padding:8px}.pos-main-offset{margin-left:56px}}', + '@media(max-width:768px){.pos-sidebar{width:56px}.brand-name,.nav-item span,.sidebar__user-info,.nav-section-label,.sidebar__theme-toggle,.sidebar__lang-toggle{display:none}.sidebar__brand{justify-content:center;padding:12px 8px}.sidebar__footer{flex-direction:column;padding:8px}.pos-main-offset{margin-left:56px}}', ].join('\n'); document.head.appendChild(css); diff --git a/pos/templates/accounting.html b/pos/templates/accounting.html index 2548828..d6d15ed 100644 --- a/pos/templates/accounting.html +++ b/pos/templates/accounting.html @@ -2301,6 +2301,7 @@ + diff --git a/pos/templates/catalog.html b/pos/templates/catalog.html index 876a57f..cdacf9e 100644 --- a/pos/templates/catalog.html +++ b/pos/templates/catalog.html @@ -737,6 +737,7 @@ + diff --git a/pos/templates/config.html b/pos/templates/config.html index dcae0d5..c4ad92b 100644 --- a/pos/templates/config.html +++ b/pos/templates/config.html @@ -1702,6 +1702,44 @@ + +
+
+
+ +
+
+
Moneda
+
Configura la moneda y tipo de cambio para ventas
+
+
+ +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ @@ -1876,6 +1914,7 @@ @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } + diff --git a/pos/templates/customers.html b/pos/templates/customers.html index bbc35e2..c430dff 100644 --- a/pos/templates/customers.html +++ b/pos/templates/customers.html @@ -2147,6 +2147,7 @@ + diff --git a/pos/templates/fleet.html b/pos/templates/fleet.html index c947d85..9cb2664 100644 --- a/pos/templates/fleet.html +++ b/pos/templates/fleet.html @@ -962,6 +962,7 @@ + diff --git a/pos/templates/inventory.html b/pos/templates/inventory.html index f3e6be5..65dffbd 100644 --- a/pos/templates/inventory.html +++ b/pos/templates/inventory.html @@ -2525,6 +2525,7 @@ + diff --git a/pos/templates/invoicing.html b/pos/templates/invoicing.html index 29fd40f..6b6da01 100644 --- a/pos/templates/invoicing.html +++ b/pos/templates/invoicing.html @@ -2723,6 +2723,7 @@ + diff --git a/pos/templates/reports.html b/pos/templates/reports.html index d71c13d..4b12a74 100644 --- a/pos/templates/reports.html +++ b/pos/templates/reports.html @@ -1846,6 +1846,7 @@ + diff --git a/pos/templates/whatsapp.html b/pos/templates/whatsapp.html index f1c1a85..c041e1f 100644 --- a/pos/templates/whatsapp.html +++ b/pos/templates/whatsapp.html @@ -531,6 +531,7 @@ function posLogout(){localStorage.removeItem('pos_token');window.location.href=' +