Checkpoint: Intégration des signatures formateurs dans la feuille de présence PDF - Les signatures tactiles des formateurs (matin et après-midi) sont maintenant affichées dans la section dédiée de la feuille de présence au lieu des lignes vides
This commit is contained in:
@@ -47,6 +47,11 @@ interface FeuillePresenceInfo {
|
|||||||
publicCible: string;
|
publicCible: string;
|
||||||
formateur?: string;
|
formateur?: string;
|
||||||
apprenants: ApprenantPresence[];
|
apprenants: ApprenantPresence[];
|
||||||
|
signaturesFormateurs?: Array<{
|
||||||
|
dateFormationId: number;
|
||||||
|
periode: 'matin' | 'apres_midi';
|
||||||
|
signatureUrl: string | null;
|
||||||
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,14 +306,56 @@ export function generateFeuillePresence(feuilleInfo: FeuillePresenceInfo): Buffe
|
|||||||
doc.text('Signatures du formateur :', 14, signatureY);
|
doc.text('Signatures du formateur :', 14, signatureY);
|
||||||
doc.setFont('helvetica', 'normal');
|
doc.setFont('helvetica', 'normal');
|
||||||
|
|
||||||
|
// Récupérer les signatures formateurs pour cette date
|
||||||
|
const signatureMatin = feuilleInfo.signaturesFormateurs?.find(
|
||||||
|
s => s.dateFormationId === dateInfo.id && s.periode === 'matin'
|
||||||
|
);
|
||||||
|
const signatureApresMidi = feuilleInfo.signaturesFormateurs?.find(
|
||||||
|
s => s.dateFormationId === dateInfo.id && s.periode === 'apres_midi'
|
||||||
|
);
|
||||||
|
|
||||||
// Signature Matin
|
// Signature Matin
|
||||||
doc.setFontSize(9);
|
doc.setFontSize(9);
|
||||||
doc.text('Matin :', 14, signatureY + 8);
|
doc.text('Matin :', 14, signatureY + 8);
|
||||||
doc.line(30, signatureY + 8, 90, signatureY + 8);
|
|
||||||
|
if (signatureMatin?.signatureUrl) {
|
||||||
|
try {
|
||||||
|
const signaturePath = path.resolve(process.cwd(), signatureMatin.signatureUrl.substring(1));
|
||||||
|
if (fs.existsSync(signaturePath)) {
|
||||||
|
const signatureBuffer = fs.readFileSync(signaturePath);
|
||||||
|
const signatureBase64 = `data:image/png;base64,${signatureBuffer.toString('base64')}`;
|
||||||
|
doc.addImage(signatureBase64, 'PNG', 30, signatureY + 2, 60, 15);
|
||||||
|
} else {
|
||||||
|
doc.line(30, signatureY + 8, 90, signatureY + 8);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur lors du chargement de la signature formateur matin:', error);
|
||||||
|
doc.line(30, signatureY + 8, 90, signatureY + 8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doc.line(30, signatureY + 8, 90, signatureY + 8);
|
||||||
|
}
|
||||||
|
|
||||||
// Signature Après-midi
|
// Signature Après-midi
|
||||||
doc.text('Après-midi :', 110, signatureY + 8);
|
doc.text('Après-midi :', 110, signatureY + 8);
|
||||||
doc.line(140, signatureY + 8, 200, signatureY + 8);
|
|
||||||
|
if (signatureApresMidi?.signatureUrl) {
|
||||||
|
try {
|
||||||
|
const signaturePath = path.resolve(process.cwd(), signatureApresMidi.signatureUrl.substring(1));
|
||||||
|
if (fs.existsSync(signaturePath)) {
|
||||||
|
const signatureBuffer = fs.readFileSync(signaturePath);
|
||||||
|
const signatureBase64 = `data:image/png;base64,${signatureBuffer.toString('base64')}`;
|
||||||
|
doc.addImage(signatureBase64, 'PNG', 140, signatureY + 2, 60, 15);
|
||||||
|
} else {
|
||||||
|
doc.line(140, signatureY + 8, 200, signatureY + 8);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur lors du chargement de la signature formateur après-midi:', error);
|
||||||
|
doc.line(140, signatureY + 8, 200, signatureY + 8);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
doc.line(140, signatureY + 8, 200, signatureY + 8);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Générer une page pour chaque date
|
// Générer une page pour chaque date
|
||||||
|
|||||||
@@ -1167,8 +1167,9 @@ export const appRouter = router({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Récupérer toutes les présences avec signatures pour cette séquence
|
// Récupérer toutes les présences avec signatures pour cette séquence
|
||||||
const { getPresencesBySequence } = await import("./presenceDb");
|
const { getPresencesBySequence, getSignaturesFormateursBySequence } = await import("./presenceDb");
|
||||||
const presences = await getPresencesBySequence(input.sequenceId);
|
const presences = await getPresencesBySequence(input.sequenceId);
|
||||||
|
const signaturesFormateurs = await getSignaturesFormateursBySequence(input.sequenceId);
|
||||||
|
|
||||||
const data = inscriptions
|
const data = inscriptions
|
||||||
.filter(i => i.inscription.statut === 'confirmee' && i.apprenant)
|
.filter(i => i.inscription.statut === 'confirmee' && i.apprenant)
|
||||||
@@ -1204,6 +1205,11 @@ export const appRouter = router({
|
|||||||
publicCible: sequence.publicCible,
|
publicCible: sequence.publicCible,
|
||||||
formateur: formateurNom,
|
formateur: formateurNom,
|
||||||
apprenants: data,
|
apprenants: data,
|
||||||
|
signaturesFormateurs: signaturesFormateurs.map(s => ({
|
||||||
|
dateFormationId: s.dateFormationId,
|
||||||
|
periode: s.periode as 'matin' | 'apres_midi',
|
||||||
|
signatureUrl: s.signatureUrl,
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
9
todo.md
9
todo.md
@@ -1548,3 +1548,12 @@
|
|||||||
- [x] Reproduire exactement le même format pour les formateurs
|
- [x] Reproduire exactement le même format pour les formateurs
|
||||||
- [x] Afficher le nom du formateur, la date/heure de signature et une case verte par ligne
|
- [x] Afficher le nom du formateur, la date/heure de signature et une case verte par ligne
|
||||||
- [x] Supprimer l'affichage actuel avec les grandes images de signature
|
- [x] Supprimer l'affichage actuel avec les grandes images de signature
|
||||||
|
|
||||||
|
|
||||||
|
## Intégrer les signatures formateurs dans la feuille de présence PDF
|
||||||
|
|
||||||
|
- [x] Analyser le code de génération de la feuille de présence PDF actuelle
|
||||||
|
- [x] Modifier le backend pour récupérer les signatures formateurs en plus des signatures apprenants
|
||||||
|
- [x] Ajouter une section "Signature Formateur" dans le PDF avec les signatures matin et après-midi
|
||||||
|
- [x] Tester la génération PDF avec les signatures formateurs
|
||||||
|
- [x] Déployer sur recette et production
|
||||||
|
|||||||
Reference in New Issue
Block a user