Compare commits
4 Commits
deb74fd971
...
b97424554c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b97424554c | ||
|
|
de72a1fb9e | ||
|
|
caeefa5d61 | ||
|
|
ea403934d3 |
2
app.py
2
app.py
@@ -28,7 +28,7 @@ app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=1)
|
|||||||
|
|
||||||
|
|
||||||
# 1. Define the version
|
# 1. Define the version
|
||||||
APP_VERSION = '0.18.0'
|
APP_VERSION = '0.18.1'
|
||||||
|
|
||||||
# 2. Inject it into all templates automatically
|
# 2. Inject it into all templates automatically
|
||||||
@app.context_processor
|
@app.context_processor
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ def execute_pipeline(actions, barcode, context):
|
|||||||
|
|
||||||
placeholders = ', '.join(['?'] * len(cols))
|
placeholders = ', '.join(['?'] * len(cols))
|
||||||
sql = f"INSERT INTO {context['table_name']} ({', '.join(cols)}) VALUES ({placeholders})"
|
sql = f"INSERT INTO {context['table_name']} ({', '.join(cols)}) VALUES ({placeholders})"
|
||||||
execute_db(sql, vals)
|
new_id = execute_db(sql, vals)
|
||||||
|
|
||||||
return {'success': True, 'message': 'Saved Successfully', 'data': field_values}
|
return {'success': True, 'message': 'Saved Successfully', 'detail_id': new_id, 'data': field_values}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {'success': False, 'message': f"Database Error: {str(e)}", 'data': field_values}
|
return {'success': False, 'message': f"Database Error: {str(e)}", 'data': field_values}
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -109,6 +109,12 @@
|
|||||||
<i class="fa-solid fa-file-import"></i> Bulk Import Excel
|
<i class="fa-solid fa-file-import"></i> Bulk Import Excel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="scans-grid scan-header-row" style="--field-count: {{ detail_fields|length }};">
|
||||||
|
{% for field in detail_fields %}
|
||||||
|
<div class="scan-row-cell scan-col-header">{{ field.field_label }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
<div class="scan-row-cell scan-col-header">Status</div>
|
||||||
|
</div>
|
||||||
<div id="scansList" class="scans-grid" style="--field-count: {{ detail_fields|length }};">
|
<div id="scansList" class="scans-grid" style="--field-count: {{ detail_fields|length }};">
|
||||||
{% for scan in scans %}
|
{% for scan in scans %}
|
||||||
<div class="scan-row scan-row-{{ scan.duplicate_status }}"
|
<div class="scan-row scan-row-{{ scan.duplicate_status }}"
|
||||||
@@ -247,6 +253,7 @@ function processSmartScan(barcode, confirm = false) {
|
|||||||
|
|
||||||
// --- 1. HANDLE DUPLICATE CONFIRMATION ---
|
// --- 1. HANDLE DUPLICATE CONFIRMATION ---
|
||||||
if (data.needs_confirmation) {
|
if (data.needs_confirmation) {
|
||||||
|
playErrorBeep();
|
||||||
isSmartScan = true;
|
isSmartScan = true;
|
||||||
currentDupKeyValue = barcode;
|
currentDupKeyValue = barcode;
|
||||||
if (data.duplicate_status === 'dup_same_session') {
|
if (data.duplicate_status === 'dup_same_session') {
|
||||||
@@ -296,23 +303,23 @@ function processSmartScan(barcode, confirm = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- 3. STANDARD SUCCESS/FAIL ---
|
// --- 3. STANDARD SUCCESS/FAIL ---
|
||||||
if(smartInput) {
|
|
||||||
smartInput.value = '';
|
|
||||||
smartInput.focus();
|
|
||||||
}
|
|
||||||
feedbackArea.style.display = 'block';
|
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
feedbackArea.style.background = 'rgba(40, 167, 69, 0.2)';
|
if (data.detail_id && data.data) {
|
||||||
feedbackArea.style.border = '1px solid #28a745';
|
addScanToList(data.detail_id, data.data, data.data.duplicate_status);
|
||||||
feedbackText.style.color = '#28a745';
|
}
|
||||||
feedbackText.textContent = data.message;
|
feedbackArea.style.display = 'none';
|
||||||
if (data.message.includes('Saved')) setTimeout(() => location.reload(), 800);
|
if(smartInput) {
|
||||||
|
smartInput.value = '';
|
||||||
|
smartInput.focus();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
playErrorBeep();
|
||||||
|
feedbackArea.style.display = 'block';
|
||||||
feedbackArea.style.background = 'rgba(220, 53, 69, 0.2)';
|
feedbackArea.style.background = 'rgba(220, 53, 69, 0.2)';
|
||||||
feedbackArea.style.border = '1px solid #dc3545';
|
feedbackArea.style.border = '1px solid #dc3545';
|
||||||
feedbackText.style.color = '#dc3545';
|
feedbackText.style.color = '#dc3545';
|
||||||
feedbackText.textContent = data.message;
|
feedbackText.textContent = data.message;
|
||||||
|
if(smartInput) smartInput.focus();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@@ -320,7 +327,7 @@ function processSmartScan(barcode, confirm = false) {
|
|||||||
console.error(err); // Log it, don't popup alert to annoy user
|
console.error(err); // Log it, don't popup alert to annoy user
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Function to handle the "Save" click from the Details Modal
|
|
||||||
// Function to handle the "Save" click from the Details Modal
|
// Function to handle the "Save" click from the Details Modal
|
||||||
function saveSmartScanData() {
|
function saveSmartScanData() {
|
||||||
// 1. Validate we have the original barcode
|
// 1. Validate we have the original barcode
|
||||||
@@ -357,8 +364,12 @@ function saveSmartScanData() {
|
|||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
document.getElementById('fieldsModal').style.display = 'none';
|
document.getElementById('fieldsModal').style.display = 'none';
|
||||||
// Optional: Small delay to let the user see it worked
|
if (data.detail_id && data.data) {
|
||||||
setTimeout(() => location.reload(), 300);
|
addScanToList(data.detail_id, data.data, data.data.duplicate_status);
|
||||||
|
}
|
||||||
|
currentDupKeyValue = '';
|
||||||
|
smartInput.value = '';
|
||||||
|
smartInput.focus();
|
||||||
} else if (data.needs_input) {
|
} else if (data.needs_input) {
|
||||||
alert("Error: Please fill in all required fields.");
|
alert("Error: Please fill in all required fields.");
|
||||||
} else {
|
} else {
|
||||||
@@ -372,6 +383,25 @@ function resetSmartScan() {
|
|||||||
document.getElementById('smartScanner').focus();
|
document.getElementById('smartScanner').focus();
|
||||||
document.getElementById('routerFeedback').style.display = 'none';
|
document.getElementById('routerFeedback').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
// --- ERROR BEEP ---
|
||||||
|
function playErrorBeep() {
|
||||||
|
try {
|
||||||
|
const ctx = new (window.AudioContext || window.webkitAudioContext)();
|
||||||
|
const oscillator = ctx.createOscillator();
|
||||||
|
const gainNode = ctx.createGain();
|
||||||
|
oscillator.connect(gainNode);
|
||||||
|
gainNode.connect(ctx.destination);
|
||||||
|
oscillator.type = 'square';
|
||||||
|
oscillator.frequency.setValueAtTime(520, ctx.currentTime);
|
||||||
|
gainNode.gain.setValueAtTime(0.3, ctx.currentTime);
|
||||||
|
gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.4);
|
||||||
|
oscillator.start(ctx.currentTime);
|
||||||
|
oscillator.stop(ctx.currentTime + 0.4);
|
||||||
|
} catch(e) {
|
||||||
|
console.warn('Audio not available:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Standard variables
|
// Standard variables
|
||||||
let currentDupKeyValue = '';
|
let currentDupKeyValue = '';
|
||||||
let currentDuplicateStatus = '';
|
let currentDuplicateStatus = '';
|
||||||
|
|||||||
@@ -1303,9 +1303,25 @@ body {
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scan-header-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(var(--field-count), 1fr) auto;
|
||||||
|
gap: var(--space-md);
|
||||||
|
padding: var(--space-xs) var(--space-md);
|
||||||
|
max-height: none;
|
||||||
|
overflow-y: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-col-header {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
color: var(--color-text-muted);
|
||||||
|
}
|
||||||
.scan-row {
|
.scan-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr 1fr 1.5fr;
|
grid-template-columns: repeat(var(--field-count), 1fr) 1fr;
|
||||||
gap: var(--space-md);
|
gap: var(--space-md);
|
||||||
padding: var(--space-md);
|
padding: var(--space-md);
|
||||||
background: var(--color-bg);
|
background: var(--color-bg);
|
||||||
|
|||||||
Reference in New Issue
Block a user