From 57e6ad09f92af2f5c87c1efd8a10bc9bfd9cb65b Mon Sep 17 00:00:00 2001 From: Jean-Christophe Engel Date: Fri, 30 Aug 2024 21:32:13 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20possibilit=C3=A9=20choisir=20champs=20i?= =?UTF-8?q?dentit=C3=A9=20et=20adresse=20membre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++-- admin/config.php | 12 ++- admin/pdf.php | 57 ++++++---- lib/Facture.php | 245 ++++++++++++++++++++++--------------------- templates/_style.css | 13 ++- templates/aide.tpl | 35 ++++--- templates/config.tpl | 48 +++++---- 7 files changed, 250 insertions(+), 182 deletions(-) diff --git a/README.md b/README.md index 09203f0..e42ad30 100644 --- a/README.md +++ b/README.md @@ -16,18 +16,19 @@ le dossier plugins de Paheko. ## Fonctionnalités : - Créer et gérer une base de client·es - Créer et modifier des factures et devis adressés aux membres de l'association ou des client·es ajouté·es -- Créer des reçus fiscaux pour des dons et génération du cerfa correspondant -- Créer des reçus sur des cotisations -- Génération des documents (facture et devis) en PDF grâce à la librairie mPDF +- (obsolète) Créer des reçus fiscaux pour des dons et génération du CERFA correspondant +- (obsolète) Créer des reçus sur des cotisations +- Génération des documents (facture et devis) en PDF - Liste les documents associés sur la fiche d'un·e client·e -- Permet de définir le statut du document sur reglée +- Permet de définir le statut du document à « réglé » - **Configuration** : - Possibilité d'ajouter un numéro RNA et SIRET de l'association si elle en possède (apparait alors sur les documents) + - Possibilité de choisir certains champs à faire figurer sur la facture (adresse, code postal, ville) - Modification du pied de page des documents (notament pour y inscrire des mentions légales) - Vérifier le code postal : si coché, lors d'ajout ou de modification de client, le plugin vérifiera que le code postal entré est bien formaté (par rapport aux codes postaux français seulement) - - Noms de client·es uniques : si coché, lors d'ajout ou de modicifation de client·e, le nom du/de la client·e ne pourra pas être le même que celui d'un·e client·e déjà existant - - Informations relatives au cerfa pour les reçus fiscaux - - Image qui sert de signature sur le cerfa + - Noms de client·es uniques : si coché, lors d'ajout ou de modification de client·e, le nom du/de la client·e ne pourra pas être le même que celui d'un·e client·e déjà existant + - (obsolète) Informations relatives au CERFA pour les reçus fiscaux + - (obsolète) Image qui sert de signature sur le CERFA Note : pour le moment, les actions sur la liste des clients à cocher ne fonctionnent pas. Pour supprimer un client, le faire depuis sa @@ -38,8 +39,9 @@ Un nouveau plugin est en cours de développement par BohwaZ, donc il n'est pas pertinent d'ajouter de nouvelles fonctionnalités à celui-ci. Par contre, si des bugs sont signalés sur la liste -hebergement@paheko.cloud, je peux tenter de les corriger, à condition -que ça n'impacte pas trop la structure du plugin. +hebergement@paheko.cloud ou aide@paheko.cloud, je +(lesanges@zaclys.net) peux tenter de les corriger, à condition que ça +n'impacte pas trop la structure du plugin. ## Futur improbable (obsolète) : - Ajout des champs Référence, Prix unitaire, Quantité sur les documents @@ -56,7 +58,7 @@ que ça n'impacte pas trop la structure du plugin. Le plugin nécessite l'extension PHP mbstring. -## Inclus les bibliothèques suivantes : +## (???) Inclus les bibliothèques suivantes : - Composer : https://getcomposer.org/ diff --git a/admin/config.php b/admin/config.php index c709f53..1a1e24f 100644 --- a/admin/config.php +++ b/admin/config.php @@ -1,11 +1,15 @@ requireAccess($session::SECTION_ACCOUNTING, $session::ACCESS_ADMIN); +$champsPaheko = DynamicFields::getInstance()->listAssocNames(); +$champsPaheko = array('' => '- Choisir un champ -') + $champsPaheko; + $form->runIf('save', function () use ($plugin) { $plugin->setConfigProperty('rna_asso', trim(f('rna_asso'))); $plugin->setConfigProperty('siret_asso', trim(f('siret_asso'))); @@ -26,9 +30,14 @@ $form->runIf('save', function () use ($plugin) { $plugin->setConfigProperty('logo', (bool)f('logo')); $plugin->setConfigProperty('footer', f('footer')); + $plugin->setConfigProperty('nom_client', f('nom_client')); + $plugin->setConfigProperty('prenom_client', f('prenom_client')); + $plugin->setConfigProperty('adresse_client', f('adresse_client')); + $plugin->setConfigProperty('code_postal_client', f('code_postal_client')); + $plugin->setConfigProperty('ville_client', f('ville_client')); + $plugin->setConfigProperty('validate_cp', (bool)f('validate_cp')); $plugin->setConfigProperty('unique_client_name', (bool)f('unique_client_name')); - $plugin->setConfigProperty('pattern', f('pattern')); $plugin->save(); @@ -38,5 +47,6 @@ $form->runIf('save', function () use ($plugin) { $tpl->assign('ok', qg('ok') !== null); $tpl->assign('conf', $plugin->getConfig()); $tpl->assign('patterns', \Paheko\Plugin\Facturation\PATTERNS_LIST); +$tpl->assign('champsPaheko', $champsPaheko); $tpl->display(PLUGIN_ROOT . '/templates/config.tpl'); diff --git a/admin/pdf.php b/admin/pdf.php index b32a39a..c8fa8c4 100644 --- a/admin/pdf.php +++ b/admin/pdf.php @@ -24,11 +24,26 @@ try if ($f->receveur_membre) { $c = $users->get($f->receveur_id); + // l'identité du membre peut être redéfinie dans la configuration des membres + $name_fields = \Paheko\Users\DynamicFields::getNameFields(); + array_walk($name_fields, function(&$elem) use ($c) { + $elem = $c->$elem ?? '** ABSENT **'; + }); + $c->nom = implode(" ", $name_fields); + + // adresse, code postal et ville peuvent être redéfini(e)s dans la configuration du plugin + $adresse_client = $plugin->getConfig('adresse_client'); + if ($adresse_client != null && $c->$adresse_client != null) { $c->adresse = $c->$adresse_client; } + $code_postal_client = $plugin->getConfig('code_postal_client'); + if ($code_postal_client != null && $c->$code_postal_client != null) { $c->code_postal = $c->$code_postal_client; } + $ville_client = $plugin->getConfig('ville_client'); + if ($ville_client != null && $c->$ville_client != null) { $c->ville = $c->$ville_client; } + foreach(['ville','code_postal','adresse'] as $v) { if($c->$v == '') { - $c->$v = '[A RENSEIGNER DANS LA FICHE MEMBRE]'; + $c->$v = '[À RENSEIGNER DANS LA FICHE MEMBRE]'; } } } @@ -58,20 +73,20 @@ if ($f->type_facture != CERFA) switch ($f->type_facture) { case FACT: - $doc = 'Facture n° '. $f->numero; - $txtemis = $doc . " - Émise le " . $emission; - $txtdest = "Adressée à :"; - break; + $doc = 'Facture n° '. $f->numero; + $txtemis = $doc . " - Émise le " . $emission; + $txtdest = "Adressée à :"; + break; case DEVIS: - $doc = 'Devis n° '. $f->numero; - $txtemis = $doc . " - Émis le " . $emission; - $txtdest = "Adressé à :"; - break; + $doc = 'Devis n° '. $f->numero; + $txtemis = $doc . " - Émis le " . $emission; + $txtdest = "Adressé à :"; + break; case COTIS: - $doc = 'Reçu de cotisation n° '. $f->numero; - $txtemis = $doc . " - Émis le " . $emission; - $txtdest = "Adressé à :"; - break; + $doc = 'Reçu de cotisation n° '. $f->numero; + $txtemis = $doc . " - Émis le " . $emission; + $txtdest = "Adressé à :"; + break; } // utiliser l'adresse configurée dans le plugin sinon celle de l'asso sinon rien ! @@ -149,7 +164,7 @@ EOF; $i = 1; foreach($f->contenu as $k=>$v) - { + { echo ''; echo str_replace("\n", '
', $v['designation']); echo ''; @@ -188,7 +203,7 @@ EOF; { $lieu = $plugin->getConfig('ville_asso'); $intitule = $f->contenu['intitule']; - + $souscription = date('d/m/Y', strtotime($f->contenu['souscription'])); if($f->contenu['expiration'] == '1970-01-01') @@ -224,7 +239,7 @@ EOF; } //-- Layout du document - + ob_start(); echo << @@ -237,7 +252,7 @@ EOF; size: A4 portrait; margin: 0; } - + body { padding: 4mm; font-family: Helvetica, Arial, sans; @@ -375,7 +390,7 @@ elseif ($f->type_facture == CERFA) $t['forme'] = $f->contenu['forme']; $t['nature'] = $f->contenu['nature']; $t['texte'] = $libelles[$f->contenu['texte']]; - + $t['art200'] = $t['art238'] = $t['art885'] = ''; if($plugin->getConfig('droit_art200')){ $t['art200'] = 'X'; @@ -441,7 +456,7 @@ elseif ($f->type_facture == CERFA) margin: 0; padding: 0; } - + body { font-family: Helvetica, Arial, sans; font-size: 10pt; @@ -463,11 +478,11 @@ elseif ($f->type_facture == CERFA) background-size: cover; background-position: -5mm -4.8mm; } - + #p1 { background-image: url('{$url}p/facturation/cerfa-1.png'); } - + #p2 { background-image: url('{$url}p/facturation/cerfa-2.png'); position: relative; diff --git a/lib/Facture.php b/lib/Facture.php index 0776728..9baabf8 100644 --- a/lib/Facture.php +++ b/lib/Facture.php @@ -34,27 +34,27 @@ class Facture ]; public $types = [ - DEVIS => [ - 'id' => DEVIS, - 'accounts' => [], - 'label' => 'Devis', - 'help' => ''], - FACT => [ - 'id' => FACT, - 'accounts' => [], - 'label' => 'Facture', - 'help' => ''], - CERFA => [ - 'id' => CERFA, - 'accounts' => [], - 'label' => 'Reçu fiscal', - 'help' => 'Reçu fiscal pour un don (membre ou client)'], - COTIS => [ - 'id' => COTIS, - 'accounts' => [], - 'label' => 'Reçu de cotisation', - 'help' => 'Reçu pour une cotisation payée par un·e membre'], - ]; + DEVIS => [ + 'id' => DEVIS, + 'accounts' => [], + 'label' => 'Devis', + 'help' => ''], + FACT => [ + 'id' => FACT, + 'accounts' => [], + 'label' => 'Facture', + 'help' => ''], + CERFA => [ + 'id' => CERFA, + 'accounts' => [], + 'label' => 'Reçu fiscal', + 'help' => 'Reçu fiscal pour un don (membre ou client)'], + COTIS => [ + 'id' => COTIS, + 'accounts' => [], + 'label' => 'Reçu de cotisation', + 'help' => 'Reçu pour une cotisation payée par un·e membre'], + ]; public function __construct() { @@ -79,112 +79,112 @@ class Facture { throw new UserException("La valeur de $k est vide"); } - + switch($k) { case 'type_facture': - if (!array_key_exists($datas[$k], $this->types)) { - throw new UserException("$k est de type non-attendue ($data)."); - } - if ($datas[$k] < 2) { - $fac = true; - $cerfa = false; - $recu = false; - } - elseif ($datas[$k] == 2) { - $fac = false; - $cerfa = true; - $recu = false; - } - elseif ($datas[$k] == 3) { - $fac = false; - $cerfa = false; - $recu = true; - } - break; + if (!array_key_exists($datas[$k], $this->types)) { + throw new UserException("$k est de type non-attendue ($data)."); + } + if ($datas[$k] < 2) { + $fac = true; + $cerfa = false; + $recu = false; + } + elseif ($datas[$k] == 2) { + $fac = false; + $cerfa = true; + $recu = false; + } + elseif ($datas[$k] == 3) { + $fac = false; + $cerfa = false; + $recu = true; + } + break; case 'receveur_membre': case 'reglee': case 'archivee': - if ($datas[$k] != 1 && $datas[$k] != 0) { - throw new UserException("$k est de valeur non-attendue ($data)."); - } - break; + if ($datas[$k] != 1 && $datas[$k] != 0) { + throw new UserException("$k est de valeur non-attendue ($data)."); + } + break; case 'receveur_id': - if (!is_numeric($datas[$k]) || $datas[$k] < 0) { - throw new UserException("L'id du receveur est non-attendu ($data)."); - } - break; + if (!is_numeric($datas[$k]) || $datas[$k] < 0) { + throw new UserException("L'id du receveur est non-attendu ($data)."); + } + break; case 'date_emission': - $datas[$k] = \DateTime::createFromFormat('!d/m/Y', $data)->format('Y-m-d'); - break; + $datas[$k] = \DateTime::createFromFormat('!d/m/Y', $data)->format('Y-m-d'); + break; case 'date_echeance': - $datas[$k] = \DateTime::createFromFormat('!d/m/Y', $data)->format('Y-m-d'); - if (DateTime::createFromFormat('!Y-m-d', $datas[$k])->format('U') < DateTime::createFromFormat('!Y-m-d', $datas['date_emission'])->format('U')) - { - throw new UserException("La date d'échéance est antérieure à la date d'émission ($data)."); - } - break; + $datas[$k] = \DateTime::createFromFormat('!d/m/Y', $data)->format('Y-m-d'); + if (DateTime::createFromFormat('!Y-m-d', $datas[$k])->format('U') < DateTime::createFromFormat('!Y-m-d', $datas['date_emission'])->format('U')) + { + throw new UserException("La date d'échéance est antérieure à la date d'émission ($data)."); + } + break; case 'moyen_paiement': - if (!array_key_exists($datas[$k], $this->listMoyensPaiement())) { - throw new UserException("Le moyen de paiement ne correspond pas à la liste interne ($data)."); - } - break; + if (!array_key_exists($datas[$k], $this->listMoyensPaiement())) { + throw new UserException("Le moyen de paiement ne correspond pas à la liste interne ($data)."); + } + break; case 'contenu': - if ($fac) + if ($fac) + { + if (!is_array($datas[$k]) || empty($datas[$k])) { + throw new UserException("Le contenu du document est vide ($data)."); + } + $total = 0; + foreach($datas[$k] as $g => $r) { - if (!is_array($datas[$k]) || empty($datas[$k])) { - throw new UserException("Le contenu du document est vide ($data)."); - } - $total = 0; - foreach($datas[$k] as $g => $r) + if (empty($r['designation']) && empty($r['prix'])) { - if (empty($r['designation']) && empty($r['prix'])) - { - unset($datas[$k][$g]); - unset($datas[$k]['prix']); - continue; - } - elseif (empty($r['prix'])) - { - $datas[$k]['prix'] = 0; - } - - if (!is_int($r['prix'])) - { - throw new UserException('Un (ou plus) des prix n\'est pas un entier.'); - } - - $total += $r['prix']; + unset($datas[$k][$g]); + unset($datas[$k]['prix']); + continue; } - - if($fac && !$total) + elseif (empty($r['prix'])) { - throw new UserException("Toutes les désignations/prix sont vides."); + $datas[$k]['prix'] = 0; } - } - elseif ($cerfa) - { + if (!is_int($r['prix'])) + { + throw new UserException('Un (ou plus) des prix n\'est pas un entier.'); + } + + $total += $r['prix']; } - elseif ($recu) + + if($fac && !$total) { - // $fields = ['id', 'intitule', 'date', 'expiration']; - // foreach ($datas[$k]as $) + throw new UserException("Toutes les désignations/prix sont vides."); } - $datas[$k] = json_encode($datas[$k]); - break; + } + elseif ($cerfa) + { + + } + elseif ($recu) + { + // $fields = ['id', 'intitule', 'date', 'expiration']; + // foreach ($datas[$k]as $) + } + $datas[$k] = json_encode($datas[$k]); + break; case 'total': - if ($cerfa && $datas[$k] < 1) { - throw new UserException('Le total ne peut être inférieur à 1€ pour les reçus (bug encore non résolu).'); - } - if ($fac && !isset($datas['contenu'])) { - throw new UserException("Pas de contenu fourni pour vérifier le total."); - } - if ($fac && $total != $datas[$k]) - { - throw new UserException("Les totaux sont différents ($total != $datas[$k]."); - } - break; + if ($cerfa && $datas[$k] < 1) { + throw new UserException('Le total ne peut être inférieur à 1€ pour les reçus (bug encore non résolu).'); + } + if ($fac && !isset($datas['contenu'])) { + throw new UserException("Pas de contenu fourni pour vérifier le total."); + } + if ($fac && $total != $datas[$k]) + { + throw new UserException("Les totaux sont différents ($total != $datas[$k]."); + } + break; } } } @@ -287,7 +287,7 @@ class Facture $r = $db->first('SELECT * FROM plugin_facturation_factures WHERE id = ? LIMIT 1;', (int)$id); if(!$r) - { + { throw new UserException("Pas de document retournée avec cet id."); } @@ -325,6 +325,14 @@ class Facture public function list(): DynamicList { $id_field = \Paheko\Users\DynamicFields::getNameFieldsSQL('u'); + $plugin_name = preg_replace('/^.*\/(\w+)\/$/', '${1}', \Paheko\PLUGIN_ADMIN_URL); + $plugin = \Paheko\Plugins::get($plugin_name); + + // adresse et ville peuvent être redéfinies dans la configuration du plugin + $adresse_client = $plugin->getConfig('adresse_client'); + if ($adresse_client == null) { $adresse = 'u.adresse'; } else { $adresse = 'u.' . $adresse_client; } + $ville_client = $plugin->getConfig('ville_client'); + if ($ville_client == null) { $ville = 'u.ville'; } else { $ville = 'u.' . $ville_client; } $columns = [ // Sélectionner cette colonne, mais ne pas la mettre dans la liste des colonnes @@ -349,15 +357,18 @@ class Facture ], 'receveur' => [ 'label' => 'Receveur', - 'select' => sprintf('CASE WHEN receveur_membre THEN %s ELSE c.nom END', $id_field), + // l'identité du membre peut être redéfinie dans la configuration des membres + 'select' => sprintf('CASE WHEN receveur_membre THEN CASE %s WHEN "" THEN "** ABSENT **" ELSE %s END ELSE c.nom END', $id_field, $id_field), ], 'receveur_adresse' => [ + // l'adresse peut être redéfinie dans la configuration du plugin 'label' => 'Adresse', - 'select' => 'CASE WHEN receveur_membre THEN u.adresse ELSE c.adresse END', + 'select' => sprintf('CASE WHEN receveur_membre THEN %s ELSE c.adresse END', $adresse), ], 'receveur_ville' => [ + // la ville peut être redéfinie dans la configuration du plugin 'label' => 'Ville', - 'select' => 'CASE WHEN receveur_membre THEN u.ville ELSE c.ville END', + 'select' => sprintf('CASE WHEN receveur_membre THEN %s ELSE c.ville END', $ville), ], 'date_emission' => [ 'label' => 'Émission', @@ -406,8 +417,8 @@ class Facture if ($row->type_facture == COTIS && isset($content->intitule, $content->souscription)) { $row->contenu = sprintf("Cotisation %s\nSouscrite le %s", - $content->intitule, - Utils::date_fr($content->souscription, 'd/m/Y') + $content->intitule, + Utils::date_fr($content->souscription, 'd/m/Y') ); } elseif ($row->type_facture != CERFA) { @@ -506,7 +517,7 @@ class Facture LEFT JOIN services_fees sf ON sf.id = su.id_fee LEFT JOIN acc_transactions_users tu ON tu.id_service_user = su.id LEFT JOIN acc_transactions_lines tl ON tl.id_transaction = tu.id_transaction - '.$where.' + '.$where.' GROUP BY su.id ORDER BY su.date;'; @@ -526,24 +537,24 @@ class Facture return $db->getGrouped($query); } } - + /* modif DD -- lecture et retour des textes de CERFA -- */ public function listTextesCerfa($menu = true) { $db = DB::getInstance(); - + $sel = ($menu) ? 'id, menu' : 'id, texte'; $query = 'SELECT '.$sel.' FROM "plugin_facturation_txt_cerfa" WHERE 1 ORDER BY id ;'; return $db->getAssoc($query); } - + public function getMoyenPaiement($code) { $db = DB::getInstance(); return $db->firstColumn('SELECT nom FROM plugin_facturation_paiement WHERE code = ?;', $code); } - + public function delete($id) { return DB::getInstance()->delete('plugin_facturation_factures', 'id = '. (int)$id); diff --git a/templates/_style.css b/templates/_style.css index 89a586e..f860f56 100644 --- a/templates/_style.css +++ b/templates/_style.css @@ -7,4 +7,15 @@ display: none; } -{/literal} \ No newline at end of file +div.aide { + margin: 1em; + padding: 1em; +} + +div.aide ul { + list-style: square; + margin: 1em; + padding: 1em; +} + +{/literal} diff --git a/templates/aide.tpl b/templates/aide.tpl index e947f09..6f8c672 100644 --- a/templates/aide.tpl +++ b/templates/aide.tpl @@ -1,21 +1,30 @@ {include file="_head.tpl" title="Aide — %s"|args:$plugin.name current="plugin_%s"|args:$plugin.id} {include file="%s/templates/_menu.tpl"|args:$plugin_root current="aide"} -
-

Quelques remarques et conseils sur l'utilisation du plugin Facturation

+

Quelques remarques et conseils sur l'utilisation du plugin Facturation

-

Une des premières choses à faire est d'aller dans l'onglet Configuration pour renseigner les valeurs nécessaires à la génération des documents.

-

Pour l'instant, il y a des choses encore brouillonnes. Notamment, dans les factures et devis, c'est l'adresse postale renseignée dans la configuration de Paheko qui fait foi plutôt que celle dans le plugin (qui sert en revanche pour les reçus).

-

Pensez à mettre une image en signature (cela sert pour les reçus fiscaux), cela se passe dans la configuration de Paheko, onglet personnalisation. Il est préférable d'avoir un fond transparent. -

-
-

- Pour créer un reçu sur une cotisation, il faut pour le moment que cette cotisation soit attachée à la compta.

-

- Pour créer un reçu fiscal, l'interface est pour l'instant la même que pour créer une facture/devis. Les champs correspondent mais les noms/labels autour ne sont pas adaptés. Vous pouvez de toutes façons tester, et si le résultat est pas celui attendu, remodifiez derrière :)

-

- La partie « Droit à la réduction d'impôt » peut faire peur, elle correspond simplement à des cases du cerfa pour les reçus fiscaux. Je n'y connais pas grand chose pour le moment, je ne peux vous éclairer davantage, il va falloir se retourner vers légifrance :(

-
-

Hésitez pas à faire des retours, proposer meilleures explications, ou quoi, vous pouvez venir en causer soit sur mon gitlab, soit sur l'adresse d'entraide de Paheko. Si vous êtes un peu dev, le code est un peu cracra mais j'espère que ça vous repoussera pas trop à le bidouiller :)

+
+

Une des premières choses à faire est d'aller dans l'onglet {link href="config.php" label="Configuration du plugin"} pour renseigner les valeurs nécessaires à la génération des documents.

+
+ Informations à configurer +
+
+
Si elle n'est pas remplie, c'est l'adresse qui figure dans la {link href="!config" label="configuration de l'association"} qui sera utilisée
+
+
Les champs qui définissent l'identité d'un membre peuvent être choisis dans la {link href="!config/users" label="configuration de la fiche membre"}
+
+
Permet de choisir les champs pour l'adresse, le code postal et la ville parmi les {link href="!config/fields" label="champs de la fiche membre"}
+
+
-
+

Pensez à mettre une image en signature (cela sert pour les reçus fiscaux), cela se passe dans la {link href="!config/custom.php" label="configuration de Paheko, onglet personnalisation"}. Il est préférable d'avoir un fond transparent. +

+ +

N'hésitez pas à faire des retours, proposer de meilleures explications dans le forum d'entraide de Paheko. Si vous êtes un peu dev, le code est un peu cracra mais j'espère que ça ne vous repoussera pas trop à le bidouiller :)

+ {include file="_foot.tpl"} \ No newline at end of file diff --git a/templates/config.tpl b/templates/config.tpl index b9b5bb6..f2da195 100644 --- a/templates/config.tpl +++ b/templates/config.tpl @@ -27,25 +27,25 @@ {input type="text" name="ville_asso" source=$conf label="Ville"} -
- Objet -
-
obligatoire pour reçus fiscaux
- {input type="text" name="objet_0" source=$conf label="Ligne 1" maxlength=95} - {input type="text" name="objet_1" source=$conf label="Ligne 2" maxlength=95} - {input type="text" name="objet_2" source=$conf label="Ligne 3" maxlength=95} -
-
+
+ Objet +
+
obligatoire pour reçus fiscaux
+ {input type="text" name="objet_0" source=$conf label="Ligne 1" maxlength=95} + {input type="text" name="objet_1" source=$conf label="Ligne 2" maxlength=95} + {input type="text" name="objet_2" source=$conf label="Ligne 3" maxlength=95} +
+
-
- Droit à la réduction d'impôt -
-
obligatoire pour reçus fiscaux
- {input type="checkbox" name="droit_art200" value="1" source=$conf label="Article 200"} - {input type="checkbox" name="droit_art238bis" value="1" source=$conf label="Article 238 bis"} - {input type="checkbox" name="droit_art885_0VbisA" value="1" source=$conf label="Article 885-0V bis A"} -
-
+
+ Droit à la réduction d'impôt +
+
obligatoire pour reçus fiscaux
+ {input type="checkbox" name="droit_art200" value="1" source=$conf label="Article 200"} + {input type="checkbox" name="droit_art238bis" value="1" source=$conf label="Article 238 bis"} + {input type="checkbox" name="droit_art885_0VbisA" value="1" source=$conf label="Article 885-0V bis A"} +
+
@@ -53,8 +53,18 @@ Factures
{input type="checkbox" name="logo" value="1" source=$conf label="Imprimer le logo de l'association"} - {input type="textarea" class="full-width" rows="10" name="footer" source=$conf label="Pied de document — informations légales" required=true} + {input type="textarea" class="full-width" rows="5" name="footer" source=$conf label="Pied de document — informations légales" required=true}
+
+ + Choisir les champs à faire figurer sur la facture + +
+ {input type="select" name="adresse_client" label="Adresse" required=true options=$champsPaheko source=$conf} + {input type="select" name="code_postal_client" label="Code postal" required=true options=$champsPaheko source=$conf} + {input type="select" name="ville_client" label="Ville" required=true options=$champsPaheko source=$conf} +
+