Files
SIRH/templates/employee-yearly-hours/print-all.html.twig
T
tristan a41bd632cf
Auto Tag Develop / tag (push) Successful in 11s
Retour RH: vue jour par date, RTT mi-semaine, récap salaire & exports, panier de nuit (#21)
## Correctifs RH (branche fix/retour-rh)

### Vue Jour (Heures)
- Mode saisie/présence, libellé de contrat et sauvegarde résolus **à la date affichée** (et non au contrat courant). Corrige les salariés passés 39h/35h → Forfait.

### RTT — heures supplémentaires
- Proratisation du **plafond 25%/50%** pour les embauches en milieu de semaine (la bande +25% se décale au lieu de rester bloquée à 43h). Témoin Dylan : 4h à 25% + 3h à 50%.

### Récap salaire (PDF mensuel)
- Forfait : congés imputés **N-1** non affichés et comptés en présence.
- Colonne « Heures payés » **scindée 25% / 50%** (en-tête fusionné).
- **Exclusion des salariés sans contrat** sur le mois (ex. Marine, contrat terminé).

### Exports heures annuelles (par salarié + tous)
- **Tous les jours sous contrat** affichés, même vides/non saisis (corrige les lignes manquantes).
- Samedis/dimanches en **gris plus foncé**.

### Panier de nuit
- **Ne s'applique pas aux conducteurs** (vue semaine + récap salaire).

## Tests
- 11 tests ajoutés. Suite verte hors un test legacy pré-existant dépendant de la date (`EmployeeRttSummaryProviderTest::testNoQueryParamsKeepsLegacyYearDefaulting`, non modifié par cette branche).

## À noter (hors scope)
- L'export heures annuelles *tous salariés* peut dépasser `memory_limit=256M` (Dompdf) — limitation **pré-existante**, non corrigée ici.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #21
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
2026-06-02 06:26:40 +00:00

284 lines
9.9 KiB
Twig

<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Export heures - {% set months = {
1:'Janvier', 2:'Février', 3:'Mars', 4:'Avril', 5:'Mai', 6:'Juin',
7:'Juillet', 8:'Août', 9:'Septembre', 10:'Octobre', 11:'Novembre', 12:'Décembre'
} %}{% if month %}{{ months[month] }} {{ year }}{% else %}{{ year }}{% endif %}</title>
<style>
@page { size: A4 portrait; margin: 4mm; }
html, body {
margin: 0;
padding: 2mm;
font-family: Helvetica, sans-serif;
font-size: 9px;
}
.employee-section {
page-break-before: always;
}
.employee-section:first-child {
page-break-before: auto;
}
.title-bar {
position: relative;
margin: 0 0 4mm 0;
}
h1 {
text-align: center;
font-size: 16px;
margin: 0;
}
.export-date {
position: absolute;
top: 0;
right: 0;
font-size: 9px;
color: #333;
padding-top: 4px;
}
h2 {
font-size: 12px;
margin: 4mm 0 2mm 0;
padding: 2px 6px;
background: #e8e8e8;
}
table {
width: 100%;
border-collapse: collapse;
table-layout: auto;
border: 2px solid #0a0a0a;
}
th, td {
border: 1px solid #0a0a0a;
padding: 2px 4px;
vertical-align: middle;
white-space: nowrap;
}
thead th {
text-align: center;
font-weight: 700;
font-size: 9px;
background: #d9e2f3;
}
td { font-size: 9px; }
td.date { text-align: left; font-weight: bold; }
td.absence { text-align: left; color: #c00; }
td.absence .holiday { color: #0277bd; font-weight: 600; }
td.absence .holiday.with-absence { display: block; }
td.time { text-align: center; }
td.presence { text-align: center; }
td.total { text-align: center; font-weight: bold; }
tr.weekend td { background: #c0c0c0; color: #333; }
tr.weekend td.date { color: #333; }
tr.holiday td { background: #e1f5fe; }
.signature-footer {
page-break-inside: avoid;
margin-top: 6mm;
}
.signature-intro {
text-align: center;
font-weight: 700;
margin-bottom: 6mm;
font-size: 11px;
}
.signature-blocks {
display: table;
width: 100%;
table-layout: fixed;
border-collapse: separate;
border-spacing: 4mm 0;
}
.signature-block {
display: table-cell;
border: 1px solid #0a0a0a;
padding: 3mm;
vertical-align: top;
width: 33.33%;
}
.signature-block .title {
text-align: center;
font-weight: 700;
font-size: 11px;
margin-bottom: 7mm;
text-decoration: underline;
}
.signature-block .line {
margin-bottom: 2mm;
font-size: 10px;
}
.signature-block .signature-line {
margin-top: 6mm;
margin-bottom: 18mm;
font-size: 10px;
}
</style>
</head>
<body>
{% set months = {
1:'Janvier', 2:'Février', 3:'Mars', 4:'Avril', 5:'Mai', 6:'Juin',
7:'Juillet', 8:'Août', 9:'Septembre', 10:'Octobre', 11:'Novembre', 12:'Décembre'
} %}
{% for entry in entries %}
<div class="employee-section">
<div class="title-bar">
<h1>
{{ entry.employeeName }}{% if entry.contractLabel %} - {{ entry.contractLabel }}{% endif %}<br>
{% if month %}{{ months[month] }} {{ year }}{% else %}{{ year }}{% endif %}
</h1>
<div class="export-date">Exporté le {{ "now"|date('d/m/Y') }} à {{ "now"|date('H:i:s') }}</div>
</div>
{% for segment in entry.segments %}
{% if entry.segments|length > 1 %}
<h2>{{ segment.contractName ?? 'Contrat inconnu' }}{% if segment.mode == 'driver' %} (Chauffeur){% endif %}</h2>
{% endif %}
{% if segment.mode == 'presence' %}
<table>
<thead>
<tr>
<th>Date</th>
<th>Absence</th>
<th>Présence matin</th>
<th>Présence après-midi</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{% for row in segment.rows %}
<tr class="{{ row.isWeekend ? 'weekend' : (row.holidayLabel ? 'holiday' : '') }}">
<td class="date">{{ row.date }}</td>
<td class="absence">
{{ row.absenceLabel ?? '' }}
{% if row.holidayLabel %}<span class="holiday {{ row.absenceLabel ? 'with-absence' : '' }}">Férié : {{ row.holidayLabel }}</span>{% endif %}
</td>
<td class="presence">{{ row.presentMorning ? 'X' : '' }}</td>
<td class="presence">{{ row.presentAfternoon ? 'X' : '' }}</td>
<td class="total">{{ row.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% elseif segment.mode == 'driver' %}
<table>
<thead>
<tr>
<th>Date</th>
<th>Absence</th>
<th>Heures jour</th>
<th>Heures nuit</th>
<th>Heures atelier</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{% for row in segment.rows %}
<tr class="{{ row.isWeekend ? 'weekend' : (row.holidayLabel ? 'holiday' : '') }}">
<td class="date">{{ row.date }}</td>
<td class="absence">
{{ row.absenceLabel ?? '' }}
{% if row.holidayLabel %}<span class="holiday {{ row.absenceLabel ? 'with-absence' : '' }}">Férié : {{ row.holidayLabel }}</span>{% endif %}
</td>
<td class="time">{{ row.dayHours }}</td>
<td class="time">{{ row.nightHours }}</td>
<td class="time">{{ row.workshopHours }}</td>
<td class="total">{{ row.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<table>
<thead>
<tr>
<th>Date</th>
<th>Absence</th>
<th>Début matin</th>
<th>Fin matin</th>
<th>Début après-midi</th>
<th>Fin après-midi</th>
<th>Début soir</th>
<th>Fin soir</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{% for row in segment.rows %}
<tr class="{{ row.isWeekend ? 'weekend' : (row.holidayLabel ? 'holiday' : '') }}">
<td class="date">{{ row.date }}</td>
<td class="absence">
{{ row.absenceLabel ?? '' }}
{% if row.holidayLabel %}<span class="holiday {{ row.absenceLabel ? 'with-absence' : '' }}">Férié : {{ row.holidayLabel }}</span>{% endif %}
</td>
<td class="time">{{ row.morningFrom }}</td>
<td class="time">{{ row.morningTo }}</td>
<td class="time">{{ row.afternoonFrom }}</td>
<td class="time">{{ row.afternoonTo }}</td>
<td class="time">{{ row.eveningFrom }}</td>
<td class="time">{{ row.eveningTo }}</td>
<td class="total">{{ row.total }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% endfor %}
<div class="signature-footer">
<div class="signature-intro">
Nom + Prénom<br>
Signature avec mention « bon pour accord »
</div>
<div class="signature-blocks">
<div class="signature-block">
<p class="title">Direction</p>
<p class="line">Nom : ...............</p>
<p class="line">Prénom : ...............</p>
<p class="line">Mention : ........................................</p>
<p class="signature-line">Signature :</p>
</div>
<div class="signature-block">
<p class="title">Responsable usine</p>
<p class="line">Nom : ...............</p>
<p class="line">Prénom : ...............</p>
<p class="line">Mention : ........................................</p>
<p class="signature-line">Signature :</p>
</div>
<div class="signature-block">
<p class="title">Salarié</p>
<p class="line">Nom : ...............</p>
<p class="line">Prénom : ...............</p>
<p class="line">Mention : ........................................</p>
<p class="signature-line">Signature :</p>
</div>
</div>
</div>
</div>
{% endfor %}
</body>
</html>