Blank asset numbers, contested device claims, and honest toner forecasting
This commit is contained in:
@@ -437,6 +437,17 @@ def update_machine(machine_id: int):
|
||||
|
||||
asset = mach.asset
|
||||
|
||||
# An UPDATE may not blank the asset number. Create validates it and the
|
||||
# column is NOT NULL, but the conflict check below only runs when the value
|
||||
# DIFFERS, and '' never collides with anything - so a payload carrying an
|
||||
# empty assetnumber wrote it straight through. A form that loaded blank
|
||||
# (a failed reference load, a partial fetch) then saved the blank over a
|
||||
# real record.
|
||||
if 'assetnumber' in data and not (data['assetnumber'] or '').strip():
|
||||
return error_response(
|
||||
ErrorCodes.VALIDATION_ERROR,
|
||||
'assetnumber cannot be empty')
|
||||
|
||||
# Check for conflicting assetnumber
|
||||
if 'assetnumber' in data and data['assetnumber'] != asset.assetnumber:
|
||||
if Asset.query.filter_by(assetnumber=data['assetnumber']).first():
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
<div class="card">
|
||||
<div v-if="loading" class="loading">Loading...</div>
|
||||
|
||||
<!-- The record failed to load. Show the reason INSTEAD of the form: an
|
||||
empty edit form is indistinguishable from a record whose fields are
|
||||
genuinely empty, and saving it would write the blanks back. -->
|
||||
<div v-else-if="loadFailed" class="error-message">{{ error }}</div>
|
||||
|
||||
<form v-else @submit.prevent="saveMachine">
|
||||
<!-- Identity Section -->
|
||||
<h3 class="form-section-title">Identity</h3>
|
||||
@@ -425,6 +430,10 @@ const statuses = ref([])
|
||||
const vendors = ref([])
|
||||
const locations = ref([])
|
||||
const models = ref([])
|
||||
// Set when the record itself could not be loaded, as opposed to a reference
|
||||
// list failing. The form is withheld entirely, because an empty edit form is
|
||||
// indistinguishable from a record whose fields are genuinely empty.
|
||||
const loadFailed = ref(false)
|
||||
const businessunits = ref([])
|
||||
const pcs = ref([])
|
||||
const relationshipTypes = ref([])
|
||||
@@ -506,9 +515,29 @@ onMounted(async () => {
|
||||
relationshipTypeId.value = controlsType.relationshiptypeid
|
||||
}
|
||||
|
||||
// Load machine if editing
|
||||
// Load machine if editing.
|
||||
//
|
||||
// ITS OWN try/catch, deliberately. This used to sit inside the same block
|
||||
// as the eight reference loads above, so ONE transient failure among them -
|
||||
// a page of listAll() timing out on a busy collector cycle - rejected the
|
||||
// whole thing and rendered a fully editable EDIT form with every field
|
||||
// BLANK, including the required Asset Number, next to a Save button. Typing
|
||||
// a number and saving then wrote the blank-loaded values over a real
|
||||
// machine. The reference lists degrade to empty dropdowns; the record must
|
||||
// not degrade at all.
|
||||
if (isEdit.value) {
|
||||
const response = await machinesApi.get(route.params.id)
|
||||
let response
|
||||
try {
|
||||
response = await machinesApi.get(route.params.id)
|
||||
} catch (err) {
|
||||
console.error('Error loading machine:', err)
|
||||
error.value = 'Could not load this machine. Nothing has been changed - '
|
||||
+ 'reload the page rather than saving, or the blank form would '
|
||||
+ 'overwrite the record.'
|
||||
loadFailed.value = true
|
||||
loading.value = false
|
||||
return
|
||||
}
|
||||
const data = response.data.data
|
||||
currentAssetId.value = data.assetid || null
|
||||
currentMachine.value = data
|
||||
|
||||
Reference in New Issue
Block a user