piccoli fix
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
let currentUser = null;
|
||||
let offices = [];
|
||||
let currentOfficeId = null;
|
||||
let currentOffice = null;
|
||||
let officeUsers = [];
|
||||
let currentWeeklyClosingDays = [];
|
||||
|
||||
@@ -20,6 +21,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
populateHourSelect();
|
||||
await loadOffices();
|
||||
setupEventListeners();
|
||||
});
|
||||
@@ -73,6 +75,27 @@ async function loadOfficeRules(officeId) {
|
||||
document.getElementById('rulesContent').style.display = 'block';
|
||||
document.getElementById('noOfficeMessage').style.display = 'none';
|
||||
|
||||
// Load full office object for algorithm settings
|
||||
try {
|
||||
const response = await api.get(`/api/offices/${officeId}`);
|
||||
if (response && response.ok) {
|
||||
currentOffice = await response.json();
|
||||
// Populate algorithm form
|
||||
const modeSelect = document.getElementById('assignmentModeSelect');
|
||||
if (currentOffice.booking_window_enabled === false) {
|
||||
modeSelect.value = 'realtime';
|
||||
} else {
|
||||
modeSelect.value = currentOffice.assignment_mode || 'random';
|
||||
}
|
||||
|
||||
document.getElementById('bookingWindowHour').value = currentOffice.booking_window_end_hour ?? 18;
|
||||
document.getElementById('bookingWindowMinute').value = currentOffice.booking_window_end_minute ?? 0;
|
||||
updateAlgorithmVisibility();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error loading office details:", e);
|
||||
}
|
||||
|
||||
// Load users for this office (for dropdowns)
|
||||
await loadOfficeUsers(officeId);
|
||||
|
||||
@@ -91,6 +114,67 @@ async function loadOfficeUsers(officeId) {
|
||||
}
|
||||
}
|
||||
|
||||
function populateHourSelect() {
|
||||
const hourSelect = document.getElementById('bookingWindowHour');
|
||||
const minuteSelect = document.getElementById('bookingWindowMinute');
|
||||
if (!hourSelect || !minuteSelect) return;
|
||||
|
||||
hourSelect.innerHTML = '';
|
||||
for (let h = 0; h < 24; h++) {
|
||||
const option = document.createElement('option');
|
||||
option.value = h;
|
||||
option.textContent = h.toString().padStart(2, '0');
|
||||
hourSelect.appendChild(option);
|
||||
}
|
||||
|
||||
minuteSelect.innerHTML = '';
|
||||
for (let m = 0; m < 60; m++) {
|
||||
const option = document.createElement('option');
|
||||
option.value = m;
|
||||
option.textContent = m.toString().padStart(2, '0');
|
||||
minuteSelect.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
function updateAlgorithmVisibility() {
|
||||
const mode = document.getElementById('assignmentModeSelect').value;
|
||||
const group = document.getElementById('cutoffTimeGroup');
|
||||
if (group) group.style.display = (mode === 'realtime') ? 'none' : 'block';
|
||||
}
|
||||
|
||||
async function saveAlgorithmSettings(e) {
|
||||
e.preventDefault();
|
||||
if (!currentOfficeId) return;
|
||||
|
||||
const btn = e.target.querySelector('button[type="submit"]');
|
||||
const originalText = btn.textContent;
|
||||
btn.disabled = true;
|
||||
btn.textContent = 'Salvataggio...';
|
||||
|
||||
const mode = document.getElementById('assignmentModeSelect').value;
|
||||
|
||||
const data = {
|
||||
assignment_mode: mode === 'realtime' ? 'random' : mode,
|
||||
booking_window_enabled: mode !== 'realtime',
|
||||
booking_window_end_hour: parseInt(document.getElementById('bookingWindowHour').value),
|
||||
booking_window_end_minute: parseInt(document.getElementById('bookingWindowMinute').value)
|
||||
};
|
||||
|
||||
try {
|
||||
const res = await api.put(`/api/offices/${currentOfficeId}`, data);
|
||||
if (res) {
|
||||
utils.showMessage('Impostazioni algoritmo salvate', 'success');
|
||||
currentOffice = res;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
utils.showMessage('Errore nel salvataggio impostazioni', 'error');
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
btn.textContent = originalText;
|
||||
}
|
||||
}
|
||||
|
||||
// Weekly Closing Days
|
||||
async function loadWeeklyClosingDays(officeId) {
|
||||
const response = await api.get(`/api/offices/${officeId}/weekly-closing-days`);
|
||||
@@ -426,6 +510,230 @@ function setupEventListeners() {
|
||||
notes: document.getElementById('exclusionNotes').value || null
|
||||
});
|
||||
});
|
||||
|
||||
// Algorithm settings events
|
||||
document.getElementById('assignmentModeSelect').addEventListener('change', updateAlgorithmVisibility);
|
||||
document.getElementById('algorithmForm').addEventListener('submit', saveAlgorithmSettings);
|
||||
|
||||
// Test Tools Logic
|
||||
// Set default date to tomorrow
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
const testDateStart = document.getElementById('testDateStart');
|
||||
if (testDateStart) testDateStart.valueAsDate = tomorrow;
|
||||
|
||||
document.getElementById('runAllocationBtn').addEventListener('click', async () => {
|
||||
if (!confirm('Sei sicuro di voler avviare l\'assegnazione ORA? Questo potrebbe sovrascrivere le assegnazioni esistenti per la data selezionata.')) return;
|
||||
|
||||
const dateStart = document.getElementById('testDateStart').value;
|
||||
const dateEnd = document.getElementById('testDateEnd').value;
|
||||
|
||||
if (!dateStart) return utils.showMessage('Seleziona una data di inizio', 'error');
|
||||
|
||||
let start = new Date(dateStart);
|
||||
let end = dateEnd ? new Date(dateEnd) : new Date(dateStart);
|
||||
|
||||
if (end < start) {
|
||||
return utils.showMessage('La data di fine deve essere successiva alla data di inizio', 'error');
|
||||
}
|
||||
|
||||
let current = new Date(start);
|
||||
let successCount = 0;
|
||||
let errorCount = 0;
|
||||
|
||||
utils.showMessage('Avvio assegnazione...', 'success');
|
||||
|
||||
while (current <= end) {
|
||||
const dateStr = utils.formatDate(current);
|
||||
try {
|
||||
await api.post('/api/parking/run-allocation', {
|
||||
date: dateStr,
|
||||
office_id: currentOfficeId
|
||||
});
|
||||
successCount++;
|
||||
} catch (e) {
|
||||
console.error(`Error for ${dateStr}`, e);
|
||||
errorCount++;
|
||||
}
|
||||
current.setDate(current.getDate() + 1);
|
||||
}
|
||||
|
||||
if (errorCount === 0) {
|
||||
utils.showMessage(`Assegnazione completata per ${successCount} giorni.`, 'success');
|
||||
} else {
|
||||
utils.showMessage(`Completato con errori: ${successCount} successi, ${errorCount} errori.`, 'warning');
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('clearAssignmentsBtn').addEventListener('click', async () => {
|
||||
if (!confirm('ATTENZIONE: Stai per eliminare TUTTE le assegnazioni per il periodo selezionato. Procedere?')) return;
|
||||
|
||||
const dateStart = document.getElementById('testDateStart').value;
|
||||
const dateEnd = document.getElementById('testDateEnd').value;
|
||||
|
||||
if (!dateStart) return utils.showMessage('Seleziona una data di inizio', 'error');
|
||||
|
||||
let start = new Date(dateStart);
|
||||
let end = dateEnd ? new Date(dateEnd) : new Date(dateStart);
|
||||
|
||||
if (end < start) {
|
||||
return utils.showMessage('La data di fine deve essere successiva alla data di inizio', 'error');
|
||||
}
|
||||
|
||||
let current = new Date(start);
|
||||
let totalRemoved = 0;
|
||||
|
||||
utils.showMessage('Rimozione in corso...', 'warning');
|
||||
|
||||
while (current <= end) {
|
||||
const dateStr = utils.formatDate(current);
|
||||
try {
|
||||
const res = await api.post('/api/parking/clear-assignments', {
|
||||
date: dateStr,
|
||||
office_id: currentOfficeId
|
||||
});
|
||||
if (res && res.ok) {
|
||||
const data = await res.json();
|
||||
totalRemoved += (data.count || 0);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`Error clearing ${dateStr}`, e);
|
||||
}
|
||||
current.setDate(current.getDate() + 1);
|
||||
}
|
||||
|
||||
utils.showMessage(`Operazione eseguita.`, 'warning');
|
||||
});
|
||||
|
||||
const clearPresenceBtn = document.getElementById('clearPresenceBtn');
|
||||
if (clearPresenceBtn) {
|
||||
clearPresenceBtn.addEventListener('click', async () => {
|
||||
if (!confirm('ATTENZIONE: Stai per eliminare TUTTI GLI STATI (Presente/Assente/ecc) e relative assegnazioni per tutti gli utenti del gruppo nel periodo selezionato. \n\nQuesta azione è irreversibile. Procedere?')) return;
|
||||
|
||||
const dateStart = document.getElementById('testDateStart').value;
|
||||
const dateEnd = document.getElementById('testDateEnd').value;
|
||||
|
||||
if (!dateStart) return utils.showMessage('Seleziona una data di inizio', 'error');
|
||||
|
||||
// Validate office
|
||||
if (!currentOfficeId) {
|
||||
return utils.showMessage('Errore: Nessun gruppo selezionato', 'error');
|
||||
}
|
||||
|
||||
const endDateVal = dateEnd || dateStart;
|
||||
|
||||
utils.showMessage('Rimozione stati in corso...', 'warning');
|
||||
|
||||
try {
|
||||
const res = await api.post('/api/presence/admin/clear-office-presence', {
|
||||
start_date: dateStart,
|
||||
end_date: endDateVal,
|
||||
office_id: currentOfficeId
|
||||
});
|
||||
|
||||
if (res && res.ok) {
|
||||
const data = await res.json();
|
||||
utils.showMessage(`Operazione completata. Rimossi ${data.count_presence} stati e ${data.count_parking} assegnazioni.`, 'success');
|
||||
} else {
|
||||
const err = await res.json();
|
||||
utils.showMessage('Errore: ' + (err.detail || 'Operazione fallita'), 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
utils.showMessage('Errore di comunicazione col server', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const testEmailBtn = document.getElementById('testEmailBtn');
|
||||
if (testEmailBtn) {
|
||||
testEmailBtn.addEventListener('click', async () => {
|
||||
const dateVal = document.getElementById('testEmailDate').value;
|
||||
|
||||
// Validate office
|
||||
if (!currentOfficeId) {
|
||||
return utils.showMessage('Errore: Nessun gruppo selezionato', 'error');
|
||||
}
|
||||
|
||||
utils.showMessage('Invio mail di test in corso...', 'warning');
|
||||
|
||||
try {
|
||||
const res = await api.post('/api/parking/test-email', {
|
||||
date: dateVal || null,
|
||||
office_id: currentOfficeId
|
||||
});
|
||||
|
||||
if (res && res.status >= 200 && res.status < 300) {
|
||||
const data = await res.json();
|
||||
|
||||
if (data.success) {
|
||||
let msg = `Email inviata con successo per la data: ${data.date}.`;
|
||||
if (data.mode === 'FILE') {
|
||||
msg += ' (SMTP disabilitato: Loggato su file)';
|
||||
}
|
||||
utils.showMessage(msg, 'success');
|
||||
} else {
|
||||
utils.showMessage('Invio fallito. Controlla i log del server.', 'error');
|
||||
}
|
||||
} else {
|
||||
const err = res ? await res.json() : {};
|
||||
console.error("Test Email Error:", err);
|
||||
const errMsg = err.detail ? (typeof err.detail === 'object' ? JSON.stringify(err.detail) : err.detail) : 'Invio fallito';
|
||||
utils.showMessage('Errore: ' + errMsg, 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
utils.showMessage('Errore di comunicazione col server', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const bulkEmailBtn = document.getElementById('bulkEmailBtn');
|
||||
if (bulkEmailBtn) {
|
||||
bulkEmailBtn.addEventListener('click', async () => {
|
||||
const dateVal = document.getElementById('testEmailDate').value;
|
||||
|
||||
// Validate office
|
||||
if (!currentOfficeId) {
|
||||
return utils.showMessage('Errore: Nessun gruppo selezionato', 'error');
|
||||
}
|
||||
|
||||
if (!dateVal) {
|
||||
return utils.showMessage('Per il test a TUTTI è obbligatorio selezionare una data specifica.', 'error');
|
||||
}
|
||||
|
||||
if (!confirm(`Sei sicuro di voler inviare una mail di promemoria a TUTTI gli utenti con parcheggio assegnato per il giorno ${dateVal}?\n\nQuesta azione invierà vere email.`)) return;
|
||||
|
||||
utils.showMessage('Invio mail massive in corso...', 'warning');
|
||||
|
||||
try {
|
||||
const res = await api.post('/api/parking/test-email', {
|
||||
date: dateVal,
|
||||
office_id: currentOfficeId,
|
||||
bulk_send: true
|
||||
});
|
||||
|
||||
if (res && res.status >= 200 && res.status < 300) {
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
let msg = `Processo completato per il ${data.date}. Inviate: ${data.count || 0}, Fallite: ${data.failed || 0}.`;
|
||||
if (data.mode === 'BULK' && (data.count || 0) === 0) msg += " (Nessun assegnatario trovato)";
|
||||
utils.showMessage(msg, 'success');
|
||||
} else {
|
||||
utils.showMessage('Errore durante l\'invio.', 'error');
|
||||
}
|
||||
} else {
|
||||
const err = res ? await res.json() : {};
|
||||
console.error("Bulk Test Email Error:", err);
|
||||
const errMsg = err.detail ? (typeof err.detail === 'object' ? JSON.stringify(err.detail) : err.detail) : 'Invio fallito';
|
||||
utils.showMessage('Errore: ' + errMsg, 'error');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
utils.showMessage('Errore di comunicazione col server: ' + e.message, 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Global functions
|
||||
|
||||
Reference in New Issue
Block a user