diff --git a/pos/blueprints/config_bp.py b/pos/blueprints/config_bp.py index 4c7ec0c..5e56a88 100644 --- a/pos/blueprints/config_bp.py +++ b/pos/blueprints/config_bp.py @@ -312,6 +312,35 @@ def update_employee(emp_id): return jsonify({'ok': True, 'message': 'Employee updated'}) +@config_bp.route('/employees/', methods=['DELETE']) +@require_auth('config.edit') +def delete_employee(emp_id): + """Soft-delete (deactivate) an employee. Owners cannot be deleted via UI + to prevent locking out the tenant; use direct DB access if really needed.""" + conn = get_tenant_conn(g.tenant_id) + cur = conn.cursor() + + cur.execute("SELECT role FROM employees WHERE id = %s", (emp_id,)) + row = cur.fetchone() + if not row: + cur.close(); conn.close() + return jsonify({'error': 'Employee not found'}), 404 + + if row[0] == 'owner': + cur.close(); conn.close() + return jsonify({'error': 'No se puede eliminar una cuenta de dueno'}), 403 + + cur.execute("UPDATE employees SET is_active = false WHERE id = %s", (emp_id,)) + + from services.audit import log_action + log_action(conn, 'EMPLOYEE_DEACTIVATE', 'employee', emp_id) + + conn.commit() + cur.close() + conn.close() + return jsonify({'ok': True, 'message': 'Employee deactivated'}) + + @config_bp.route('/currency', methods=['GET']) @require_auth() def get_currency(): diff --git a/pos/static/js/config.js b/pos/static/js/config.js index 92d0070..8f597cf 100644 --- a/pos/static/js/config.js +++ b/pos/static/js/config.js @@ -298,7 +298,10 @@ const Config = (() => { + '' + escHtml(emp.branch_name || 'Todas') + '' + '' + statusBadge + '' + '' + (emp.max_discount_pct || 0) + '%' - + '' + + '' + + '' + + (emp.role !== 'owner' ? ' ' : '') + + '' + ''; }); @@ -362,6 +365,21 @@ const Config = (() => { return el ? el.value.trim() : ''; } + async function deleteEmployee(empId, name) { + if (!confirm('¿Eliminar al empleado "' + name + '"? Esta accion lo desactiva.')) return; + try { + var res = await fetch(API + '/employees/' + empId, { method: 'DELETE', headers: headers() }); + if (!res.ok) { + var err = await res.json().catch(function() { return { error: 'Error ' + res.status }; }); + throw new Error(err.error || 'Error al eliminar'); + } + toast('Empleado eliminado', 'ok'); + loadEmployees(); + } catch (e) { + toast(e.message, 'error'); + } + } + async function editEmployee(empId) { if (!checkAuth()) return; // Find the employee in the loaded data by re-fetching @@ -1028,7 +1046,7 @@ const Config = (() => { return { init, setTheme, selectThemeOption, loadAllowedBrands, saveAllowedBrands, - loadBranches, loadEmployees, saveBranch, saveEmployee, editEmployee, + loadBranches, loadEmployees, saveBranch, saveEmployee, editEmployee, deleteEmployee, loadBusiness, saveBusiness, saveTaxParams, saveAll, loadCurrency, saveCurrency, loadVehicleCompatSource, saveVehicleCompatSource,