feat(workshop): remove quality_check and add edit order modal
- Removed 'Control de calidad' from service order pipeline (VALID_TRANSITIONS, status labels, Kanban columns). - Added editable fields for customer, vehicle, branch, mechanic, priority, mileage, fuel level, estimated completion/cost and reception notes. - Added customer/vehicle autocomplete in the edit order modal.
This commit is contained in:
@@ -18,6 +18,10 @@ var Workshop = (function() {
|
||||
var currentOrder = null;
|
||||
var selectedInventoryItem = null;
|
||||
var itemSearchTimer = null;
|
||||
var customerSearchTimer = null;
|
||||
var selectedEditCustomer = null;
|
||||
var vehicleSearchTimer = null;
|
||||
var selectedEditVehicle = null;
|
||||
var currentView = 'list';
|
||||
var currentPage = 1;
|
||||
var perPage = 25;
|
||||
@@ -35,7 +39,6 @@ var Workshop = (function() {
|
||||
{key: 'diagnosis', label: 'Diagnóstico'},
|
||||
{key: 'waiting_parts', label: 'Espera refacciones'},
|
||||
{key: 'repair', label: 'En reparación'},
|
||||
{key: 'quality_check', label: 'Control calidad'},
|
||||
{key: 'ready', label: 'Listo'},
|
||||
{key: 'delivered', label: 'Entregado'},
|
||||
];
|
||||
@@ -45,7 +48,6 @@ var Workshop = (function() {
|
||||
diagnosis: 'Diagnóstico',
|
||||
waiting_parts: 'Espera refacciones',
|
||||
repair: 'En reparación',
|
||||
quality_check: 'Control calidad',
|
||||
ready: 'Listo',
|
||||
delivered: 'Entregado',
|
||||
cancelled: 'Cancelado'
|
||||
@@ -55,8 +57,7 @@ var Workshop = (function() {
|
||||
received: ['diagnosis', 'cancelled'],
|
||||
diagnosis: ['waiting_parts', 'repair', 'cancelled'],
|
||||
waiting_parts: ['repair', 'cancelled'],
|
||||
repair: ['quality_check', 'cancelled'],
|
||||
quality_check: ['ready', 'cancelled'],
|
||||
repair: ['ready', 'cancelled'],
|
||||
ready: ['delivered', 'cancelled'],
|
||||
delivered: [],
|
||||
cancelled: []
|
||||
@@ -100,6 +101,11 @@ var Workshop = (function() {
|
||||
return el.innerHTML;
|
||||
}
|
||||
|
||||
function escJs(s) {
|
||||
if (s == null) return '';
|
||||
return String(s).replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
function api(method, url, body) {
|
||||
var opts = {method: method, headers: headers()};
|
||||
if (body) opts.body = JSON.stringify(body);
|
||||
@@ -414,6 +420,7 @@ var Workshop = (function() {
|
||||
'</div>' : '';
|
||||
footer.innerHTML = statusHtml +
|
||||
'<button class="btn btn--ghost" onclick="Workshop.closeDetailModal()">Cerrar</button>' +
|
||||
(canEdit ? '<button class="btn btn--secondary" onclick="Workshop.openEditOrderModal()">Editar orden</button>' : '') +
|
||||
(canDelete ? '<button class="btn btn--danger" onclick="Workshop.deleteOrder()">Eliminar orden</button>' : '') +
|
||||
'<button class="btn btn--secondary" onclick="Workshop.printOrder()">' +
|
||||
'<svg viewBox="0 0 24 24"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg>' +
|
||||
@@ -528,6 +535,175 @@ var Workshop = (function() {
|
||||
currentOrder = null;
|
||||
}
|
||||
|
||||
function openEditOrderModal() {
|
||||
if (!currentOrder) return;
|
||||
populateEditOrderModal();
|
||||
document.getElementById('editOrderModal').classList.add('is-open');
|
||||
}
|
||||
|
||||
function closeEditOrderModal() {
|
||||
document.getElementById('editOrderModal').classList.remove('is-open');
|
||||
selectedEditCustomer = null;
|
||||
selectedEditVehicle = null;
|
||||
}
|
||||
|
||||
function toDatetimeLocal(d) {
|
||||
if (!d) return '';
|
||||
var date = new Date(d);
|
||||
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
|
||||
return date.toISOString().slice(0, 16);
|
||||
}
|
||||
|
||||
async function populateEditOrderModal() {
|
||||
var o = currentOrder;
|
||||
selectedEditCustomer = o.customer_id ? {id: o.customer_id, name: o.customer_name || ''} : null;
|
||||
selectedEditVehicle = o.vehicle_id ? {id: o.vehicle_id, label: (o.vehicle_plate || '') + ' ' + (o.vehicle_make || '') + ' ' + (o.vehicle_model || '')} : null;
|
||||
|
||||
document.getElementById('eoCustomerSearch').value = selectedEditCustomer ? selectedEditCustomer.name : '';
|
||||
document.getElementById('eoCustomerId').value = selectedEditCustomer ? selectedEditCustomer.id : '';
|
||||
document.getElementById('eoVehicleSearch').value = selectedEditVehicle ? selectedEditVehicle.label.trim() : '';
|
||||
document.getElementById('eoVehicleId').value = selectedEditVehicle ? selectedEditVehicle.id : '';
|
||||
|
||||
// Branches
|
||||
var branchSel = document.getElementById('eoBranch');
|
||||
branchSel.innerHTML = branches.map(function(b) {
|
||||
return '<option value="' + b.id + '"' + (b.id === o.branch_id ? ' selected' : '') + '>' + esc(b.name) + '</option>';
|
||||
}).join('');
|
||||
|
||||
// Mechanics/employees
|
||||
var mechSel = document.getElementById('eoMechanic');
|
||||
mechSel.innerHTML = '<option value="">— Ninguno —</option>';
|
||||
try {
|
||||
var res = await fetch('/pos/api/config/employees', {headers: headers()});
|
||||
var json = await res.json();
|
||||
(json.data || []).forEach(function(e) {
|
||||
if (!e.is_active) return;
|
||||
mechSel.innerHTML += '<option value="' + e.id + '"' + (e.id === o.employee_id ? ' selected' : '') + '>' + esc(e.name) + '</option>';
|
||||
});
|
||||
} catch (e) {}
|
||||
|
||||
document.getElementById('eoPriority').value = o.priority || 'normal';
|
||||
document.getElementById('eoFuelLevel').value = o.fuel_level || '';
|
||||
document.getElementById('eoMileageIn').value = o.mileage_in != null ? o.mileage_in : '';
|
||||
document.getElementById('eoMileageOut').value = o.mileage_out != null ? o.mileage_out : '';
|
||||
document.getElementById('eoEstimatedCompletion').value = toDatetimeLocal(o.estimated_completion);
|
||||
document.getElementById('eoEstimatedCost').value = o.estimated_cost != null ? o.estimated_cost : '';
|
||||
document.getElementById('eoNotes').value = o.reception_notes || '';
|
||||
}
|
||||
|
||||
function hideEditSearchResults(type) {
|
||||
var box = document.getElementById(type === 'customer' ? 'eoCustomerResults' : 'eoVehicleResults');
|
||||
if (box) box.style.display = 'none';
|
||||
}
|
||||
|
||||
function searchCustomersForSO() {
|
||||
var input = document.getElementById('eoCustomerSearch');
|
||||
var box = document.getElementById('eoCustomerResults');
|
||||
var q = input.value.trim();
|
||||
selectedEditCustomer = null;
|
||||
document.getElementById('eoCustomerId').value = '';
|
||||
if (!q || q.length < 2) {
|
||||
box.style.display = 'none'; box.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
clearTimeout(customerSearchTimer);
|
||||
customerSearchTimer = setTimeout(function() {
|
||||
fetch('/pos/api/customers?q=' + encodeURIComponent(q) + '&per_page=20', {headers: headers()})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(d) {
|
||||
var items = d.data || [];
|
||||
if (!items.length) {
|
||||
box.innerHTML = '<div style="padding:var(--space-2);color:var(--color-text-muted);">Sin resultados</div>';
|
||||
box.style.display = 'block'; return;
|
||||
}
|
||||
box.innerHTML = items.map(function(c) {
|
||||
return '<div class="so-search-result" style="padding:var(--space-2);cursor:pointer;border-bottom:1px solid var(--color-border);" onclick="Workshop.selectEditCustomer(' + c.id + ', \'' + escJs(c.name) + '\')">' +
|
||||
'<strong>' + esc(c.name) + '</strong>' +
|
||||
'<small>' + esc(c.phone || '') + ' · ' + esc(c.rfc || '') + '</small>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
box.style.display = 'block';
|
||||
})
|
||||
.catch(function() { box.style.display = 'none'; });
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function selectEditCustomer(id, name) {
|
||||
selectedEditCustomer = {id: id, name: name};
|
||||
document.getElementById('eoCustomerSearch').value = name;
|
||||
document.getElementById('eoCustomerId').value = id;
|
||||
hideEditSearchResults('customer');
|
||||
}
|
||||
|
||||
function searchVehiclesForSO() {
|
||||
var input = document.getElementById('eoVehicleSearch');
|
||||
var box = document.getElementById('eoVehicleResults');
|
||||
var q = input.value.trim();
|
||||
selectedEditVehicle = null;
|
||||
document.getElementById('eoVehicleId').value = '';
|
||||
if (!q || q.length < 2) {
|
||||
box.style.display = 'none'; box.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
clearTimeout(vehicleSearchTimer);
|
||||
vehicleSearchTimer = setTimeout(function() {
|
||||
fetch('/pos/api/fleet/vehicles?q=' + encodeURIComponent(q) + '&per_page=20&active_only=true', {headers: headers()})
|
||||
.then(function(r) { return r.json(); })
|
||||
.then(function(d) {
|
||||
var items = d.data || [];
|
||||
if (!items.length) {
|
||||
box.innerHTML = '<div style="padding:var(--space-2);color:var(--color-text-muted);">Sin resultados</div>';
|
||||
box.style.display = 'block'; return;
|
||||
}
|
||||
box.innerHTML = items.map(function(v) {
|
||||
var label = (v.plate || '') + ' · ' + (v.make || '') + ' ' + (v.model || '');
|
||||
return '<div class="so-search-result" style="padding:var(--space-2);cursor:pointer;border-bottom:1px solid var(--color-border);" onclick="Workshop.selectEditVehicle(' + v.id + ', \'' + escJs(label) + '\')">' +
|
||||
'<strong>' + esc(v.plate || '') + '</strong>' +
|
||||
'<small>' + esc(v.make || '') + ' ' + esc(v.model || '') + ' · ' + esc(v.owner_name || '') + '</small>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
box.style.display = 'block';
|
||||
})
|
||||
.catch(function() { box.style.display = 'none'; });
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function selectEditVehicle(id, label) {
|
||||
selectedEditVehicle = {id: id, label: label};
|
||||
document.getElementById('eoVehicleSearch').value = label;
|
||||
document.getElementById('eoVehicleId').value = id;
|
||||
hideEditSearchResults('vehicle');
|
||||
}
|
||||
|
||||
async function saveOrderChanges() {
|
||||
if (!currentOrderId) return;
|
||||
var customerId = selectedEditCustomer ? selectedEditCustomer.id : parseInt(document.getElementById('eoCustomerId').value, 10) || null;
|
||||
var vehicleId = selectedEditVehicle ? selectedEditVehicle.id : parseInt(document.getElementById('eoVehicleId').value, 10) || null;
|
||||
var payload = {
|
||||
customer_id: customerId,
|
||||
vehicle_id: vehicleId,
|
||||
branch_id: parseInt(document.getElementById('eoBranch').value, 10) || null,
|
||||
employee_id: parseInt(document.getElementById('eoMechanic').value, 10) || null,
|
||||
priority: document.getElementById('eoPriority').value,
|
||||
fuel_level: document.getElementById('eoFuelLevel').value || null,
|
||||
mileage_in: document.getElementById('eoMileageIn').value ? parseInt(document.getElementById('eoMileageIn').value, 10) : null,
|
||||
mileage_out: document.getElementById('eoMileageOut').value ? parseInt(document.getElementById('eoMileageOut').value, 10) : null,
|
||||
estimated_completion: document.getElementById('eoEstimatedCompletion').value || null,
|
||||
estimated_cost: document.getElementById('eoEstimatedCost').value ? parseFloat(document.getElementById('eoEstimatedCost').value) : null,
|
||||
reception_notes: document.getElementById('eoNotes').value
|
||||
};
|
||||
try {
|
||||
await api('PUT', '/' + currentOrderId, payload);
|
||||
toast('Orden actualizada');
|
||||
closeEditOrderModal();
|
||||
closeDetailModal();
|
||||
loadSummary();
|
||||
loadOrders();
|
||||
} catch (e) {
|
||||
alert('Error: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Actions ───
|
||||
|
||||
function changeStatus() {
|
||||
@@ -930,6 +1106,13 @@ var Workshop = (function() {
|
||||
closeCatalogModal: closeCatalogModal,
|
||||
addCatalogItem: addCatalogItem,
|
||||
deleteCatalogItem: deleteCatalogItem,
|
||||
openEditOrderModal: openEditOrderModal,
|
||||
closeEditOrderModal: closeEditOrderModal,
|
||||
saveOrderChanges: saveOrderChanges,
|
||||
selectEditCustomer: selectEditCustomer,
|
||||
selectEditVehicle: selectEditVehicle,
|
||||
searchCustomersForSO: searchCustomersForSO,
|
||||
searchVehiclesForSO: searchVehiclesForSO,
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user