diff --git a/lib/Facture.php b/lib/Facture.php index 7b4a643..4f3068f 100644 --- a/lib/Facture.php +++ b/lib/Facture.php @@ -58,12 +58,21 @@ class Facture if (!array_key_exists($datas[$k], $this->type)) { throw new UserException("$k est de type non-attendue ($data)."); } - if ($datas[$k] > 1) { - $recu = true; - } - else { + 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': @@ -98,37 +107,49 @@ class Facture unset($cats); break; case 'contenu': - if (!$recu && (!is_array($datas[$k]) || empty($datas[$k]))) { - throw new UserException("Le contenu du document est vide ($data)."); - } - $total = 0; - $vide = 1; - foreach($datas[$k] as $g=>$r) + if ($fac) { - if ($r['designation'] !== '' && is_numeric($r['prix'])) - { - $vide = 0; + if (!is_array($datas[$k]) || empty($datas[$k])) { + throw new UserException("Le contenu du document est vide ($data)."); } - else + $total = 0; + $vide = 1; + foreach($datas[$k] as $g=>$r) { - unset($datas[$k][$g]); + if ($r['designation'] !== '' && is_numeric($r['prix'])) + { + $vide = 0; + } + else + { + unset($datas[$k][$g]); + } + $total += $r['prix']; + } + if($fac && $vide) + { + throw new UserException("Toutes les désignations/prix sont vides."); } - $total += $r['prix']; } - if(!$recu && $vide) + elseif ($cerfa) { - throw new UserException("Toutes les désignations/prix sont vides."); + + } + elseif ($recu) + { + // $fields = ['id', 'intitule', 'date', 'expiration']; + // foreach ($datas[$k]as $) } $datas[$k] = json_encode($datas[$k]); break; case 'total': - if ($recu && $datas[$k] < 1) { + 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 (!$recu && !isset($datas['contenu'])) { + if ($fac && !isset($datas['contenu'])) { throw new UserException("Pas de contenu fourni pour vérifier le total."); } - if ($total != $datas[$k]) + if ($fac && $total != $datas[$k]) { throw new UserException("Les totaux sont différents ($total != $datas[$k]."); } @@ -253,4 +274,28 @@ class Facture return DB::getInstance()->test('plugin_facturation_factures', 'receveur_membre = '. $base .' AND receveur_id = '. $id); } + // ** Pour type reçu ** + + public $recu_fields = ['id', 'intitule', 'montant', 'date', 'expiration']; + + public function getCotis($membre_id = 1) + { + // C un peu overkill nn? + // Copié/modifié de Membres\Cotisations::listSubscriptionsForMember($id) + $db = DB::getInstance(); + return $db->get('SELECT cm.id, c.intitule, strftime(\'%s\', c.debut) AS debut, strftime(\'%s\', c.fin) AS fin, c.montant, strftime(\'%s\', cm.date) AS date, + CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date() + WHEN c.fin IS NOT NULL THEN (cm.id IS NOT NULL AND cm.date <= c.fin AND cm.date >= c.debut) + WHEN cm.id IS NOT NULL THEN 1 ELSE 0 END AS a_jour, + strftime(\'%s\', CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') + WHEN c.fin IS NOT NULL THEN c.fin ELSE 1 END ) AS expiration, + (julianday(date()) - julianday(CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') + WHEN c.fin IS NOT NULL THEN c.fin END)) AS nb_jours + FROM cotisations_membres AS cm + INNER JOIN cotisations AS c ON c.id = cm.id_cotisation + WHERE cm.id_membre = ? + AND ((c.fin IS NOT NULL AND cm.date <= c.fin AND cm.date >= c.debut) OR c.fin IS NULL) + GROUP BY cm.id_cotisation + ORDER BY cm.date DESC;', (int)$membre_id); + } } diff --git a/templates/config.tpl b/templates/config.tpl index 76cd4a9..6766d4f 100644 --- a/templates/config.tpl +++ b/templates/config.tpl @@ -51,7 +51,7 @@
Droit à la réduction d'impôt
-
obligatoire pour reçus fiscaux
+
obligatoire pour reçus fiscaux
diff --git a/templates/cotis_ajouter.tpl b/templates/cotis_ajouter.tpl new file mode 100644 index 0000000..10c8ab2 --- /dev/null +++ b/templates/cotis_ajouter.tpl @@ -0,0 +1,109 @@ +{include file="admin/_head.tpl" title="Créer un document — %s"|args:$plugin.nom current="plugin_%s"|args:$plugin.id js=1} +{include file="%s/templates/_menu.tpl"|args:$plugin_root current="facture"} + + + +{form_errors} + +
+ + +
+ Créer une reçu de cotisation +
+
obligatoire et unique
+
+

Chaque facture doit comporter un numéro unique délivré chronologiquement et de façon continue.
Il faut que le système adopté par l'association garantisse que deux factures émises la même année ne peuvent pas porter le même numéro.

+
+ +
obligatoire
+
+ +
+
+ +
+
+ +
+ Membre +
+
+
+ +
+
+
+ +

+ {csrf_field key="add_cotis_1"} + +

+ + +{if $step} + +
+ Cotisation +
+
Sélectionnez la cotisation concernée :
+ + + + + + + + + + + + {foreach from=$liste item=cotis key=i} + + + {foreach from=$cotis item=element key=key} + + {/foreach} + + {/foreach} +
IdIntituléMontantDate (souscrit)Expiration (calculée)
+ + + +
+ +
+
+ +

+ {csrf_field key="add_cotis_2"} + +

+
+{/if} + +{include file="%s/templates/_js.tpl"|args:$plugin_root} +{include file="admin/_foot.tpl"} diff --git a/templates/cotis_modifier.tpl b/templates/cotis_modifier.tpl new file mode 100644 index 0000000..bfbe860 --- /dev/null +++ b/templates/cotis_modifier.tpl @@ -0,0 +1,109 @@ +{include file="admin/_head.tpl" title="Créer un document — %s"|args:$plugin.nom current="plugin_%s"|args:$plugin.id js=1} +{include file="%s/templates/_menu.tpl"|args:$plugin_root current="index"} + + + +{form_errors} + +
+ + +
+ Créer une reçu de cotisation +
+
obligatoire et unique
+
+

Chaque facture doit comporter un numéro unique délivré chronologiquement et de façon continue.
Il faut que le système adopté par l'association garantisse que deux factures émises la même année ne peuvent pas porter le même numéro.

+
+ +
obligatoire
+
+ +
+
+ +
+
+ +
+ Membre +
+
+
+ +
+
+
+ +

+ {csrf_field key="add_cotis_1"} + +

+ + +{* {if $step} *} + +
+ Cotisation +
+
Sélectionnez la cotisation concernée :
+ + + + + + + + + + + + {foreach from=$liste item=cotis key=i} + + + {foreach from=$cotis item=element key=key} + + {/foreach} + + {/foreach} +
IdIntituléMontantDate (souscrit)Expiration (calculée)
+ + + +
+ +
+
+ +

+ {csrf_field key="add_cotis_2"} + +

+
+{* {/if} *} + +{include file="%s/templates/_js.tpl"|args:$plugin_root} +{include file="admin/_foot.tpl"} diff --git a/templates/facture.tpl b/templates/facture.tpl index 1d68e72..77d167a 100644 --- a/templates/facture.tpl +++ b/templates/facture.tpl @@ -4,7 +4,11 @@ {form_errors} {if $session->canAccess('compta', Membres::DROIT_ECRITURE)} - + {if $type == 3} + + {else} + + {/if} {/if} diff --git a/templates/facture_ajouter.tpl b/templates/facture_ajouter.tpl index 46e0f27..f23ea96 100644 --- a/templates/facture_ajouter.tpl +++ b/templates/facture_ajouter.tpl @@ -13,18 +13,15 @@
    -
  • -
  • -
  • -
  • +
  • +
  • +
  • +
  • Reçu de cotisaition
Créer une facture
- {*
-
-
*}
obligatoire et unique
diff --git a/www/admin/cotis_ajouter.php b/www/admin/cotis_ajouter.php new file mode 100644 index 0000000..afb282f --- /dev/null +++ b/www/admin/cotis_ajouter.php @@ -0,0 +1,119 @@ +requireAccess('compta', Membres::DROIT_ECRITURE); + +use Garradin\DB; + +$db = DB::getInstance(); + + +$step = $radio = false; +$liste = []; + +$fields = $facture->recu_fields; + +if (f('select')) +{ + $form->check('add_cotis_1',[ + 'numero_facture' => 'required|string', + 'date_emission' => 'required|date', + 'membre' => 'required|numeric', + ]); + + $step = true; +} +elseif (f('add')) +{ + $form->check('add_cotis_2',[ + 'numero_facture' => 'required|string', + 'date_emission' => 'required|date', + 'membre' => 'required|numeric', + 'cotisation' => 'required', + ]); + + $radio = f('cotisation'); + + if (!$form->hasErrors()) + { + try + { + $num = (int) str_replace('cotis_', '', $radio); + foreach($fields as $field) + { + $cotis[$field] = f($field.'_'.$num); + } + + $r = $db->get('SELECT moyen_paiement, montant FROM membres_operations AS mo INNER JOIN compta_journal AS cj ON cj.id = mo.id_operation + WHERE mo.id_cotisation = ?;', (int)$cotis['id']); + $r = $r[0]; + + $data = [ + 'type_facture' => 3, + 'numero' => f('numero_facture'), + 'receveur_membre' => 1, + 'receveur_id' => f('membre'), + 'date_emission' => f('date_emission'), + 'moyen_paiement' => $r->moyen_paiement, + 'total' => $r->montant, + 'contenu' => ['id' => $cotis['id'], + 'intitule' => $cotis['intitule'], + 'souscription' => $cotis['date'], + 'expiration' => $cotis['expiration'] ] + ]; + + $id = $facture->add($data); + + Utils::redirect(PLUGIN_URL . 'facture.php?id='.(int)$id); + } + catch (UserException $e) + { + $form->addError($e->getMessage()); + } + } + + $step = true; +} + + +if ($step) +{ + try + { + $r = $facture->getCotis((int)f('membre')); + // Passe les expiration nulles (cotis ponctuelle) à 0 pour avoir moins d'embrouilles + foreach ($r as $i=>$cotis) + { + foreach($cotis as $k=>$v) + { + if (in_array($k, $fields)) + { + $liste[$i][$k] = $v; + } + } + if($liste[$i]['expiration'] < 0) + { + $liste[$i]['expiration'] = 0; + } + } + + } + catch (UserException $e) + { + $form->addError($e->getMessage()); + } +} + + +$tpl->assign('liste', $liste); +$tpl->assign('radio', $radio); + +$tpl->assign('step', $step); +$tpl->assign('identite', $identite); +$tpl->assign('membre_id', f('membre') ?: -1); +$tpl->assign('membres', (array)DB::getInstance()->get('SELECT id, '.$identite.' FROM membres WHERE id_categorie != -2 NOT IN (SELECT id FROM membres_categories WHERE cacher = 1);')); + +$tpl->display(PLUGIN_ROOT . '/templates/cotis_ajouter.tpl'); \ No newline at end of file diff --git a/www/admin/cotis_modifier.php b/www/admin/cotis_modifier.php new file mode 100644 index 0000000..0440562 --- /dev/null +++ b/www/admin/cotis_modifier.php @@ -0,0 +1,144 @@ +requireAccess('compta', Membres::DROIT_ECRITURE); + +use Garradin\DB; + +$db = DB::getInstance(); + + +qv(['id' => 'required|numeric']); +$id = (int) qg('id'); + +if (!$f = $facture->get($id)) +{ + throw new UserException("Ce document n'existe pas."); +} + +$fields = $facture->recu_fields; + +$membre_id = f('membre') ?: $f->receveur_id; + +$values['numero_facture'] = $f->numero; +$values['date_emission'] = date('Y-m-d', $f->date_emission); + +$radio = ''; +$liste = []; + + +if (f('select')) +{ + $form->check('add_cotis_1',[ + 'numero_facture' => 'required|string', + 'date_emission' => 'required|date', + 'membre' => 'required|numeric', + ]); + +} +elseif (f('add')) +{ + $form->check('add_cotis_2',[ + 'numero_facture' => 'required|string', + 'date_emission' => 'required|date', + 'membre' => 'required|numeric', + 'cotisation' => 'required', + ]); + + $radio = f('cotisation'); + + if (!$form->hasErrors()) + { + try + { + $num = (int) str_replace('cotis_', '', $radio); + foreach($fields as $field) + { + $cotis[$field] = f($field.'_'.$num); + } + + $cotis['date'] = date('Y-m-d', $cotis['date']); + $cotis['expiration'] = date('Y-m-d', $cotis['expiration']); + + var_export($cotis); + // die(); + + $r = $db->get('SELECT moyen_paiement, montant FROM membres_operations AS mo INNER JOIN compta_journal AS cj ON cj.id = mo.id_operation + WHERE mo.id_cotisation = ?;', (int)$cotis['id']); + $r = $r[0]; + + $data = [ + 'type_facture' => 3, + 'numero' => f('numero_facture'), + 'receveur_membre' => 1, + 'receveur_id' => f('membre'), + 'date_emission' => f('date_emission'), + 'moyen_paiement' => $r->moyen_paiement, + 'total' => $r->montant, + 'contenu' => ['id' => $cotis['id'], + 'intitule' => $cotis['intitule'], + 'souscription' => $cotis['date'], + 'expiration' => $cotis['expiration'] ] + ]; + + if($facture->edit($id, $data)) + { + Utils::redirect(PLUGIN_URL . 'facture.php?id='.(int)$id); + } + throw new UserException('Erreur d\'édition du reçu'); + } + catch (UserException $e) + { + $form->addError($e->getMessage()); + } + } + +} + + +try +{ + $r = $facture->getCotis((int)$membre_id); + // Garde seulement les champs requis + // Rattrape le bouton radio à pré-sélectionner + // Passe les expiration nulles (cotis ponctuelle) à 0 pour avoir moins d'embrouilles + foreach ($r as $i=>$cotis) + { + foreach($cotis as $k=>$v) + { + if (in_array($k, $fields)) + { + $liste[$i][$k] = $v; + } + } + + if($liste[$i]['id'] == $f->contenu['id']) + { + $radio = 'cotis_'.$i; + } + + if($liste[$i]['expiration'] < 0) + { + $liste[$i]['expiration'] = 0; + } + } +} +catch (UserException $e) +{ + $form->addError($e->getMessage()); +} + + +$tpl->assign('liste', $liste); +$tpl->assign('radio', $radio); +$tpl->assign('values', $values); + +// $tpl->assign('step', $step); +$tpl->assign('identite', $identite); +$tpl->assign('membre_id', $membre_id); +$tpl->assign('membres', (array)DB::getInstance()->get('SELECT id, '.$identite.' FROM membres WHERE id_categorie != -2 NOT IN (SELECT id FROM membres_categories WHERE cacher = 1);')); + +$tpl->display(PLUGIN_ROOT . '/templates/cotis_modifier.tpl'); diff --git a/www/admin/facture_ajouter.php b/www/admin/facture_ajouter.php index e9286ff..825898e 100644 --- a/www/admin/facture_ajouter.php +++ b/www/admin/facture_ajouter.php @@ -98,6 +98,25 @@ if (f('add')) } +$type = qg('t'); +$radio = []; +if (is_numeric($type)) +{ + switch($type) + { + case 0: + $radio['type'] = 'devis'; + break; + case 2: + $radio['type'] = 'cerfa'; + break; + case 1: + default: + $radio['type'] = 'facture'; + break; + } +} +$tpl->assign('radio', $radio); $tpl->assign('client_id', f('client') ?: -1); $tpl->assign('membre_id', f('membre') ?: -1); diff --git a/www/admin/facture_modifier.php b/www/admin/facture_modifier.php index 853528c..d14b8a4 100644 --- a/www/admin/facture_modifier.php +++ b/www/admin/facture_modifier.php @@ -11,9 +11,7 @@ use Garradin\DB; qv(['id' => 'required|numeric']); $id = (int) qg('id'); -$f = $facture->get($id); - -if (!$f) +if (!$f = $facture->get($id)) { throw new UserException("Ce document n'existe pas."); } diff --git a/www/admin/pdf.php b/www/admin/pdf.php index c88b446..c241607 100644 --- a/www/admin/pdf.php +++ b/www/admin/pdf.php @@ -322,54 +322,139 @@ elseif ($f->type_facture == 3) ob_start(); $doc = 'Reçu n°'.$f->numero; - $emission = date('d/m/Y' ,$f->date_emission); + $emission = date('d/m/Y',$f->date_emission); $pdf->SetTitle($doc.' - '.$emission); - + $asso = - // 'Émis par :

'. - ''.$config->get('nom_asso')."
". - str_replace("\n", '
', $config->get('adresse_asso'))."
". - (($t = $plugin->getConfig('rna_asso'))?"RNA : $t
":''). - (($t = $plugin->getConfig('siret_asso'))?"SIRET : $t
":''). - (($t = $config->get('email_asso'))?"Email : $t
":''). - (($t = $config->get('site_asso'))?"Site web : $t
":''); - + // 'Émis par :

'. + ''.$config->get('nom_asso')."
". + str_replace("\n", '
', $config->get('adresse_asso'))."
". + (($t = $plugin->getConfig('rna_asso'))?"RNA : $t
":''). + (($t = $plugin->getConfig('siret_asso'))?"SIRET : $t
":''). + (($t = $config->get('email_asso'))?"Email : $t
":''). + (($t = $config->get('site_asso'))?"Site web : $t
":''); + $receveur = - 'Adressé à :

'. - ''.$c->identite.'
'. - $c->adresse."
". - $c->code_postal.' '.$c->ville."
". - (($t = $c->email)?"Email : $t
":''). - (($t = $c->telephone)?"Tel : $t
":''); - + 'Adressé à :

'. + ''.$c->identite.'
'. + $c->adresse."
". + $c->code_postal.' '.$c->ville."
". + (($t = $c->email)?"Email : $t
":''). + (($t = $c->telephone)?"Tel : $t
":''); + $total = number_format($f->total, 2, ',', ' '); - $echeance = date('d/m/Y' ,$f->date_echeance); - $footer = str_replace("\n", '
', $plugin->getConfig('footer')); $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') + { + $expiration = "jour même, s'agissant d'une cotisation ponctuelle."; + } + else { + $expiration = date('d/m/Y', strtotime($f->contenu['expiration'])); + } + echo << + + + + +
+

+$doc - Émis le $emission +

+ + + + + + +
$asso$receveur
+
+
+ Reçu de votre cotisation - $doc +
+
+

-$asso +Bonjour,

-$receveur -

-À $lieu, le $echeance, +À $lieu, le $emission,

-Nous accusons réception de votre cotisation reçue le $emission et nous vous en remercions. +Nous accusons réception de votre cotisation « $intitule » reçue le $emission et nous vous en remercions.

Nous reconnaissons que vous avez acquitté la somme de $total € par $moyen_paiement .
-Votre adhésion sera donc effective à compter du DATE?? jusqu’au DATE??. +Votre adhésion sera donc effective à compter du $souscription jusqu’au $expiration.


Nous vous prions de recevoir, chère adhérente, cher adhérent, nos meilleures salutations, -

-Moi JE Chef


-Nous vous rappelons que la cotisation n’est pas soumise à la TVA et qu’elle ne donne pas lieu à la délivrance d’une facture. Elle n’ouvre pas droit au bénéfice des dispositions des articles 200, 238 bis et 885-0 V bis A du code général des impôts. +-représentant·e de l'asso- +


+Nous vous rappelons que la cotisation n’est pas soumise à la TVA et qu’elle ne donne pas lieu à la délivrance d’une facture. Elle n’ouvre pas droit au bénéfice des dispositions des articles 200, 238 bis et 885-0 V bis A du code général des impôts. EOF; $html = ob_get_clean();