diff --git a/CHANGELOG b/CHANGELOG
index e42abea..e4e5dae 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,11 @@
+0.12
+- Ajout Mollie à la table moyens de paiement
+0.11
+- Changement mention finale pour devis
+0.9
+- Ajout possibilité choisir champs identité et adresse membre
+0.8.8
+- correction typo
0.8.7
- correction typo
0.8.6
diff --git a/README.md b/README.md
index 1829668..8685449 100644
--- a/README.md
+++ b/README.md
@@ -1,56 +1,50 @@
# Plugin Facturation pour Paheko (ex Garradin)
-Plugin de facturation pour le logiciel de gestion d'association Paheko ( https://paheko.eu/ - https://fossil.kd2.org/paheko ).
+Plugin de facturation pour le logiciel de gestion d'association Paheko
+( https://paheko.eu/ - https://fossil.kd2.org/paheko ).
+
Source :
-- version historique : https://gitlab.com/noizette/garradin-plugin-facturation
- version compatible paheko 1.3.x : https://git.roflcopter.fr/lesanges/facturation
+- version historique non compatible paheko 1.3.x : https://gitlab.com/noizette/garradin-plugin-facturation
-## Installation:
-Vous pouvez télécharger l'archive .tar.gz depuis la page des [releases](https://git.roflcopter.fr/lesanges/paheko-plugin-facturation/releases), supprimer le numéro de version du nom de l'archive puis la placer dans le dossier plugins de Paheko.
-
-### Anciennes versions (<0.6)
-
-Normalement, les plugins de Paheko doivent seulement être laissé sous forme d'archive .tar.gz dans le dossier plugins, or pour la génération des PDF, la librairie mPDF a besoin d'écrire des fichiers temporaires.
-
-Il faut pour cela faire :
-
- tar xvf paheko-plugin-facturation-v0.5.0.tar.gz
- mv paheko-plugin-facturation-v0.5.0 facturation
- rm paheko-plugin-facturation-v0.5.0.tar.gz
- chown -R www-data:www-data facturation/
- chmod -R g+w facturation/
-
-
-Supprimer l'archive permet à Paheko de ne pas la lire à la place du dossier.
-
-*Note : www-data correspond dans la plupart des cas à l'utlisateur d'Apache, si vous utilisez un autre serveur web, il faudra probablement adapter.*
-
-## Migration vers Garradin 1.0 (obsolète)
-
-Lorsque vous tentez de mettre à jour une installation de Garradin avec le plugin facturation vers Garradin 1.0, l'upgrade est bloquée par le plugin.
-
-Pour remédier à cela et parvenir à faire la mise à jour, il faut dans un premier temps installer la version 0.4 du plugin sur votre installation Garradin 0.9.8, se rendre sur la page principale du plugin (menu > Facturation), vous pouvez ensuite mettre à jour Garradin vers la 1.0.
+## Installation :
+Vous pouvez télécharger l'archive .tar.gz depuis la page des
+[releases](https://git.roflcopter.fr/lesanges/paheko-plugin-facturation/releases),
+supprimer le numéro de version du nom de l'archive puis la placer dans
+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)
- - Modification du pied de page des documents (notament pour y inscrire des mentions légales)
+ - Possibilité de choisir certains champs à faire figurer sur la facture (adresse, code postal, ville)
+ - Modification du pied de page des documents (notamment 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 set 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 fiche.
+Note : pour le moment, les actions sur la liste des clients à cocher
+ne fonctionnent pas. Pour supprimer un client, le faire depuis sa
+fiche.
-## Futur :
-- Ajout des champs Référence, Prix unitaire, Quantité sur les documents
+## Futur de ce plugin :
+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 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
- Actions sur liste de client·es (exporter, supprimer)
- Afficher/filtrer les documents par statuts réglé/archivé
- Changer statut depuis la liste des documents
@@ -59,15 +53,12 @@ Note : pour le moment, les actions sur la liste des clients à cocher ne fonctio
- Gestion TVA ?
- Un devis ne devrait pas pouvoir être réglé
- Quid si un·e membre de l'asso est supprimé·e alors que des documents lui sont adressés ?
-
-## Futur improbable :
- Opérations de paiements dans la compta liés à une facture
- Gestion de produits
+Le plugin nécessite l'extension PHP mbstring.
-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/_facture_common.php b/admin/_facture_common.php
index ecc0c30..b729f34 100644
--- a/admin/_facture_common.php
+++ b/admin/_facture_common.php
@@ -4,6 +4,28 @@ namespace Paheko;
require_once __DIR__ . '/_inc.php';
+function toArray($array, $cle, $sep=",")
+{
+ $result = array();
+ foreach ($array as $elem)
+ {
+ $ro = new \ReflectionObject($elem);
+ $proprietes = $ro->getProperties();
+ $ligne = "";
+ foreach ($proprietes as $p)
+ {
+ if ($p->getName() == $cle) {
+ $key = $p->getValue($elem);
+ }
+ else {
+ $ligne .= $sep . $p->getValue($elem);
+ }
+ }
+ $result[$key] = substr($ligne, strlen($sep));
+ }
+ return $result;
+}
+
if (!isset($target) || !in_array( $target, ['new', 'edit'])) {
throw new Exception('blabla illegal call'); // Fix: exception type?
} else {
@@ -67,15 +89,21 @@ $form->runIf(f('save') && !$form->hasErrors(),
'reglee' => f('reglee') == 1?1:0,
'archivee' => f('archivee') == 1?1:0,
'moyen_paiement' => f('moyen_paiement'),
+ 'nom_contact' => f('nom_contact'),
'toto' => 0
];
$data['type_facture'] = f('type');
if (in_array(f('type'), [DEVIS, FACT]))
{
- foreach(f('designation') as $k=>$value)
+ foreach(f('designation') as $k=>$value)
{
- if ($value != '' && f('prix')[$k] == null) {
+ if (empty($value) && f('prix')[$k] != null) {
+ throw new UserException("Il manque la désignation de la ligne " . $k+1 . " !!");
+ }
+ elseif ($value != '' && f('prix')[$k] == null) {
throw new UserException('Il manque le prix sur la ligne '. $k+1 . ' !!');
+ } elseif (empty($value) && f('prix')[$k] == null) {
+ continue;
}
$data['contenu'][$k]['designation'] = $value;
@@ -84,7 +112,14 @@ $form->runIf(f('save') && !$form->hasErrors(),
}
$data['total'] = $data['toto'];
unset($data['toto']);
- }
+ if (! isset($data['contenu'])) {
+ throw new UserException("Aucune désignation ni aucun prix saisi !!");
+ }
+ if (f('type') == FACT) {
+ $data['numero_commande'] = f('numero_commande');
+ $data['reference_acheteur'] = f('reference_acheteur');
+ }
+ }
elseif ( f('type') == CERFA )
{
$data['moyen_paiement'] = f('moyen_paiement_cerfa');
@@ -120,45 +155,45 @@ $form->runIf(f('save') && !$form->hasErrors(),
$form->runIf(f('select_cotis') && !$form->hasErrors(),
function () use ($step)
- {
- $step = true;
- }, 'add_cotis_1');
+ {
+ $step = true;
+ }, 'add_cotis_1');
$form->runIf(f('add_cotis') && !$form->hasErrors(),
function () use ($radio, $fields, $facture, $form)
- {
- $radio['type'] = f('cotisation');
- try
- {
- $num = (int) str_replace('cotis_', '', $radio['type']);
- foreach($fields as $field)
- {
- $cotis[$field] = f($field.'_'.$num);
- }
+ {
+ $radio['type'] = f('cotisation');
+ try
+ {
+ $num = (int) str_replace('cotis_', '', $radio['type']);
+ foreach($fields as $field)
+ {
+ $cotis[$field] = f($field.'_'.$num);
+ }
- $r = $facture->getCotis(f('membre_cotis'), $cotis['id']);
- $r = $r[0];
+ $r = $facture->getCotis(f('membre_cotis'), $cotis['id']);
+ $r = $r[0];
- $data = [
- 'type_facture' => COTIS,
- 'numero' => f('numero_facture'),
- 'receveur_membre' => 1,
- 'receveur_id' => f('membre_cotis'),
- 'date_emission' => f('date_emission'),
- 'moyen_paiement' => 'AU',
- 'total' => $r->paid_amount ?? $r->amount,
- 'contenu' => ['id' => $cotis['id'],
- 'intitule' => $cotis['label'],
- 'souscription' => $cotis['date'],
- 'expiration' => $cotis['expiry'] ]
- ];
+ $data = [
+ 'type_facture' => COTIS,
+ 'numero' => f('numero_facture'),
+ 'receveur_membre' => 1,
+ 'receveur_id' => f('membre_cotis'),
+ 'date_emission' => f('date_emission'),
+ 'moyen_paiement' => 'AU',
+ 'total' => $r->paid_amount ?? $r->amount,
+ 'contenu' => ['id' => $cotis['id'],
+ 'intitule' => $cotis['label'],
+ 'souscription' => $cotis['date'],
+ 'expiration' => $cotis['expiry'] ]
+ ];
- }
- catch (UserException $e)
- {
- $form->addError($e->getMessage());
- }
- }, 'add_cotis_2');
+ }
+ catch (UserException $e)
+ {
+ $form->addError($e->getMessage());
+ }
+ }, 'add_cotis_2');
if (! $form->hasErrors())
{
@@ -246,6 +281,9 @@ else
$doc['date_emission'] = f('date_emission') ?: $f->date_emission;
$doc['date_echeance'] = f('date_echeance')?: $f->date_echeance; // Smarty m'a saoulé pour utiliser form_field|date_fr:---
+ $doc['nom_contact'] = $f->nom_contact;
+ $doc['numero_commande'] = $f->numero_commande;
+ $doc['reference_acheteur'] = $f->reference_acheteur;
/* modif DD -- CERFA -------------------------------------- */
if ( $f->type_facture == CERFA ) {
$doc['total'] = $f->total;
@@ -292,8 +330,10 @@ if (in_array($radio['type'], [DEVIS, FACT]))
}
}
else {
- $designations = ['Exemple'];
- $prix = [250];
+ /*
+ $designations = ['Exemple'];
+ $prix = [250];
+ */
}
}
@@ -301,10 +341,10 @@ $date = new \DateTime;
$date->setTimestamp(time());
$tpl->assign('date', $date->format('d/m/Y'));
-
$tpl->assign(compact('liste', 'radio', 'step', 'designations', 'prix', 'from_user', 'identite', 'csrf_key', 'doc'));
-$tpl->assign('users', $db->getAssoc('SELECT id, '.$identite.' FROM users WHERE id_category != -2 NOT IN (SELECT id FROM users_categories WHERE hidden = 1) ORDER BY ' .$identite. ';'));
+$tpl->assign('users', toArray($db->get('SELECT id, '.$identite.' FROM users WHERE id_category != -2 NOT IN (SELECT id FROM users_categories WHERE hidden = 1) ORDER BY ' .$identite. ';'), 'id', " "));
$tpl->assign('clients', $db->getAssoc('SELECT id, nom FROM plugin_facturation_clients;'));
+$tpl->assign('contacts', $db->getAssoc('SELECT id, nom_contact FROM plugin_facturation_clients;'));
$tpl->assign('require_number', $require_number);
$tpl->assign('number_pattern', PATTERNS_LIST[$plugin->getConfig('pattern')]);
diff --git a/admin/_inc.php b/admin/_inc.php
index 582e462..f11fc22 100644
--- a/admin/_inc.php
+++ b/admin/_inc.php
@@ -11,7 +11,7 @@ define('CERFA', 2);
define('COTIS', 3);
const PATTERNS_LIST = [
- null => 'Aucun, le numéro sera à spécifier manuellement pour chaque document',
+ '' => 'Aucun, le numéro sera à spécifier manuellement pour chaque document',
'%{type}-%{year}-%{ynumber}' => 'Type-Année-Numéro du document par année ("FACT-2021-42")',
'%{year}-%{type}-%04{ynumber}' => 'Année-Type-Numéro du document par année ("2021-DEVIS-0042")',
'%{t}-%{year}-%{ynumber}' => 'Type court-Année-Numéro du document par année ("F-2021-42")',
@@ -48,11 +48,11 @@ $tpl->register_function('money_fac', function (array $params)
if (!isset($user)) {
$user = false;
- }
+ }
if (!isset($name))
{
- $name = 'prix[]';
+ $name = 'prix[]';
}
if (null !== $current_value && !$user) {
@@ -62,7 +62,7 @@ $tpl->register_function('money_fac', function (array $params)
if (null !== $current_value) {
$current_value = htmlspecialchars($current_value, ENT_QUOTES, 'UTF-8');
}
-
+
$currency = Config::getInstance()->get('monnaie');
return sprintf('
';
echo str_replace("\n", ' ', $v['designation']);
echo ' | ';
@@ -170,12 +202,17 @@ EOF;
$echeance
$reglee
Moyen de paiement : $moyen_paiement
-
$footer
+
EOF;
+ if ($f->type_facture == DEVIS) {
+ echo <<Bon pour accord, date et signature
+EOF;
+ }
$content = ob_get_clean();
@@ -184,7 +221,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')
@@ -220,7 +257,7 @@ EOF;
}
//-- Layout du document
-
+
ob_start();
echo <<
@@ -233,7 +270,7 @@ EOF;
size: A4 portrait;
margin: 0;
}
-
+
body {
padding: 4mm;
font-family: Helvetica, Arial, sans;
@@ -267,6 +304,13 @@ EOF;
width: 40%;
vertical-align: top;
}
+ .adressage td#logo {
+ width: 20%;
+ vertical-align: top;
+ }
+ .adressage img#logo {
+ height : 3cm;
+ }
.contenuTexte {
padding: 0 6mm;
@@ -318,6 +362,7 @@ EOF;
+ | $logo |
$asso |
$receveur |
@@ -348,7 +393,7 @@ elseif ($f->type_facture == CERFA)
$t['objet1'] = $plugin->getConfig('objet_1');
$t['objet2'] = $plugin->getConfig('objet_2');
- $t['nom'] = $c->nom;
+ $t['nom'] = $nom_client;
$t['adresse'] = $c->adresse;
$t['cp'] = $c->code_postal;
$t['ville'] = $c->ville;
@@ -363,7 +408,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';
@@ -429,7 +474,7 @@ elseif ($f->type_facture == CERFA)
margin: 0;
padding: 0;
}
-
+
body {
font-family: Helvetica, Arial, sans;
font-size: 10pt;
@@ -451,11 +496,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;
@@ -519,7 +564,7 @@ if(qg('d') !== null)
{
$filename = 'Print';
if (preg_match('!(.*)!U', $html, $match)) {
- $filename = trim($match[1]);
+ $filename = str_replace(" ", "_", trim($match[1]));
}
header('Content-type: application/pdf');
diff --git a/data/schema.sql b/data/schema.sql
index 0cc7a67..923b4eb 100644
--- a/data/schema.sql
+++ b/data/schema.sql
@@ -10,7 +10,10 @@ CREATE TABLE IF NOT EXISTS plugin_facturation_factures (
archivee INTEGER DEFAULT 0, -- bool
moyen_paiement TEXT NOT NULL,
contenu TEXT NOT NULL,
- total INTEGER DEFAULT 0
+ total INTEGER DEFAULT 0,
+ nom_contact TEXT,
+ numero_commande TEXT,
+ reference_acheteur TEXT
-- FOREIGN KEY(moyen_paiement) REFERENCES compta_moyens_paiement(code)
);
@@ -24,7 +27,9 @@ CREATE TABLE IF NOT EXISTS plugin_facturation_clients (
siret TEXT,
date_creation TEXT NOT NULL DEFAULT CURRENT_DATE CHECK (date(date_creation) IS NOT NULL AND date(date_creation) = date_creation), -- Date d\'inscription
telephone TEXT,
- email TEXT
+ email TEXT,
+ nom_contact TEXT,
+ note TEXT
);
@@ -43,6 +48,7 @@ INSERT OR IGNORE INTO plugin_facturation_paiement (code, nom) VALUES ('PR', 'Pr
INSERT OR IGNORE INTO plugin_facturation_paiement (code, nom) VALUES ('TI', 'TIP');
INSERT OR IGNORE INTO plugin_facturation_paiement (code, nom) VALUES ('VI', 'Virement');
INSERT OR IGNORE INTO plugin_facturation_paiement (code, nom) VALUES ('HA', 'HelloAsso');
+INSERT OR IGNORE INTO plugin_facturation_paiement (code, nom) VALUES ('MO', 'Mollie');
INSERT OR IGNORE INTO plugin_facturation_paiement (code, nom) VALUES ('AU', 'Autre');
-- Modif DD -- ajout de la table des textes associés aux CERFA
diff --git a/lib/Client.php b/lib/Client.php
index 66aabf3..66e7d75 100644
--- a/lib/Client.php
+++ b/lib/Client.php
@@ -17,7 +17,9 @@ class Client
'ville',
'siret',
'telephone',
- 'email'
+ 'email',
+ 'nom_contact',
+ 'note'
];
private $config = [
@@ -40,7 +42,7 @@ class Client
{
$data[$key] = trim($data[$key]);
- if($data[$key] == '' && ($key != 'siret' && $key != 'telephone' && $key != 'email'))
+ if($data[$key] == '' && ! in_array($key, ['siret', 'telephone', 'email', 'nom_contact', 'note']))
{
throw new UserException('Le champs '.$key.' doit être renseigné.');
}
@@ -136,6 +138,12 @@ class Client
'email' => [
'label' => 'E-Mail',
],
+ 'nom_contact' => [
+ 'label' => 'Contact',
+ ],
+ 'note' => [
+ 'label' => 'Note',
+ ],
'nb_documents' => [
'label' => 'Nombre de documents',
'select' => '(SELECT COUNT(*) FROM plugin_facturation_factures WHERE receveur_id = c.id)',
diff --git a/lib/Facture.php b/lib/Facture.php
index 0776728..270fca7 100644
--- a/lib/Facture.php
+++ b/lib/Facture.php
@@ -30,31 +30,24 @@ class Facture
'archivee',
'moyen_paiement',
'contenu',
- 'total'
+ 'total',
+ 'nom_contact',
+ 'numero_commande',
+ 'reference_acheteur'
];
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' => ''],
+ ];
public function __construct()
{
@@ -75,116 +68,119 @@ class Facture
if(!is_array($data) && null !== $data){
$datas[$k] = trim($data);
}
- if ($datas[$k] === '' && $k != 'numero')
+ if ($datas[$k] === '' && ! in_array($k, ['numero', 'nom_contact', 'numero_commande', 'reference_acheteur']))
{
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 (! is_numeric($r['prix']) && empty($r['prix']))
{
- throw new UserException("Toutes les désignations/prix sont vides.");
+ $datas[$k]['prix'] = 0;
+ }
+ elseif (empty($r['designation'])) {
+ throw new UserException("Une au moins des désignations est absente.");
}
- }
- 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 && count($datas['contenu']) == 0)
{
- // $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 +283,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 +321,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 +353,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',
@@ -391,7 +398,6 @@ class Facture
$list = new DynamicList($columns, $tables);
$list->orderBy('date_emission', true);
- $list->setCount('COUNT(f.id)');
$currency = Config::getInstance()->monnaie;
@@ -406,8 +412,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) {
@@ -492,7 +498,7 @@ class Facture
public $recu_fields = ['id', 'label', 'amount', 'date', 'expiry', 'paid', 'paid_amount'];
- public function getCotis(int $user_id, int $su_id = null)
+ public function getCotis(int $user_id, ?int $su_id = null)
{
$where = 'WHERE su.id_user = ?';
if (null !== $su_id)
@@ -506,7 +512,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 +532,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/plugin.ini b/plugin.ini
index e4cd258..c75a449 100644
--- a/plugin.ini
+++ b/plugin.ini
@@ -1,8 +1,8 @@
name="Facturation"
-description="Permet d'éditer des factures, devis et reçus à ses membres ainsi qu'à une base de clients supplémentaire."
+description="Permet d'éditer des factures et devis à ses membres ainsi qu'à une base de clients supplémentaire."
author="zou ; adapté par jce"
url="https://git.roflcopter.fr/lesanges/paheko-plugin-facturation"
-version="0.8.7"
+version="0.16"
menu=true
restrict_section="accounting"
restrict_level="read"
diff --git a/templates/_form.tpl b/templates/_form.tpl
index 3e6029d..f533acf 100644
--- a/templates/_form.tpl
+++ b/templates/_form.tpl
@@ -3,7 +3,7 @@
|