- i18n.js with 130+ translation keys for es/en, loaded in all 11 templates - sidebar.js uses t() for all nav labels, adds MX/US language toggle - app-init.js role labels use i18n - currency.py service with convert() and format_currency() - config.py adds DEFAULT_CURRENCY and EXCHANGE_RATE_USD_MXN settings - config_bp.py adds GET/PUT /pos/api/config/currency endpoints - config.html adds currency/exchange-rate section (Section 8) - config.js adds loadCurrency/saveCurrency with localStorage sync - pos.js fmt() reads pos_currency from localStorage for USD/MXN display Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
};
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user