Last active
January 24, 2025 11:28
-
-
Save erseco/5ff0850ecff7c8ea16a9862e473b5dea to your computer and use it in GitHub Desktop.
sicher
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Auto Fichaje SICHO | |
// @namespace https://gobiernodecanarias.net/ | |
// @version 1.3 | |
// @description Shows a floating panel to automate fichaje after detecting #thBienvenidaMensaje | |
// @match https://www3.gobiernodecanarias.net/aplicaciones/SICHO/* | |
// @updateURL https://gist.github.com/erseco/5ff0850ecff7c8ea16a9862e473b5dea/raw/6bae071265187149a84a8cf183074738fe164733/sicher.user.js | |
// @downloadURL https://gist.github.com/erseco/5ff0850ecff7c8ea16a9862e473b5dea/raw/6bae071265187149a84a8cf183074738fe164733/sicher.user.js | |
// @grant none | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
/** | |
* Detect if the user is on a mobile device by checking the user agent. | |
* This is a simple (and not always perfect) approach. | |
*/ | |
function isMobileDevice() { | |
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); | |
} | |
/** | |
* Creates and injects the floating panel in the DOM. | |
*/ | |
function createFichajePanel() { | |
const container = document.createElement('div'); | |
container.id = 'autoFichajePanel'; | |
// Position it at the bottom-right | |
container.style.position = 'fixed'; | |
container.style.bottom = '20px'; | |
container.style.right = '20px'; | |
container.style.zIndex = '99999'; | |
container.style.backgroundColor = '#f0f0f0'; | |
container.style.border = '2px solid #333'; | |
container.style.padding = '10px'; | |
container.style.fontFamily = 'sans-serif'; | |
container.style.boxShadow = '2px 2px 6px rgba(0,0,0,0.2)'; | |
// Slightly bigger for desktop, even bigger if mobile | |
if (isMobileDevice()) { | |
// If it's mobile, let's give it a bigger width | |
container.style.width = '300px'; | |
} else { | |
// Slightly bigger than 220px for desktop | |
container.style.width = '260px'; | |
} | |
// Close (X) button | |
const closeBtn = document.createElement('span'); | |
closeBtn.textContent = '✖'; | |
closeBtn.style.cursor = 'pointer'; | |
closeBtn.style.float = 'right'; | |
closeBtn.style.fontSize = '16px'; | |
closeBtn.style.marginBottom = '6px'; | |
closeBtn.addEventListener('click', () => { | |
container.remove(); | |
}); | |
container.appendChild(closeBtn); | |
// Title | |
const titleEl = document.createElement('p'); | |
titleEl.textContent = '¿Desea fichar automáticamente?'; | |
titleEl.style.margin = '0'; | |
titleEl.style.fontWeight = 'bold'; | |
titleEl.style.clear = 'both'; | |
container.appendChild(titleEl); | |
// Buttons | |
const buttonsWrapper = document.createElement('div'); | |
buttonsWrapper.style.marginTop = '8px'; | |
buttonsWrapper.innerHTML = ` | |
<button id="ficharNowBtn">Fichar 🚀</button> | |
<button id="olvidoBtn">Olvido 😅</button> | |
<button id="falloBtn">Fallo ⚡</button> | |
`; | |
container.appendChild(buttonsWrapper); | |
// Manual date/time selection | |
const dateTimeSection = document.createElement('div'); | |
dateTimeSection.id = 'dateTimeSection'; | |
dateTimeSection.style.marginTop = '12px'; | |
dateTimeSection.style.display = 'none'; | |
dateTimeSection.innerHTML = ` | |
<label for="fichajeDate" style="display:block; margin-bottom:4px;">Select a date:</label> | |
<input type="date" id="fichajeDate" style="margin-bottom:8px; width:150px;"> | |
<label for="fichajeTime" style="display:block; margin-bottom:4px;">Select a time:</label> | |
<input type="time" id="fichajeTime" style="margin-bottom:8px; width:150px;"> | |
<button id="submitManualFicha" style="display:block; margin-top:6px;">Submit</button> | |
`; | |
container.appendChild(dateTimeSection); | |
document.body.appendChild(container); | |
} | |
/** | |
* Show or hide the date/time manual selection. | |
* @param {boolean} show - Whether to show the date/time block. | |
*/ | |
function toggleDateTimeSection(show) { | |
const section = document.getElementById('dateTimeSection'); | |
if (section) { | |
section.style.display = show ? 'block' : 'none'; | |
} | |
} | |
/** | |
* Opens "Mis permisos e incidencias" by clicking #celdaIconosPrimera_8, if found. | |
*/ | |
function openMisPermisosIncidencias() { | |
const misIncidenciasBtn = document.getElementById('celdaIconosPrimera_8'); | |
if (misIncidenciasBtn) { | |
misIncidenciasBtn.click(); | |
} else { | |
alert('Could not find "Mis permisos e incidencias" button.'); | |
} | |
} | |
/** | |
* Chooses either "1.A - ENTRADA" or "2.A - SALIDA" depending on hour (before or after 11). | |
*/ | |
function selectConceptByTime(dateObj) { | |
const hour = dateObj.getHours(); | |
let textToSelect = (hour < 11) ? '1.A - ENTRADA' : '2.A - SALIDA'; | |
const selectConcept = document.getElementById('principal.menuConstructor.objMisIncidencias.selectorIncidencias.comboIncidencias.objPintaCombo'); | |
if (selectConcept) { | |
const options = selectConcept.querySelectorAll('option'); | |
let foundOption = false; | |
options.forEach(opt => { | |
if (opt.textContent.trim() === textToSelect) { | |
opt.selected = true; | |
foundOption = true; | |
} | |
}); | |
selectConcept.dispatchEvent(new Event('change', { bubbles: true })); | |
if (!foundOption) { | |
alert('Could not find the option: ' + textToSelect); | |
} | |
} else { | |
alert('Could not find the Concept select box.'); | |
} | |
} | |
/** | |
* Selects hour & minute in #Horas and #Minutos (if they exist). | |
*/ | |
function selectHourMinute(dateObj) { | |
const hour = dateObj.getHours().toString().padStart(2, '0'); | |
const minute = dateObj.getMinutes().toString().padStart(2, '0'); | |
const selectHour = document.getElementById('Horas'); | |
if (selectHour) { | |
const hourOpt = selectHour.querySelector(`option[value="${hour}"]`); | |
if (hourOpt) { | |
hourOpt.selected = true; | |
selectHour.dispatchEvent(new Event('change', { bubbles: true })); | |
} | |
} | |
const selectMin = document.getElementById('Minutos'); | |
if (selectMin) { | |
const minOpt = selectMin.querySelector(`option[value="${minute}"]`); | |
if (minOpt) { | |
minOpt.selected = true; | |
selectMin.dispatchEvent(new Event('change', { bubbles: true })); | |
} | |
} | |
} | |
/** | |
* Selects the day in the calendar by matching the date in the title (DD/MM/YYYY). | |
*/ | |
function selectDay(dateObj) { | |
const dayNumber = dateObj.getDate().toString(); | |
const month = (dateObj.getMonth() + 1).toString().padStart(2, '0'); | |
const year = dateObj.getFullYear().toString(); | |
const desiredTitlePart = dayNumber + '/' + month + '/' + year; | |
const dayCells = document.querySelectorAll('td.dia'); | |
let found = false; | |
dayCells.forEach(cell => { | |
const numeroDia = cell.getAttribute('numero-dia'); | |
const title = cell.getAttribute('title'); | |
if (numeroDia === dayNumber && title && title.includes(desiredTitlePart)) { | |
cell.click(); | |
found = true; | |
} | |
}); | |
if (!found) { | |
alert('Could not find day ' + desiredTitlePart + ' in the calendar.'); | |
} | |
} | |
/** | |
* Clicks the "Solicitar" button if available. | |
*/ | |
function clickSolicitar() { | |
const solicitarBtn = document.getElementById('principal.menuConstructor.objMisIncidencias.selectorIncidencias.botonSolicitar.btn'); | |
if (solicitarBtn) { | |
solicitarBtn.click(); | |
} else { | |
alert('Could not find the "Solicitar" button.'); | |
} | |
} | |
/** | |
* Selects a cause by its numeric value. | |
*/ | |
function selectCause(causeValue) { | |
const causeSelect = document.getElementById('principal.menuConstructor.objMisIncidencias.ventanaCausa.comboCausa.objPintaCombo'); | |
if (causeSelect) { | |
const opts = causeSelect.querySelectorAll('option'); | |
let foundOption = false; | |
opts.forEach(opt => { | |
if (opt.value === causeValue) { | |
opt.selected = true; | |
foundOption = true; | |
} | |
}); | |
causeSelect.dispatchEvent(new Event('change', { bubbles: true })); | |
if (!foundOption) { | |
alert('Could not find cause option: ' + causeValue); | |
} | |
} else { | |
alert('Could not find the cause select box.'); | |
} | |
} | |
/** | |
* Clicks the final "Aceptar" button. | |
*/ | |
function clickAceptarCausa() { | |
const aceptarBtn = document.getElementById('principal.menuConstructor.objMisIncidencias.ventanaCausa.botonAceptar.btn'); | |
if (aceptarBtn) { | |
aceptarBtn.click(); | |
alert('Fichaje sent. If everything is correct, the system will record it.'); | |
} else { | |
alert('Could not find the "Aceptar" button for the cause.'); | |
} | |
} | |
/** | |
* Main function that simulates the entire "fichar" process. | |
* (Here we do NOT call clickAceptarCausa, for testing.) | |
*/ | |
function doFichaje(causeValue, dateObj) { | |
openMisPermisosIncidencias(); | |
// Simple timeouts for demonstration | |
setTimeout(() => { | |
selectDay(dateObj); | |
}, 4500); | |
setTimeout(() => { | |
selectConceptByTime(dateObj); | |
}, 1500); | |
setTimeout(() => { | |
selectHourMinute(dateObj); | |
}, 3000); | |
setTimeout(() => { | |
clickSolicitar(); | |
}, 6000); | |
setTimeout(() => { | |
selectCause(causeValue); | |
}, 7500); | |
// Uncomment for final confirmation if needed: | |
// setTimeout(() => { | |
// clickAceptarCausa(); | |
// }, 9000); | |
} | |
let manualCause = null; | |
/** | |
* Sets up button event listeners. | |
*/ | |
function setupEventListeners() { | |
const ficharNowBtn = document.getElementById('ficharNowBtn'); | |
if (ficharNowBtn) { | |
ficharNowBtn.addEventListener('click', function() { | |
const now = new Date(); | |
const causeValue = '114283907'; // INSTRUCCIONES_FICHAJE_DGFP | |
doFichaje(causeValue, now); | |
}); | |
} | |
const olvidoBtn = document.getElementById('olvidoBtn'); | |
if (olvidoBtn) { | |
olvidoBtn.addEventListener('click', function() { | |
manualCause = '2220603'; // OLVIDO | |
toggleDateTimeSection(true); | |
}); | |
} | |
const falloBtn = document.getElementById('falloBtn'); | |
if (falloBtn) { | |
falloBtn.addEventListener('click', function() { | |
manualCause = '2220605'; // FALLO ELÉCTRICO | |
toggleDateTimeSection(true); | |
}); | |
} | |
// "Submit" for manual date/time | |
const submitManual = document.getElementById('submitManualFicha'); | |
if (submitManual) { | |
submitManual.addEventListener('click', function() { | |
const dateInput = document.getElementById('fichajeDate'); | |
const timeInput = document.getElementById('fichajeTime'); | |
if (!dateInput.value || !timeInput.value) { | |
alert('Please provide both date and time.'); | |
return; | |
} | |
const combinedDate = new Date(dateInput.value + ' ' + timeInput.value + ':00'); | |
toggleDateTimeSection(false); | |
doFichaje(manualCause, combinedDate); | |
}); | |
} | |
} | |
/** | |
* Wait for the #thBienvenidaMensaje element, then create the panel and set up listeners. | |
*/ | |
function waitForBienvenidaMensaje() { | |
const el = document.getElementById('thBienvenidaMensaje'); | |
if (el) { | |
createFichajePanel(); | |
setupEventListeners(); | |
} else { | |
// If not found, retry after 1 second | |
setTimeout(waitForBienvenidaMensaje, 1000); | |
} | |
} | |
// Start checking for the #thBienvenidaMensaje element | |
waitForBienvenidaMensaje(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment