﻿{"id":1116,"date":"2025-12-22T20:03:53","date_gmt":"2025-12-22T19:03:53","guid":{"rendered":"https:\/\/www.laterzagroup.it\/site\/?page_id=1116"},"modified":"2025-12-22T21:10:07","modified_gmt":"2025-12-22T20:10:07","slug":"calcolo-retribuzione-oraria","status":"publish","type":"page","link":"https:\/\/www.laterzagroup.it\/site\/calcolo-retribuzione-oraria\/","title":{"rendered":"Calcolo retribuzione oraria"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"it\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\">\n    <title>Calcolatore Ore Pro<\/title>\n    \n    <script defer src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf\/2.5.1\/jspdf.umd.min.js\"><\/script>\n    <script defer src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jspdf-autotable\/3.5.23\/jspdf.plugin.autotable.min.js\"><\/script>\n\n    <style>\n        :root {\n            --primary: #4f46e5;\n            --accent: #6366f1;\n            --success: #10b981;\n            --danger: #ef4444;\n            --bg: #f1f5f9;\n            --card-bg: #ffffff;\n            --text-main: #0f172a;\n            --text-light: #64748b;\n        }\n\n        * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }\n\n        body {\n            font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;\n            background-color: var(--bg);\n            padding: 20px 10px;\n            margin: 0;\n            color: var(--text-main);\n        }\n\n        .container { max-width: 850px; margin: 0 auto; }\n\n        h1 { text-align: center; color: var(--primary); font-size: 2rem; font-weight: 800; margin-bottom: 30px; }\n\n        .config-card {\n            background: var(--card-bg);\n            padding: 25px;\n            border-radius: 20px;\n            box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1);\n            margin-bottom: 25px;\n            border-left: 8px solid var(--primary);\n        }\n\n        .config-card label { display: block; font-weight: 700; color: var(--text-light); margin-bottom: 10px; text-transform: uppercase; font-size: 0.8rem; letter-spacing: 1px; }\n        \n        .input-tariffa {\n            font-size: 1.8rem !important;\n            font-weight: 800;\n            color: var(--primary);\n            border: 2px solid #e2e8f0;\n            padding: 10px 15px;\n            border-radius: 12px;\n            width: 100%;\n        }\n\n        .work-card {\n            background: var(--card-bg);\n            border-radius: 24px;\n            padding: 25px;\n            margin-bottom: 20px;\n            box-shadow: 0 10px 15px -3px rgba(0,0,0,0.05);\n            display: flex;\n            flex-direction: column;\n            gap: 20px;\n            border: 1px solid #e2e8f0;\n            animation: slideIn 0.3s ease-out;\n        }\n\n        @keyframes slideIn {\n            from { opacity: 0; transform: translateY(10px); }\n            to { opacity: 1; transform: translateY(0); }\n        }\n\n        .grid-inputs {\n            display: grid;\n            grid-template-columns: repeat(3, 1fr);\n            gap: 15px;\n        }\n\n        .input-group label { display: block; font-size: 0.85rem; font-weight: 700; color: var(--text-light); margin-bottom: 8px; }\n        \n        input {\n            font-size: 1.1rem !important;\n            padding: 12px;\n            border: 2px solid #f1f5f9;\n            border-radius: 12px;\n            width: 100%;\n            background: #f8fafc;\n            color: var(--text-main);\n        }\n\n        .row-results {\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            background: #f8fafc;\n            padding: 20px;\n            border-radius: 18px;\n            border: 1px dashed #cbd5e1;\n        }\n\n        .res-box { display: flex; flex-direction: column; }\n        .res-label { font-size: 0.75rem; font-weight: 700; color: var(--text-light); text-transform: uppercase; margin-bottom: 5px; }\n        .res-value { font-size: 1.6rem; font-weight: 800; color: var(--text-main); }\n        .res-value.compenso { color: var(--primary); }\n\n        .btn-delete {\n            background: #fff1f2;\n            color: var(--danger);\n            border: 1px solid #fecaca;\n            padding: 10px;\n            border-radius: 10px;\n            font-weight: 700;\n            cursor: pointer;\n        }\n\n        .btn-add {\n            background: var(--success);\n            color: white;\n            border: none;\n            width: 100%;\n            padding: 20px;\n            border-radius: 18px;\n            font-size: 1.2rem;\n            font-weight: 800;\n            cursor: pointer;\n            box-shadow: 0 4px 14px 0 rgba(16, 185, 129, 0.3);\n            margin-bottom: 40px;\n        }\n\n        .total-section {\n            background: #0f172a;\n            color: white;\n            border-radius: 30px;\n            padding: 40px 20px;\n            text-align: center;\n        }\n\n        .total-grid {\n            display: grid;\n            grid-template-columns: 1fr 1fr;\n            gap: 20px;\n            margin-top: 20px;\n            margin-bottom: 30px;\n            border-top: 1px solid #334155;\n            padding-top: 25px;\n        }\n\n        .total-label { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 2px; opacity: 0.7; font-weight: 600; }\n        .total-val-small { font-size: 1.4rem; font-weight: 700; color: #cbd5e1; }\n        .total-price { font-size: 3.5rem; font-weight: 900; color: #fff; margin: 10px 0; display: block; }\n\n        .btn-pdf {\n            background: var(--primary);\n            color: white;\n            border: none;\n            padding: 20px 40px;\n            border-radius: 15px;\n            font-size: 1.1rem;\n            font-weight: 700;\n            cursor: pointer;\n            width: 100%;\n        }\n\n        @media (max-width: 600px) {\n            .grid-inputs { grid-template-columns: 1fr; }\n            .total-grid { grid-template-columns: 1fr; }\n            .total-price { font-size: 2.5rem; }\n            .row-results { flex-direction: column; gap: 15px; text-align: center; }\n        }\n    <\/style>\n<\/head>\n<body>\n\n<div class=\"container\">\n    <h1>\ud83d\udcb0 Calcolo Compenso<\/h1>\n\n    <div class=\"config-card\">\n        <label>Tariffa Oraria Applicata (\u20ac)<\/label>\n        <input type=\"number\" id=\"hourlyRate\" class=\"input-tariffa\" value=\"12\" oninput=\"calculateAll()\">\n    <\/div>\n\n    <div id=\"cards-container\"><\/div>\n\n    <button type=\"button\" class=\"btn-add\" id=\"addBtn\">+ AGGIUNGI GIORNATA<\/button>\n\n    <div class=\"total-section\">\n        <span class=\"total-label\">Compenso Totale<\/span>\n        <span class=\"total-price\" id=\"grandTotalDisplay\">0.00 \u20ac<\/span>\n        \n        <div class=\"total-grid\">\n            <div>\n                <span class=\"total-label\">Somma Ore (Decimale)<\/span><br>\n                <span class=\"total-val-small\" id=\"totalHoursDec\">0.00 h<\/span>\n            <\/div>\n            <div>\n                <span class=\"total-label\">Tempo Totale (HH:MM)<\/span><br>\n                <span class=\"total-val-small\" id=\"totalHoursClock\">0h 0m<\/span>\n            <\/div>\n        <\/div>\n\n        <button type=\"button\" class=\"btn-pdf\" id=\"pdfBtn\">\ud83d\udcc4 SCARICA REPORT PDF<\/button>\n    <\/div>\n<\/div>\n\n<script>\n    function formatDateIT(dateStr) {\n        if (!dateStr) return \"\";\n        const [year, month, day] = dateStr.split(\"-\");\n        return `${day}\/${month}\/${year}`;\n    }\n\n    function formatClock(decimalHours) {\n        const h = Math.floor(decimalHours);\n        const m = Math.round((decimalHours - h) * 60);\n        return `${h}h ${m}m`;\n    }\n\n    function calculateAll() {\n        const rate = parseFloat(document.getElementById('hourlyRate').value) || 0;\n        const cards = document.querySelectorAll('.work-card');\n        let totalHours = 0;\n        let totalMoney = 0;\n\n        cards.forEach(card => {\n            const start = card.querySelector('.row-start').value;\n            const end = card.querySelector('.row-end').value;\n            \n            if(start && end) {\n                const [hS, mS] = start.split(':').map(Number);\n                const [hE, mE] = end.split(':').map(Number);\n                let diff = (hE + mE\/60) - (hS + mS\/60);\n                if(diff < 0) diff += 24;\n                \n                const subtotal = diff * rate;\n                card.querySelector('.row-hours').innerText = diff.toFixed(2);\n                card.querySelector('.row-subtotal').innerText = subtotal.toFixed(2) + \" \u20ac\";\n                \n                totalHours += diff;\n                totalMoney += subtotal;\n            }\n        });\n\n        document.getElementById('grandTotalDisplay').innerText = totalMoney.toFixed(2) + \" \u20ac\";\n        document.getElementById('totalHoursDec').innerText = totalHours.toFixed(2) + \" h\";\n        document.getElementById('totalHoursClock').innerText = formatClock(totalHours);\n    }\n\n    function addRow() {\n        const container = document.getElementById('cards-container');\n        const cards = document.querySelectorAll('.work-card');\n        let nextDate = new Date();\n\n        \/\/ Se esistono gi\u00e0 righe, imposta la data del giorno successivo all'ultima riga\n        if (cards.length > 0) {\n            const lastDateVal = cards[cards.length - 1].querySelector('.row-data').value;\n            nextDate = new Date(lastDateVal);\n            nextDate.setDate(nextDate.getDate() + 1);\n        }\n\n        const dateString = nextDate.toISOString().split('T')[0];\n        const card = document.createElement('div');\n        card.className = 'work-card';\n        \n        card.innerHTML = `\n            <div class=\"grid-inputs\">\n                <div class=\"input-group\">\n                    <label>Data<\/label>\n                    <input type=\"date\" value=\"${dateString}\" class=\"row-data\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label>Inizio<\/label>\n                    <input type=\"time\" value=\"09:00\" class=\"row-start\" oninput=\"calculateAll()\">\n                <\/div>\n                <div class=\"input-group\">\n                    <label>Fine<\/label>\n                    <input type=\"time\" value=\"18:00\" class=\"row-end\" \n                           oninput=\"calculateAll()\" \n                           onkeydown=\"if(event.key==='Enter'){ addRow(); }\">\n                <\/div>\n            <\/div>\n            <div class=\"row-results\">\n                <div class=\"res-box\">\n                    <span class=\"res-label\">Ore Lavorate<\/span>\n                    <span class=\"res-value row-hours\">9.00<\/span>\n                <\/div>\n                <div class=\"res-box\">\n                    <span class=\"res-label\">Subtotale<\/span>\n                    <span class=\"res-value compenso row-subtotal\">108.00 \u20ac<\/span>\n                <\/div>\n                <button type=\"button\" class=\"btn-delete\" onclick=\"this.closest('.work-card').remove(); calculateAll()\">Elimina<\/button>\n            <\/div>\n        `;\n        container.appendChild(card);\n        \n        \/\/ Focus automatico sul nuovo orario di inizio per velocizzare l'inserimento\n        const startTimeInput = card.querySelector('.row-start');\n        startTimeInput.focus();\n        startTimeInput.select(); \n\n        calculateAll();\n    }\n\n    async function generatePDF() {\n        if (!window.jspdf) return;\n        const { jsPDF } = window.jspdf;\n        const doc = new jsPDF();\n        \n        const body = [];\n        const dateObjects = [];\n\n        document.querySelectorAll('.work-card').forEach(card => {\n            const rawDate = card.querySelector('.row-data').value;\n            if (rawDate) dateObjects.push(new Date(rawDate));\n\n            body.push([\n                formatDateIT(rawDate),\n                card.querySelector('.row-start').value,\n                card.querySelector('.row-end').value,\n                card.querySelector('.row-hours').innerText,\n                card.querySelector('.row-subtotal').innerText\n            ]);\n        });\n\n        let titolo = \"Report lavori\";\n        if (dateObjects.length > 0) {\n            const minDate = new Date(Math.min(...dateObjects));\n            const maxDate = new Date(Math.max(...dateObjects));\n            const startStr = formatDateIT(minDate.toISOString().split('T')[0]);\n            const endStr = formatDateIT(maxDate.toISOString().split('T')[0]);\n            titolo = `Report lavori del periodo dal ${startStr} al ${endStr}`;\n        }\n\n        doc.setFontSize(14);\n        doc.text(titolo, 14, 20);\n        \n        doc.autoTable({\n            startY: 30,\n            head: [['Data', 'Inizio', 'Fine', 'Ore (Dec)', 'Importo']],\n            body: body,\n            headStyles: { fillColor: [79, 70, 229] },\n            styles: { fontSize: 10 }\n        });\n\n        const finalY = doc.lastAutoTable.finalY + 15;\n        doc.setFontSize(11);\n        doc.text(`SOMMA ORE (MATEMATICA): ${document.getElementById('totalHoursDec').innerText}`, 14, finalY);\n        doc.text(`TEMPO TOTALE (ORE\/MIN): ${document.getElementById('totalHoursClock').innerText}`, 14, finalY + 7);\n        doc.setFontSize(14);\n        doc.setTextColor(79, 70, 229);\n        doc.text(`COMPENSO TOTALE: ${document.getElementById('grandTotalDisplay').innerText}`, 14, finalY + 18);\n        \n        doc.save(`Report_Lavori.pdf`);\n    }\n\n    document.addEventListener('DOMContentLoaded', () => {\n        document.getElementById('addBtn').addEventListener('click', addRow);\n        document.getElementById('pdfBtn').addEventListener('click', generatePDF);\n        addRow();\n    });\n<\/script>\n\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Calcolatore Ore Pro \ud83d\udcb0 Calcolo Compenso Tariffa Oraria Applicata (\u20ac) + AGGIUNGI GIORNATA Compenso Totale 0.00 \u20ac Somma Ore (Decimale) 0.00 h Tempo Totale (HH:MM) 0h 0m \ud83d\udcc4 SCARICA REPORT PDF<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"saved_in_kubio":false,"footnotes":""},"class_list":["post-1116","page","type-page","status-publish","hentry"],"kubio_ai_page_context":{"short_desc":"","purpose":"general"},"_links":{"self":[{"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/pages\/1116","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/comments?post=1116"}],"version-history":[{"count":5,"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/pages\/1116\/revisions"}],"predecessor-version":[{"id":1122,"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/pages\/1116\/revisions\/1122"}],"wp:attachment":[{"href":"https:\/\/www.laterzagroup.it\/site\/wp-json\/wp\/v2\/media?parent=1116"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}