87bbf158a4
- InventoryController: extract RecordInventoryUsageAsync helper; both LogUsage (scan page) and LogMaterial (jobs modal, moved from JobsController) call it — no more duplicate save/GL logic across two controllers - Log Material modal: replace radio buttons with prominent toggle buttons so the active mode (Amount Used vs Amount Remaining) is always visually obvious; add always-visible preview line showing exactly what will be logged before saving - Edit Usage modal: add quantity field (pre-populated from existing transaction) with delta adjustment to InventoryItem.QuantityOnHand on save; include completed/terminal jobs in the dropdown so entries can be corrected after a job is marked done - Scan page job picker: include jobs completed within the last 7 days (marked with '(completed)') so usage can be logged after a job is finished Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
85 lines
3.4 KiB
JavaScript
85 lines
3.4 KiB
JavaScript
// inventory-ledger.js — Edit Usage Record modal logic
|
|
|
|
async function openUsageEdit(transactionId) {
|
|
const modal = new bootstrap.Modal(document.getElementById('editUsageModal'));
|
|
const loading = document.getElementById('editUsageLoading');
|
|
const form = document.getElementById('editUsageForm');
|
|
const saveBtn = document.getElementById('euSaveBtn');
|
|
|
|
loading.classList.remove('d-none');
|
|
form.classList.add('d-none');
|
|
saveBtn.disabled = true;
|
|
modal.show();
|
|
|
|
try {
|
|
const resp = await fetch(`/Inventory/GetUsageForEdit?id=${transactionId}`);
|
|
if (!resp.ok) throw new Error('Failed to load usage record.');
|
|
const data = await resp.json();
|
|
|
|
document.getElementById('euTxnId').value = data.transactionId;
|
|
document.getElementById('euItemName').textContent = data.itemName || '—';
|
|
document.getElementById('euQuantity').value = data.quantity != null ? parseFloat(data.quantity).toFixed(4) : '';
|
|
document.getElementById('euDate').value = data.transactionDate;
|
|
document.getElementById('euNotes').value = data.notes || '';
|
|
|
|
const jobSel = document.getElementById('euJobId');
|
|
jobSel.innerHTML = '<option value="">— No job —</option>';
|
|
(data.jobs || []).forEach(j => {
|
|
const opt = document.createElement('option');
|
|
opt.value = j.id;
|
|
opt.textContent = `${j.jobNumber} — ${j.customerName}`;
|
|
if (j.id === data.jobId) opt.selected = true;
|
|
jobSel.appendChild(opt);
|
|
});
|
|
|
|
loading.classList.add('d-none');
|
|
form.classList.remove('d-none');
|
|
saveBtn.disabled = false;
|
|
} catch (e) {
|
|
loading.innerHTML = `<div class="text-danger"><i class="bi bi-exclamation-triangle me-1"></i>${e.message}</div>`;
|
|
}
|
|
}
|
|
|
|
document.getElementById('euSaveBtn').addEventListener('click', async () => {
|
|
const form = document.getElementById('editUsageForm');
|
|
if (!form.reportValidity()) return;
|
|
|
|
const saveBtn = document.getElementById('euSaveBtn');
|
|
const spinner = document.getElementById('euSaveBtnSpinner');
|
|
const btnText = document.getElementById('euSaveBtnText');
|
|
|
|
saveBtn.disabled = true;
|
|
spinner.classList.remove('d-none');
|
|
btnText.textContent = 'Saving…';
|
|
|
|
const token = form.querySelector('input[name="__RequestVerificationToken"]')?.value;
|
|
const params = new URLSearchParams({
|
|
id: document.getElementById('euTxnId').value,
|
|
quantity: document.getElementById('euQuantity').value,
|
|
jobId: document.getElementById('euJobId').value,
|
|
notes: document.getElementById('euNotes').value,
|
|
transactionDate: document.getElementById('euDate').value,
|
|
__RequestVerificationToken: token || ''
|
|
});
|
|
|
|
try {
|
|
const resp = await fetch('/Inventory/EditUsageTransaction', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: params.toString()
|
|
});
|
|
const result = await resp.json();
|
|
if (result.success) {
|
|
bootstrap.Modal.getInstance(document.getElementById('editUsageModal')).hide();
|
|
location.reload();
|
|
} else {
|
|
throw new Error('Save failed.');
|
|
}
|
|
} catch (e) {
|
|
saveBtn.disabled = false;
|
|
spinner.classList.add('d-none');
|
|
btnText.textContent = 'Save Changes';
|
|
alert('Error saving changes: ' + e.message);
|
|
}
|
|
});
|