diff --git a/templates/recu.skel b/templates/recu.skel index 941ce6a..d60fa68 100644 --- a/templates/recu.skel +++ b/templates/recu.skel @@ -8,62 +8,43 @@ size: A4 portrait; margin: 1cm; } - body + body.print { + width : 19cm; font-family: Serif; font-size: 11pt; background-color: white; - width : 19cm; - } - #entete - { - position : relative; } #logo { - position : fixed; - max-width : 4cm; max-height : 4cm; } #titre { - position : fixed; - margin : 0 4.5cm 0 4.5cm; - top : 1cm; + margin : 0 2cm 0 2cm; text-align : center; font-size : 14pt; font-weight: bold; } #articles { - position : fixed; - margin : 0 4.5cm 0 4.5cm; /* idem titre */ - top : 6em; text-align : center; } #numRecu { - position : relative; text-align : right; - top : 8em; - right: 1em; - } - #beneficiaire, #donateur, #versements, #final - { - position : relative; - top : 9em; + margin-right: 1em; } + #versements { - position : relative; - top : 9em; border-top: 1px solid rgb(0, 0, 128); border-bottom: 1px solid rgb(0, 0, 128); } .rubrique { background-color : rgb(200, 200, 250); - padding : 2mm; + padding : 0 0 0 1mm; } .titre, .important { @@ -73,6 +54,10 @@ { font-weight: normal; } + #ville + { + margin-bottom: 0; + } #signature { display: block; @@ -84,7 +69,7 @@ - +

Reçu au titre des dons à certains organismes d'intérêt général

@@ -97,8 +82,9 @@

Bénéficiaire des versements

Association « {{$config.nom_asso}} »
- {{$config.adresse_asso}}
- Objet : {{$objet_asso}}

+ {{$config.adresse_asso}}
+ Objet : {{$objet_asso}} +

@@ -134,7 +120,6 @@ du {{$dateMin}} au {{$dateMax}} {{/if}} -
{{/versements}} @@ -146,7 +131,7 @@
-

{{$ville_asso}} le {{$date}}
+

{{$ville_asso}} le {{$date}}

diff --git a/templates/recu_html.tpl b/templates/recu_html.tpl new file mode 100644 index 0000000..e7de081 --- /dev/null +++ b/templates/recu_html.tpl @@ -0,0 +1,143 @@ + + +{include file="%s/templates/_nav.tpl"|args:$plugin_root current_nav="%s"|args:$nav} + + + +
+ +{* Itération sur les personnes *} +{foreach from=$totalPersonnes key="idPersonne" item="personne"} +
+ +
+ +

Reçu au titre des dons à certains organismes d'intérêt général

+

Articles 200, 238 bis et 978 du code général des impôts

+
+ {if $numero_sequentiel} + {afficher_numero_recu prefixe=$prefixeNum membre=$membre numero_personne=$personne->numero numero_sequentiel=$numero_courant} + + {else} + {afficher_numero_recu prefixe=$prefixeNum membre=$membre numero_personne=$personne->numero numero_sequentiel=$numero_sequentiel} + {/if} +
+
+ +
+

Bénéficiaire des versements

+

Association « {$nom_asso} »
+ {$adresse_asso}
+ Objet : {$objet_asso} +

+
+ +
+

Donateur

+

+ {$personne.nomPrenom}
+ {$personne.adresse}
+ {$personne.code} {$personne.ville} + {if $courriel && $personne.courriel != ""} +
courriel : {$personne.courriel} + {/if} +

+
+ +
+

Le bénéficiaire reconnaît avoir reçu au titre des dons et versements ouvrant droit à réduction d'impôt :

+
    + {foreach from=$personne.versements key="taux" item="versement"} +
  • + la somme de ***{$versement.montant|raw|money}*** euros + format((int)($versement->montant / 100)); + if ($versement->montant % 100 != 0) { + $cents = $fmt->format($versement->montant % 100); + } else { + $cents = ""; + } + ?> + {if $cents != ""} + ({$euros} euros et {$cents} cents) + {else} + ({$euros} euros) + {/if} + + {if $libelle != ""} + ({$libelle}) + {/if} +
    date des versements : + dateMin); + $dmax = date("d/m/Y", $versement->dateMax); + ?> + {if $versement.dateMin == $versement.dateMax} + le {$dmin} + {else} + du {$dmin} au {$dmax} + {/if} +{* + Erreur : dates décalées d'un jour (en arrière) + {if $versement.dateMin == $versement.dateMax} + le {$versement.dateMin|date_format:"%d/%m/%Y"} + {else} + du {$versement.dateMin|date_format:"%d/%m/%Y"} au {$versement.dateMax|date_format:"%d/%m/%Y"} + {/if} +*} + +
  • + {/foreach} +
+ + {foreach from=$complements item="elem"} +

{$elem.titre} {$elem.libelle}

+ {/foreach} + +

Le bénéficiaire certifie sur l’honneur que les dons et versements qu’il reçoit ouvrent droit à la réduction d'impôt prévue {$texteArticles} du code général des impôts.

+
+ +
+

{$ville_asso} le {$date} + +

+
+ {$nom_responsable}
+ {$fonction_responsable} +
+
+
+ +{/foreach} {* Itération sur les personnes *} +
+ +{* scripts divers *} + + +{* + * remplacer la feuille de style d'impression de paheko par la mienne + * puis déclencher l'impression +*} +{literal} + +{/literal} + + +{include file="admin/_foot.tpl"} \ No newline at end of file diff --git a/templates/versements_activites.tpl b/templates/versements_activites.tpl index c0668f9..4b50d24 100644 --- a/templates/versements_activites.tpl +++ b/templates/versements_activites.tpl @@ -1,22 +1,29 @@ {include file="%s/templates/_nav.tpl"|args:$plugin_root current_nav="activite"} -

Versements par activité et tarif

+

Année {$annee_recu} : versements par activité et tarif

+ onclick="montrerMasquerDetails(this.id, 'details.activite', 'toutes les activités')"> + Replier toutes les activités - + onclick="montrerMasquerDetails(this.id, 'details.personne', 'toutes les personnes')"> + Replier toutes les personnes +
+ {button type="submit" label="Télécharger les reçus au format PDF" shape="download" + form="versements_activites" + formaction="generer_recus.php?type=activite&format=pdf" + onclick="return verifierChoix(this.form)"} + {button type="submit" target="_dialog" label="Imprimer les reçus" shape="print" + form="versements_activites" + formaction="generer_recus.php?type=activite&format=print" + onclick="return verifierChoix(this.form)"}
-
+ {* Itération sur les versements *} {foreach from=$lesVersements key="rang" item="versement"} @@ -73,8 +80,6 @@ {fin_compte} {fin_personne} {fin_tarif} - -
{* scripts divers *} diff --git a/templates/versements_personnes.tpl b/templates/versements_personnes.tpl index 27dd96d..f6dcf59 100644 --- a/templates/versements_personnes.tpl +++ b/templates/versements_personnes.tpl @@ -1,20 +1,27 @@ {include file="%s/templates/_nav.tpl"|args:$plugin_root current_nav="personne"} -

Versements par personne

+

Année {$annee_recu} : versements par personne

- + onclick="montrerMasquerDetails(this.id, 'details.personne', 'toutes les personnes')"> + Replier toutes les personnes +
+ {button type="submit" label="Télécharger les reçus au format PDF" shape="download" + form="versements_personnes" + formaction="generer_recus.php?type=personne&format=pdf" + onclick="return verifierChoix(this.form)"} + {button type="submit" target="_dialog" label="Imprimer les reçus" shape="print" + form="versements_personnes" + formaction="generer_recus.php?type=personne&format=print" + onclick="return verifierChoix(this.form)"}
-
+ {* Itération sur les personnes *} {foreach from=$lesVersements key="rang" item="versement"} @@ -32,9 +39,9 @@ {fin_compte} {fin_personne} idUser; - $compteCourant = $versement->idCompte; + $pair = true; + $personneCourante = $versement->idUser; + $compteCourant = $versement->idCompte; ?> {afficher_debut_personne user=$personneCourante idVersement=$personneCourante} {afficher_debut_compte idCompte=$compteCourant} @@ -54,8 +61,6 @@ {/foreach} {* Itération sur les personnes *} {fin_compte} {fin_personne} - -
{* scripts divers *} diff --git a/www/admin/config.php b/www/admin/config.php index f40b688..842ecb3 100644 --- a/www/admin/config.php +++ b/www/admin/config.php @@ -57,8 +57,6 @@ if (f('save') && $form->check('recusfiscaux_config')) { $plugin->setConfig('ville_asso', trim(f('ville_asso'))); } // signature - // error_log("SESSION['sig_file'] = " . print_r($_SESSION['sig_file'], true)); - // error_log("plugin->getConfig('signature') = " . $plugin->getConfig('signature')); if (isset($_SESSION['sig_file']) && count($_SESSION['sig_file']) > 0) { // supprimer la signature précédente, si besoin @@ -78,7 +76,6 @@ if (f('save') && $form->check('recusfiscaux_config')) { // autres informations // numérotation des reçus $configNum = $plugin->getConfig('numerotation'); - error_log("configNum=" . print_r($configNum, true)); $formNum = clone $configNum; if ($configNum->prefixe != trim(f('prefixe'))) { $formNum->prefixe = trim(f('prefixe')); diff --git a/www/admin/generer_recus.php b/www/admin/generer_recus.php index 25b5d30..a17eb44 100644 --- a/www/admin/generer_recus.php +++ b/www/admin/generer_recus.php @@ -11,39 +11,34 @@ use Garradin\Plugin\RecusFiscaux\Personne; // signature $signature = - (null !== $plugin->getConfig('signature')) ? - Files::get($plugin->getConfig('signature'))->fullpath() : - ""; + (null !== $plugin->getConfig('signature')) ? + \KD2\HTTP::getScheme() . '://' . \KD2\HTTP::getHost() . WWW_URI . "/" . $plugin->getConfig('signature') : + ""; // logo -$logo_file = Files::get(File::CONTEXT_CONFIG . '/logo.png'); +$config = Config::getInstance(); $logo_asso = - (null !== $logo_file) ? - Files::get($logo_file->path)->fullpath() : - ""; + (null !== $config->fileURL('logo')) ? + $config->fileURL('logo') : + ""; // articles du CGI $articlesCGI = array(); -foreach ($plugin->getConfig('articlesCGI') as $article) -{ +foreach ($plugin->getConfig('articlesCGI') as $article) { if ($article->valeur == 1) { $articlesCGI[] = $article->titre; } } $nbArticles = count($articlesCGI); -if ($nbArticles == 1) -{ +if ($nbArticles == 1) { $texteArticles = 'à l’article ' . $articlesCGI[0]; -} -elseif ($nbArticles > 1) -{ +} elseif ($nbArticles > 1) { $texteArticles = 'aux articles '; for ($i = 0; $i < $nbArticles; ++$i) { $texteArticles .= $articlesCGI[$i]; if ($i < $nbArticles - 2) { $texteArticles .= ", "; - } - else if ($i == $nbArticles - 2) { + } else if ($i == $nbArticles - 2) { $texteArticles .= " et "; } } @@ -52,23 +47,8 @@ elseif ($nbArticles > 1) // libellés pour les taux de réduction $libelles_taux = Utils::getLignesReduction($plugin->getConfig('reduction')); +// numérotation des reçus $configNum = $plugin->getConfig('numerotation'); -error_log("config num = " . print_r($configNum, true)); -$prefixeNum = ""; -if (isset($configNum->prefixe) && $configNum->prefixe != "") { - $prefixeNum = $configNum->prefixe; -} -if (isset($configNum->annee) && $configNum->annee) { - if ($prefixeNum != "") { $prefixeNum .= "-"; } - $prefixeNum .= $_SESSION['annee_recu']; -} -if (isset($configNum->sequentiel) && $configNum->sequentiel) { - if (isset($configNum->valeur_init) && $configNum->valeur_init !="") { - $numero_sequentiel = $configNum->valeur_init; - } else { - $numero_sequentiel = 1; - } -} // filtrer les versements sélectionnés $lesLignes = f('selected'); @@ -78,125 +58,178 @@ foreach ($lesLignes as $ligne) { } // cumuler les versements -if ($_GET['type'] == 'personne') -{ +if ($_GET['type'] == 'personne') { $totalPersonnes = cumulerVersementsPersonne($versementsSelectionnes); -} -elseif ($_GET['type'] == 'activite') -{ +} elseif ($_GET['type'] == 'activite') { $totalPersonnes = cumulerVersementsTarif($versementsSelectionnes); } // générer les reçus -$listeFichiersPDF = array(); -$fmt = new \NumberFormatter('fr_FR', \NumberFormatter::SPELLOUT); -foreach ($totalPersonnes as $idPersonne => $personne) -{ - $tpl = new UserTemplate(); - $tpl->setSource(PLUGIN_ROOT . '/templates/recu.skel'); +if ($_GET['format'] == 'pdf') { + genererRecusPDF($totalPersonnes, + $signature, + $logo_asso, + $texteArticles, + $plugin, + $configNum, + $libelles_taux + ); +} else if ($_GET['format'] == 'print') { + generererRecusHTML($tpl, + $totalPersonnes, + $signature, + $logo_asso, + $texteArticles, + $plugin, + $configNum, + $libelles_taux + ); +} else { + // Erreur : format inconnu ; ne devrait pas se produire +} - $tpl->assignArray(compact('signature', 'logo_asso', 'texteArticles')); +function genererRecusPDF($totalPersonnes, + $signature, + $logo_asso, + $texteArticles, + $plugin, + $configNum, + $libelles_taux +) +{ + $listeFichiersPDF = array(); + $fmt = new \NumberFormatter('fr_FR', \NumberFormatter::SPELLOUT); + $prefixeNum = getNumPrefixe($configNum); + $numero_sequentiel = getNumSequentiel($configNum); + foreach ($totalPersonnes as $idPersonne => $personne) { + $tpl = new UserTemplate(); + $tpl->setSource(PLUGIN_ROOT . '/templates/recu.skel'); + + $tpl->assignArray(compact('signature', 'logo_asso', 'texteArticles')); + $tpl->assign('objet_asso', $plugin->getConfig('objet_asso')); + $tpl->assign('nom_responsable', $plugin->getConfig('nom_responsable')); + $tpl->assign('fonction_responsable', $plugin->getConfig('fonction_responsable')); + $tpl->assign('ville_asso', $plugin->getConfig('ville_asso')); + $tpl->assign('nom', $personne->nomPrenom); + $tpl->assign('adresse', $personne->adresse); + $tpl->assign('code_postal', $personne->codePostal); + $tpl->assign('ville', $personne->ville); + $tpl->assign('date', date("j/m/Y")); + + // numéro de reçu + $tpl->assign('numero', + faireNumeroRecu($prefixeNum, + $configNum->membre, + $personne->numero, + $numero_sequentiel)); + + // adresse de courriel + if ($plugin->getConfig('imprimerCourriel')) { + $courriel = $personne->courriel; + } else { + $courriel = ""; + } + $tpl->assign('courriel', $courriel); + + // les versements + $tpl->registerSection( + 'versements', + function () use ($personne, $libelles_taux, $fmt) { + foreach ($personne->versements as $taux => $versement) { + $ligne['montant'] = $versement->montant; + $ligne['euros'] = $fmt->format((int)($versement->montant / 100)); + if ($versement->montant % 100 != 0) { + $ligne['cents'] = $fmt->format($versement->montant % 100); + } else { + $ligne['cents'] = ""; + } + $ligne['libelle'] = $libelles_taux[$taux]; + $ligne['dateMin'] = date("d/m/Y", $versement->dateMin); + $ligne['dateMax'] = date("d/m/Y", $versement->dateMax); + yield $ligne; + } + } + ); + + // mentions complémentaires + $complements = mentionsComplémentaires(); + + $tpl->registerSection( + 'informations', + function () use ($complements) { + foreach ($complements as $elem) { + yield (array) $elem; + } + } + ); + + // fabriquer le fichier PDF + genererPDF($tpl->fetch(), $personne->nomPrenom, $listeFichiersPDF); + } + + // faire une archive zip + $fichierZip = Utils::makeArchive( + $listeFichiersPDF, + $_SESSION['annee_recu'], + PLUGIN_ROOT . "/zip" + ); + + //supprimer les fichiers pdf (utile ?) + foreach ($listeFichiersPDF as $f) { + // Utils::safe_unlink($f); + } +} // genererRecusPDF + +function generererRecusHTML($tpl, + $totalPersonnes, + $signature, + $logo_asso, + $texteArticles, + $plugin, + $configNum, + $libelles_taux +) +{ + $tpl->register_function('afficher_numero_recu', function($params) + { + $prefixeNum = $params['prefixe']; + $membre = $params['membre']; + $numero_personne = $params['numero_personne']; + $numero_sequentiel = $params['numero_sequentiel']; + $numero = faireNumeroRecu($prefixeNum, + $membre, + $numero_personne, + $numero_sequentiel); + $out = sprintf(' +

Reçu %s

', + $numero + ); + return $out; + }); + + $tpl->assign(compact( + 'totalPersonnes', + 'logo_asso', + 'signature', + 'libelles_taux', + 'texteArticles' + )); + $tpl->assign('prefixeNum', getNumPrefixe($configNum)); + $tpl->assign('membre', $configNum->membre); + $tpl->assign('numero_sequentiel', getNumSequentiel($configNum)); + $tpl->assign('nom_asso', Config::getInstance()->get('nom_asso')); + $tpl->assign('adresse_asso', Config::getInstance()->get('adresse_asso')); $tpl->assign('objet_asso', $plugin->getConfig('objet_asso')); + $tpl->assign('courriel', $plugin->getConfig('imprimerCourriel')); + $tpl->assign('complements', mentionsComplémentaires()); + $tpl->assign('ville_asso', $plugin->getConfig('ville_asso')); + $tpl->assign('date', date("j/m/Y")); $tpl->assign('nom_responsable', $plugin->getConfig('nom_responsable')); $tpl->assign('fonction_responsable', $plugin->getConfig('fonction_responsable')); - $tpl->assign('ville_asso', $plugin->getConfig('ville_asso')); - $tpl->assign('nom', $personne->nomPrenom); - $tpl->assign('adresse', $personne->adresse); - $tpl->assign('code_postal', $personne->codePostal); - $tpl->assign('ville', $personne->ville); - $tpl->assign('date', date("j/m/Y")); - // numéro de reçu - $chaineNum = $prefixeNum; - if (isset($configNum->membre) && $configNum->membre) { - if ($chaineNum != "") { $chaineNum .= "-"; } - $chaineNum .= $personne->numero; - } - if (isset($configNum->sequentiel) && $configNum->sequentiel) { - if ($chaineNum != "") { $chaineNum .= "-"; } - $chaineNum .= $numero_sequentiel; - ++$numero_sequentiel; - } - $tpl->assign('numero', $chaineNum); - // adresse de courriel - if ($plugin->getConfig('imprimerCourriel')) { - $courriel = $personne->courriel; - } - else { - $courriel = ""; - } - $tpl->assign('courriel', $courriel); - - // les versements - $tpl->registerSection('versements', - function () use($personne, $libelles_taux, $fmt) - { - foreach ($personne->versements as $taux => $versement) - { - $ligne['montant'] = $versement->montant; - $ligne['euros'] = $fmt->format((int)($versement->montant/100)); - if ($versement->montant % 100 != 0) { - $ligne['cents'] = $fmt->format($versement->montant % 100); - } else { - $ligne['cents'] = ""; - } - $ligne['libelle'] = $libelles_taux[$taux]; - $ligne['dateMin'] = date("d/m/Y", $versement->dateMin); - $ligne['dateMax'] = date("d/m/Y", $versement->dateMax); - yield $ligne; - } - }); - - // mentions complémentaires - $donnees = array( - 'Nature du don : ' => "Numéraire", - 'Mode de versement : ' => "chèque et/ou virement" - ); - $infos = array(); - foreach ($donnees as $titre => $libelle) - { - $elem = new \stdClass(); - $elem->titre = $titre; - $elem->libelle = $libelle; - $infos[] = $elem; - } - - $tpl->registerSection('informations', - function () use ($infos) - { - foreach ($infos as $elem) - { - yield (array) $elem; - } - }); - - // fabriquer le fichier PDF - $result = $tpl->fetch(); - $nomPDF = \Garradin\Utils::filePDF($result); - // changer le nom du fichier - $nom = str_replace(' ', '_', $personne->nomPrenom); - $nom = str_replace("'", "", $nom); - $nomFichier = sprintf('%s/recu_%s_%s.pdf', - dirname($nomPDF), - $_SESSION['annee_recu'], - $nom); - rename($nomPDF, $nomFichier); - // ajouter le nom du fichier à la liste pour mettre dans une archive - $listeFichiersPDF[] = $nomFichier; -} - -// faire une archive zip -$fichierZip = Utils::makeArchive( - $listeFichiersPDF, - $_SESSION['annee_recu'], - PLUGIN_ROOT . "/zip" -); - -//supprimer les fichiers pdf (utile ?) -foreach ($listeFichiersPDF as $f) -{ - unlink($f); -} + $tpl->assign('plugin_css', ['previs_recu.css', 'imprimer_recu.css']); + $tpl->display(PLUGIN_ROOT . '/templates/recu_html.tpl'); +} // generererRecusHTML /** * Cumuler les versements de chaque personne @@ -210,13 +243,10 @@ function cumulerVersementsPersonne($versements) $dateMin = PHP_INT_MAX; $dateMax = -1; $totalVersements = 0; - foreach ($versements as $ligne) - { - if ($ligne->idUser != $idPersonneCourant) - { + foreach ($versements as $ligne) { + if ($ligne->idUser != $idPersonneCourant) { // changement de personne - if ($idPersonneCourant != -1) - { + if ($idPersonneCourant != -1) { $totalPersonnes[$idPersonneCourant]->ajouterVersement( $_SESSION['taux_reduction'], $totalVersements, @@ -229,15 +259,18 @@ function cumulerVersementsPersonne($versements) $idPersonneCourant = $ligne->idUser; $totalVersements = $ligne->versement; // créer les infos de la personne, sauf si elle est déjà présente - if (!array_key_exists($idPersonneCourant, $totalPersonnes)) - { - $totalPersonnes["$idPersonneCourant"] = $_SESSION['membresDonateurs'][$ligne->idUser]->clone(); + if (!array_key_exists($idPersonneCourant, $totalPersonnes)) { + $totalPersonnes[$idPersonneCourant] = $_SESSION['membresDonateurs'][$ligne->idUser]->clone(); } } else { // même personne : cumuler versements et mettre à jour les dates $totalVersements += $ligne->versement; - if (strtotime($ligne->date) < $dateMin) { $dateMin = strtotime($ligne->date); } - if (strtotime($ligne->date) > $dateMax) { $dateMax = strtotime($ligne->date); } + if (strtotime($ligne->date) < $dateMin) { + $dateMin = strtotime($ligne->date); + } + if (strtotime($ligne->date) > $dateMax) { + $dateMax = strtotime($ligne->date); + } } } // et le dernier @@ -248,7 +281,7 @@ function cumulerVersementsPersonne($versements) $dateMax ); return $totalPersonnes; -} +} // cumulerVersementsPersonne /** * Cumuler les versements de chaque personne par tarif @@ -264,20 +297,17 @@ function cumulerVersementsTarif($versements) $dateMin = PHP_INT_MAX; $dateMax = -1; $totalVersements = 0; - foreach ($versements as $ligne) - { + foreach ($versements as $ligne) { if ( $ligne->idTarif != $idTarifCourant || $ligne->idUser != $idPersonneCourant || $ligne->idCompte != $idCompteCourant - ) - { - if ($idTarifCourant != -1) - { + ) { + if ($idTarifCourant != -1) { // changement de tarif, de personne ou de compte $tarifCompte = ($idTarifCourant == 0) ? - $idCompteCourant : - $idTarifCourant . "_" . $idCompteCourant; + $idCompteCourant : + $idTarifCourant . "_" . $idCompteCourant; $totalPersonnes[$idPersonneCourant]->ajouterVersement( $_SESSION['tauxSelectionnes'][$tarifCompte], $totalVersements, @@ -292,21 +322,24 @@ function cumulerVersementsTarif($versements) $idCompteCourant = $ligne->idCompte; $totalVersements = $ligne->versement; // créer les infos de la personne, sauf si elle est déjà présente - if (!array_key_exists($idPersonneCourant, $totalPersonnes)) - { - $totalPersonnes["$idPersonneCourant"] = $_SESSION['membresDonateurs'][$ligne->idUser]->clone(); + if (!array_key_exists($idPersonneCourant, $totalPersonnes)) { + $totalPersonnes[$idPersonneCourant] = $_SESSION['membresDonateurs'][$ligne->idUser]->clone(); } } else { // même personne : cumuler versements et mettre à jour les dates $totalVersements += $ligne->versement; - if (strtotime($ligne->date) < $dateMin) { $dateMin = strtotime($ligne->date); } - if (strtotime($ligne->date) > $dateMax) { $dateMax = strtotime($ligne->date); } + if (strtotime($ligne->date) < $dateMin) { + $dateMin = strtotime($ligne->date); + } + if (strtotime($ligne->date) > $dateMax) { + $dateMax = strtotime($ligne->date); + } } } // et le dernier $tarifCompte = ($idTarifCourant == 0) ? - $idCompteCourant : - $idTarifCourant . "_" . $idCompteCourant; + $idCompteCourant : + $idTarifCourant . "_" . $idCompteCourant; $totalPersonnes[$idPersonneCourant]->ajouterVersement( $_SESSION['tauxSelectionnes'][$tarifCompte], $totalVersements, @@ -314,4 +347,94 @@ function cumulerVersementsTarif($versements) $dateMax ); return $totalPersonnes; +} // cumulerVersementsTarif + +/** + * génère un fichier PDF à partir d'un document html + * ajoute son nom à la liste de fichiers + */ +function genererPDF($docHTML, $nomPersonne, &$listeFichiersPDF) +{ + // fabriquer le fichier PDF + $nomPDF = \Garradin\Utils::filePDF($docHTML); + // changer le nom du fichier + $nom = str_replace(' ', '_', $nomPersonne); + $nom = str_replace("'", "", $nom); + $nomFichier = sprintf( + '%s/recu_%s_%s.pdf', + dirname($nomPDF), + $_SESSION['annee_recu'], + $nom + ); + rename($nomPDF, $nomFichier); + // ajouter le nom du fichier à la liste pour mettre dans une archive + $listeFichiersPDF[] = $nomFichier; +} // genererPDF + +function faireNumeroRecu($prefixeNum, $membre, $numero, &$numero_sequentiel) +{ + if (isset($membre) && $membre) { + if ($prefixeNum != "") { + $prefixeNum .= "-"; + } + $prefixeNum .= $numero; + } + if ($numero_sequentiel) { + if ($prefixeNum != "") { + $prefixeNum .= "-"; + } + $prefixeNum .= $numero_sequentiel; + ++$numero_sequentiel; + } + return $prefixeNum; +} + +/** + * renvoyer le préfixe du numéro de reçu + */ +function getNumPrefixe($configNum) +{ + $prefixeNum = ""; + if (isset($configNum->prefixe) && $configNum->prefixe != "") { + $prefixeNum = $configNum->prefixe; + } + if (isset($configNum->annee) && $configNum->annee) { + if ($prefixeNum != "") { + $prefixeNum .= "-"; + } + $prefixeNum .= $_SESSION['annee_recu']; + } + return $prefixeNum; +} + +/** + * renvoyer le premier numéro de la numérotation séquentielle + * renvoie false si pas de numérotation séquentielle + */ +function getNumSequentiel($configNum) +{ + if (isset($configNum->sequentiel) && $configNum->sequentiel) { + if (isset($configNum->valeur_init) && $configNum->valeur_init != "") { + $numero_sequentiel = $configNum->valeur_init; + } else { + $numero_sequentiel = 1; + } + } + return isset($numero_sequentiel) ? $numero_sequentiel : false; +} + +function mentionsComplémentaires() +{ + $donnees = array( + 'Nature du don : ' => "Numéraire", + 'Mode de versement : ' => "chèque et/ou virement" + ); + $complements = array(); + foreach ($donnees as $titre => $libelle) { + $elem = new \stdClass(); + $elem->titre = $titre; + $elem->libelle = $libelle; + $complements[] = $elem; + } + return $complements; } diff --git a/www/admin/imprimer_recu.css b/www/admin/imprimer_recu.css new file mode 100644 index 0000000..8a51941 --- /dev/null +++ b/www/admin/imprimer_recu.css @@ -0,0 +1,38 @@ +/* + * impression + */ +@page +{ + size: A4 portrait; +} + +header.header { + display: none; +} + +body { + background: #fff; + padding: 0; + margin: 0; +} + +.noprint { + display: none; +} + +nav.tabs +{ + display: none; +} + +main { + margin: 0; +} + +div.previs_recu +{ + font-family: Serif; + font-size: 11pt; + background-color: white; + page-break-after: always; +} diff --git a/www/admin/previs_recu.css b/www/admin/previs_recu.css new file mode 100644 index 0000000..0bf2103 --- /dev/null +++ b/www/admin/previs_recu.css @@ -0,0 +1,97 @@ +/* + * prévisualisation reçu au format HTML + */ + +div.previs_recu +{ + width : 18.5cm; +} + +#logo +{ + max-height : 4cm; +} + +#titre +{ + margin : 0 2cm 0 2cm; + text-align : center; + font-size : 14pt; + font-weight: bold; +} + +#articles +{ + margin-bottom: 0.5cm; + text-align : center; +} + +#numRecu +{ + text-align : right; + margin-right: 1em; +} + +#versements +{ + border-top: 1px solid rgb(0, 0, 128); + border-bottom: 1px solid rgb(0, 0, 128); + padding-top: 1em; + margin-bottom: 1em; +} + +.cartouche +{ + padding-bottom: 1em; +} + +.rubrique +{ + background-color : rgb(200, 200, 250); + padding : 0 0 0 1mm; + margin-bottom: 1em; +} + +.titre, .important +{ + font-weight:bold; +} +.libelle +{ + font-weight: normal; +} + +#ville +{ + margin-bottom: 0; +} + +#signature +{ + display: block; + max-width : 7cm; + max-height : 4cm; + margin: 0 auto; + padding-bottom : 2mm; +} + +#versements > ul +{ + list-style: inside; + margin-left: 2em; +} + +#date_versements +{ + margin-left: 1.5em; +} + +p.complements +{ + margin-top : 1em; +} + +span.titre, span.libelle +{ + display : inline; +} diff --git a/www/admin/script.js b/www/admin/script.js index e1b03b0..a46ce9a 100644 --- a/www/admin/script.js +++ b/www/admin/script.js @@ -9,12 +9,10 @@ * (dé)sélectionner toutes les cases de toutes les activités * @param {HTMLInputElement} idCaseGlobale id de la case globale */ -function cocherDecocherTout(idCaseGlobale) -{ +function cocherDecocherTout(idCaseGlobale) { // itérer sur la liste des éléments détails : 1 par couple let lesDetails = document.querySelectorAll("details.activite"); - for (let i = 0; i < lesDetails.length; ++i) - { + for (let i = 0; i < lesDetails.length; ++i) { let idCase = lesDetails[i].querySelector("input[type=checkbox]"); idCase.checked = idCaseGlobale.checked; cocherDecocherTarif(idCase); @@ -28,8 +26,7 @@ function cocherDecocherTout(idCaseGlobale) * (dé)sélectionner toutes les cases de cette activité * @param {HTMLInputElement} idCaseGlobale id de la case d'activité */ -function cocherDecocherTarif(idCaseGlobale) -{ +function cocherDecocherTarif(idCaseGlobale) { let lesPersonnes = idCaseGlobale.closest("details").querySelectorAll("div.personne"); cocherDecocherLesPersonnes(idCaseGlobale, lesPersonnes); } @@ -38,8 +35,7 @@ function cocherDecocherTarif(idCaseGlobale) * idem dans le cas des versements des personnes * @param {HTMLInputElement} idCaseGlobale id case à cocher d'une personne */ -function cocherDecocherToutesLesPersonnes(idCaseGlobale) -{ +function cocherDecocherToutesLesPersonnes(idCaseGlobale) { let lesPersonnes = document.querySelectorAll("div.personne"); cocherDecocherLesPersonnes(idCaseGlobale, lesPersonnes); changerMessage(idCaseGlobale.nextElementSibling, idCaseGlobale); @@ -49,10 +45,8 @@ function cocherDecocherToutesLesPersonnes(idCaseGlobale) * @param {HTMLInputElement} idCaseGlobale * @param {NodeListOf} lesPersonnes */ -function cocherDecocherLesPersonnes(idCaseGlobale, lesPersonnes) -{ - for (let j = 0; j < lesPersonnes.length; ++j) - { +function cocherDecocherLesPersonnes(idCaseGlobale, lesPersonnes) { + for (let j = 0; j < lesPersonnes.length; ++j) { // trouver l'élément total de la personne let idTotal = lesPersonnes[j].querySelector("span"); // puis la case à cocher @@ -70,13 +64,11 @@ function cocherDecocherLesPersonnes(idCaseGlobale, lesPersonnes) * @param {HTMLInputElement} idCase id de la case qui a été cochée * @param {HTMLSpanElement} idTotal id de l'élément où afficher le total */ -function cocherDecocherPersonne(idCase, idTotal) -{ +function cocherDecocherPersonne(idCase, idTotal) { // chercher le fieldset des versements let fieldset = idCase.closest("details").querySelector("div.versements"); let listeCases = fieldset.querySelectorAll("input[type=checkbox]"); - for (let i = 0; i < listeCases.length; ++i) - { + for (let i = 0; i < listeCases.length; ++i) { listeCases[i].checked = idCase.checked; cocherDecocherVersement(listeCases[i], idTotal); } @@ -89,8 +81,7 @@ function cocherDecocherPersonne(idCase, idTotal) * @param {HTMLInputElement} idCase id de la case qui a été cochée * @param {HTMLSpanElement} idTotal id de l'élément où afficher le total */ -function cocherDecocherVersement(idCase, idTotal) -{ +function cocherDecocherVersement(idCase, idTotal) { let fieldset = idCase.closest("div.versements"); let listeCases = fieldset.querySelectorAll("input[type=checkbox]"); let listeMontants = fieldset.querySelectorAll("span.montant"); @@ -103,19 +94,19 @@ function cocherDecocherVersement(idCase, idTotal) * @param {NodeListOf} listeMontants liste des montants associés * @param {HTMLSpanElement} idTotal id de l'élément où afficher le total */ -function calculerTotal(listeCases, listeMontants, idTotal) -{ +function calculerTotal(listeCases, listeMontants, idTotal) { let total = 0; - for (let i = 0; i < listeCases.length; ++i) - { + for (let i = 0; i < listeCases.length; ++i) { if (listeCases[i].checked) { total += parseFloat(listeMontants[i].textContent.replace(/\s/g, "").replace(",", ".")); } } // afficher le total idTotal.innerHTML = - total.toLocaleString('fr-FR', {style: 'currency', currency: 'EUR', - minimumFractionDigits: 2}); + total.toLocaleString('fr-FR', { + style: 'currency', currency: 'EUR', + minimumFractionDigits: 2 + }); } /** @@ -123,8 +114,7 @@ function calculerTotal(listeCases, listeMontants, idTotal) * @param {Element} message * @param {HTMLInputElement} idCase */ -function changerMessage(message, idCase) -{ +function changerMessage(message, idCase) { if (idCase.checked) { message.innerHTML = "Cliquer pour dé-cocher toutes les lignes"; } else { @@ -138,14 +128,11 @@ function changerMessage(message, idCase) * @param {string} classe des détails à afficher/masquer * @param {string} texte du bouton */ -function montrerMasquerDetails(idElem, classe, texte) -{ +function montrerMasquerDetails(idElem, classe, texte) { let lesDetails = document.querySelectorAll(classe); - if (lesDetails.length > 0) - { + if (lesDetails.length > 0) { let leBouton = document.getElementById(idElem); - if (leBouton.textContent.startsWith('Replier')) - { + if (leBouton.textContent.includes('Replier')) { // masquer lesDetails.forEach((e) => { e.removeAttribute('open'); @@ -153,8 +140,7 @@ function montrerMasquerDetails(idElem, classe, texte) leBouton.textContent = "Déplier " + texte; leBouton.setAttribute('data-icon', '↓'); } - else - { + else { // montrer lesDetails.forEach((e) => { e.setAttribute('open', 'open'); @@ -171,8 +157,7 @@ function montrerMasquerDetails(idElem, classe, texte) * @return vrai si au moins un choix a été fait * @param {HTMLFormElement} formulaire */ -function verifierChoix(formulaire) -{ +function verifierChoix(formulaire) { return verifierCases(formulaire, 'checkbox', "au moins un versement"); } @@ -188,17 +173,13 @@ function verifierChoix(formulaire) * @param {any} idElem id de l'élément à afficher * @param {any} nomClasse classe des éléments à masquer (sauf idElem) */ -function choixMethodeGeneration(formulaire, action, idElem, nomClasse) -{ +function choixMethodeGeneration(formulaire, action, idElem, nomClasse) { formulaire.setAttribute('action', 'action.php?action=' + action); - for (let elem of formulaire.querySelectorAll(nomClasse)) - { - if (elem.id == idElem) - { + for (let elem of formulaire.querySelectorAll(nomClasse)) { + if (elem.id == idElem) { elem.classList.remove('hidden'); } - else - { + else { elem.classList.add('hidden'); } } @@ -210,23 +191,20 @@ function choixMethodeGeneration(formulaire, action, idElem, nomClasse) * - qu'un radio de chaque activité/tarif sélectionné a été sélectionné :) * @param conteneur des cases à vérifier */ -function verifierActivitésTaux(conteneur) -{ +function verifierActivitésTaux(conteneur) { let nbChoix = 0; // parcourir les cases à cocher - for (let idCase of conteneur.querySelectorAll("input[type=checkbox]")) - { + for (let idCase of conteneur.querySelectorAll("input[type=checkbox]")) { if (idCase.checked) { ++nbChoix; // vérifier qu'un radio de la même ligne est sélectionné let ligneCorrecte = false; // trouver la ligne englobante let ligne = idCase.closest("li"); - for (let idRadio of ligne.querySelectorAll('input[type=radio]')) - { + for (let idRadio of ligne.querySelectorAll('input[type=radio]')) { if (idRadio.checked) { ligneCorrecte = true; break; } } - if (! ligneCorrecte) { + if (!ligneCorrecte) { alert("Erreur : il faut sélectionner un taux de réduction dans chaque ligne cochée"); return false; } @@ -241,8 +219,7 @@ function verifierActivitésTaux(conteneur) /** * vérifier qu'un taux a été sélectionné dans le conteneur paramètre */ -function verifierTaux(conteneur) -{ +function verifierTaux(conteneur) { return verifierCases(conteneur, 'radio', "un taux de réduction"); } @@ -253,17 +230,16 @@ function verifierTaux(conteneur) /** * vérifier les données saisies dans le formulaire de configuration */ -function verifierConfig(divArticles, divTauxReduc) -{ +function verifierConfig(divArticles, divTauxReduc) { // articles - if (! verifierCases(divArticles, "checkbox", "au moins un article")) { return false; } + if (!verifierCases(divArticles, "checkbox", "au moins un article")) { return false; } // taux de réduction - if (! verifierCases(divTauxReduc, "checkbox", "au moins un taux de réduction")) { return false; } + if (!verifierCases(divTauxReduc, "checkbox", "au moins un taux de réduction")) { return false; } // Nom, fonction, signature - + // alert("Erreur : il faut sélectionner au moins un versement"); return true; } @@ -274,14 +250,27 @@ function verifierConfig(divArticles, divTauxReduc) * @param type de case à vérifier (radio, checkbox) * @param message à afficher si erreur */ -function verifierCases(conteneur, type, message) -{ +function verifierCases(conteneur, type, message) { let selecteur = "input[type=" + type + "]"; let listeCheck = conteneur.querySelectorAll(selecteur); - for (let elem of listeCheck) - { + for (let elem of listeCheck) { if (elem.checked) { return true; } } alert("Erreur : il faut sélectionner " + message); return false; } + +/** + * petite bidouille pour utiliser ma feuille de style pour imprimer les reçus + * à la place de la feuille de style de paheko + * @param {*} document + */ +function changerStyle(document) { + let styles = document.querySelectorAll('link[rel="stylesheet"]'); + // console.log(styles); + for (let sheet of styles) { + if (sheet.href.includes('print.css')) { sheet.media = "tv"; sheet.remove; } + if (sheet.href.includes('imprimer_recu.css')) { sheet.media = 'print'; } + } + // console.log(styles); +} \ No newline at end of file diff --git a/www/admin/versements_activites.php b/www/admin/versements_activites.php index d2fa478..6545123 100644 --- a/www/admin/versements_activites.php +++ b/www/admin/versements_activites.php @@ -9,39 +9,56 @@ use Garradin\Plugin\RecusFiscaux\Utils; // récupérer les infos du formulaire // ------------------------------------------------------------ -// vérifier qu'on a bien sélectionné une activité ou un compe -if (null === f('tarifs') && null === f('comptes')) +// vérifier qu'on a bien sélectionné une activité ou un compte +if (! isset($_SESSION['tauxSelectionnes']) + && + null === f('tarifs') + && + null === f('comptes')) { \Garradin\Utils::redirect(PLUGIN_URL . 'index.php'); } // tarifs sélectionnés -$tarifsSelectionnes = f('tarifs') ?: []; +if (null !== f('tarifs')) { + $tarifsSelectionnes = f('tarifs'); +} else if (! isset($_SESSION['tauxSelectionnes'])) { + $tarifsSelectionnes = []; +} // comptes sélectionnés -$comptesSelectionnes = f('comptes') ?: []; +if (null !== f('comptes')) { + $_SESSION['comptesSelectionnes'] = f('comptes'); +} /* +else if (! isset($_SESSION['tauxSelectionnes'])) { + $_SESSION['comptesSelectionnes'] = []; +} + */ // taux de réduction associés -$tauxSelectionnes = array(); -foreach ($tarifsSelectionnes as $idTarif) +if (isset($tarifsSelectionnes) && isset($_SESSION['comptesSelectionnes'])) { - $nomRadio = "taux_reduction_" . $idTarif; - $valRadio = f("$nomRadio"); - $tauxSelectionnes[$idTarif] = $valRadio; + $tauxSelectionnes = array(); + foreach ($tarifsSelectionnes as $idTarif) + { + $nomRadio = "taux_reduction_" . $idTarif; + $tauxSelectionnes[$idTarif] = f("$nomRadio"); + } + foreach ($_SESSION['comptesSelectionnes'] as $idCompte) + { + $nomRadio = "taux_reduction_" . $idCompte; + $tauxSelectionnes[$idCompte] = f("$nomRadio"); + } + $_SESSION['tauxSelectionnes'] = $tauxSelectionnes; } -foreach ($comptesSelectionnes as $idCompte) -{ - $nomRadio = "taux_reduction_" . $idCompte; - $valRadio = f("$nomRadio"); - $tauxSelectionnes[$idCompte] = $valRadio; -} -$_SESSION['tauxSelectionnes'] = $tauxSelectionnes; -// versements correspondants à la sélection, triés par tarif, nom, compte, date -$lesTarifs = array_map(fn($elem) : string => substr($elem, 0, strpos($elem, '_')), - $tarifsSelectionnes); -$lesComptes = array_map(fn($elem) : string => substr($elem, 1 + strpos($elem, '_')), - $tarifsSelectionnes); +$lesTarifs = array_map(fn($elem) : string => + strpos($elem, '_') !== false ? substr($elem, 0, strpos($elem, '_')) : "", + array_keys($_SESSION['tauxSelectionnes'])); +$lesComptes = array_map(fn($elem) : string => + strpos($elem, '_') !== false ? substr($elem, 1 + strpos($elem, '_')) : "", + array_keys($_SESSION['tauxSelectionnes'])); + $_SESSION['lesVersements'] = Utils::getVersementsTarifsComptes( $_SESSION['annee_recu'], @@ -51,15 +68,15 @@ $_SESSION['lesVersements'] = // ajouter les versements sans tarif (tri par nom, compte, date) $versementsSansTarif = Utils::getVersementsComptes($_SESSION['annee_recu'], - $comptesSelectionnes, + $_SESSION['comptesSelectionnes'], $champsNom); foreach ($versementsSansTarif as $versement) { $_SESSION['lesVersements'][] = $versement; } - // préparation de l'affichage $tpl->assign('lesVersements', $_SESSION['lesVersements']); +$tpl->assign('annee_recu', $_SESSION['annee_recu']); $tpl->assign('plugin_css', ['style.css']); // envoyer au template diff --git a/www/admin/versements_personnes.php b/www/admin/versements_personnes.php index 5a626bd..74e7d95 100644 --- a/www/admin/versements_personnes.php +++ b/www/admin/versements_personnes.php @@ -6,11 +6,16 @@ use Garradin\Plugin\RecusFiscaux\Personne; use Garradin\Plugin\RecusFiscaux\Utils; // vérifier si le taux de réduction a été sélectionné au préalable -$_SESSION['taux_reduction'] = f('taux_reduction'); -if (! isset($_SESSION['taux_reduction']) || $_SESSION['taux_reduction'] == "") +$taux = f('taux_reduction'); +if (! isset($_SESSION['taux_reduction']) + && + null === $taux) { \Garradin\Utils::redirect(PLUGIN_URL . 'index.php'); } +if (null !== $taux) { + $_SESSION['taux_reduction'] = $taux; +} // versements par personne $_SESSION['lesVersements'] = Utils::getVersementsPersonnes( @@ -21,6 +26,7 @@ $_SESSION['lesVersements'] = Utils::getVersementsPersonnes( // préparation de l'affichage $tpl->assign('lesVersements', $_SESSION['lesVersements']); +$tpl->assign('annee_recu', $_SESSION['annee_recu']); $tpl->assign('plugin_css', ['style.css']); // envoyer au template