Fix time entry workers, powder usage logging, inventory edit, and mojibake
- JobTimeEntry: migrate to UserId/UserDisplayName; make ShopWorkerId nullable (migration MigrateTimeEntriesToUserId) - Log Time modal: populate worker dropdown from Identity users instead of ShopWorkers; fix ShopMobile view same issue - Inventory Ledger: scan-based JobUsage transactions now appear in Powder Usage By Job tab (synthesized from InventoryTransaction) - Inventory Ledger: add Edit button for JobUsage transactions; new GetUsageForEdit + EditUsageTransaction endpoints; inventory-ledger.js - InventoryTransactionRepository: include Job.Customer for ledger queries - InventoryAiLookupService: handle JSON-LD @graph wrapper (Columbia Coatings / WooCommerce+Yoast); add HTML price snippet fallback - Fix mojibake in 9 views: â†' → →, âœ" → ✓, âš → ⚠ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
// 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('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,
|
||||
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);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user