diff --git a/CHANGELOG b/CHANGELOG
deleted file mode 100644
index e4e5dae..0000000
--- a/CHANGELOG
+++ /dev/null
@@ -1,87 +0,0 @@
-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
-- Correction erreur si pas de prix saisi
-0.8.5
-- Ajout numéro SIREN/SIRET pour les clients
-- Ajout pagination liste factures
-
-0.8.4
-- Correction bug si identité définie par plusieurs champs
-- Correction bug oubli choix receveur
-- Mise-à-jour Changelog
-
-0.8.3 :
-- Mise-à-jour README
-
-0.8.2 :
-- Tri des membres en ordre alphabétique
-- Élimination de plusieurs bugs
-
-0.8.1 :
-- reprise du code par jce (lesanges@zaclys.net ; https://git.roflcopter.fr/lesanges/paheko-plugin-facturation)
-- Achèvement migration vers Paheko 1.3
-
-0.7.4 :
-- Corrections de dépréciations PHP, le plugin être compatible PHP8.2
-- Quelques problèmes réglés de formulaires invalidables
-- Nettoyage du code et factorization des facture_{ajouter,modifier}.php
-
-0.7.3 :
-- Règle le problème de formulaire bloqué que je croyais avoir résolu la dernière fois :)
-
-0.7.2 :
-- Petite correction du moyen de paiement qui n'était pas retenu à cause d'un doublon dans le formulaire.
-
-0.7.1 :
-- Ajout d'une case dans la config pour choisir si les factures sont TTC ou HT
-- Le formulaire de document était cassé à cause d'un champs obligatoire invisible
-
-0.7.0 :
-- Modernisation des formulaires, de la fiche client
-- Liste dynamiques des documents et des clients + export CSV/ODS
-- Numérotation automatique des documents
-- Ajout du bouton Dupliquer sur les documents
-- Divers fixes
-- Changements de la gestion des CERFA :
- - organisation du champ `contenu` pour gérer les paramètres de CERFA sous la forme {"forme":"3","nature":"1","texte":"1"}
- - ajout d'une table `plugin_facturation_txt_cerfa` pour stocker les textes explicatifs additionnels
- - formulaires adaptés aux CERFA pour permettre le choix de la forme, de la nature, du mode de versement et du texte explicatif éventuel
-
-0.6.0 :
-- Génération des PDF par Garradin, on se débarasse de mPDF et l'installation du plugin devient standard
-- Fix #32 (prix total affiché incorrect), en stockant les prix sous formes d'entiers à la manière de Garradin
-- Possibilité de supprimer un document
-- Fix #34, problème sélection membre
-
-0.5.0 :
-Mise à jour rapide du plugin pour Garradin 1.1.
-La gestion de la signature dans les reçus fiscaux a été désactivés pour l'instant (changements de méthodes avec Garradin 1.1, flemme de m'y pencher pour le moment)
-
-0.4.1 :
-Release mineure qui corrige un problème qui apparaît, selon la configuration de PHP (?), lors de la migration depuis une version précédente.
-
-0.4.0 :
-Cette version a pour principal but d'être compatible avec Garradin 1.0 et de ne pas empêcher la mise à jour d'une ancienne installation comprenant une ancienne version du plugin.
-Le formulaire de création/édition de document a été modifié pour simplifier l'expérience utilisateur : tout les types de documents se font depuis le même formulaire, suivi des évolutions graphiques/ergonomiques de Garradin.
-
-0.3.0 :
-- Ajouts des reçus fiscaux et des reçus sur des cotisations :
-- Génération du cerfa pour reçu fiscaux, paramètres disponibles dans la config
-- Ajout d'une page d'aide
-- L'identité des destinataires membres est maintenant définie selon la configuration de Garradin, et non plus de manière statique sur la colonne "nom"
-- Suppression de la classe Facturation\Config pour utiliser celle que propose Garradin
-- Ajout du champs de numéro RNA
-
-
-0.2.0 :
-- Stockage des désignations des documents changé de serialize à json_decode
-- Petites améliorations sur les formulaires
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..cbd5b07
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,160 @@
+# Changelog
+
+## v0.27.2 - 2026-07-02
+### Changed
+- Conserver les tags html dans les libellés
+
+## v0.25 - 2026-05-15 - Jason Pelletier
+### Added
+- Options d'affichage du rendu facture
+
+## v0.19 - 2026-05-15 - Jason Pelletier
+### Fixed
+- Réparation des schémas partiellement migrés
+
+## v0.18 - 2026-05-15 - Jason Pelletier
+### Changed
+- améliorations proposées par Jason Pelletier
+### Added
+- Personnalisation du rendu des factures
+
+## v0.17 - 2026-02-26 - @jce
+### Added
+- archivage factures
+
+## v0.15 - 2025-03-25 - @jce
+### Added
+- champ contact à la fiche client
+
+## v0.13 - 2025-02-26 - @jce
+### Changed
+- Amélioration contrôles saisie facture
+
+## v0.12 - 2025-01-04 - @jce
+### Added
+- Mollie à la table moyens de paiement
+
+## v0.11 - 2024-10-19 - @jce
+### Changed
+- mention finale pour devis
+
+## v0.9 - 2024-08-30 - @jce
+### Added
+- possibilité choisir champs identité et adresse membre
+
+## v0.8.8 - 2024-08-13 - @jce
+### Added
+- impression logo avec option de configuration
+### Changed
+- Adaptation Readme à la situation actuelle
+
+## v0.8.6 - 2024-03-29 - @jce
+### Fixed
+- Erreur si pas de prix saisi
+
+## v0.8.5 - 2024-01-12 - @jce
+### Added
+- numéro SIREN/SIRET pour les clients
+- pagination liste factures
+
+## v0.8.4 - 2024-01-11 - @jce
+### Fixed
+- Bug si identité définie par plusieurs champs
+- Bug oubli choix receveur
+
+## v0.8.2 - 2024-01-10 - @jce
+### Added
+- Tri des membres en ordre alphabétique
+### Fixed
+- Élimination de plusieurs bugs
+
+## v0.8.1 - 2023-11-03 - @jce
+### Changed
+- reprise du code par jce (lesanges@zaclys.net ; https://gitea.zaclys.com/lesanges/facturation)
+- Achèvement migration vers Paheko 1.3
+
+## v0.7.4 - 2023-04-16 - @noizette
+### Fixed
+- Corrections de dépréciations PHP, le plugin être compatible PHP8.2
+### Changed
+- Quelques problèmes réglés de formulaires invalidables
+- Nettoyage du code et factorization des facture_{ajouter,modifier}.php
+
+## v0.7.3 - 2022-03-03 - @noizette
+### Fixed
+- Règle le problème de formulaire bloqué que je croyais avoir résolu la dernière fois :)
+
+## v0.7.2 - 2022-01-31 - @noizette
+### Fixed
+- Petite correction du moyen de paiement qui n'était pas retenu à cause d'un doublon dans le formulaire.
+
+## v0.7.1 - 2022-01-10 - @noizette
+### Added
+- ajout d'une case dans la config pour choisir si les factures sont TTC ou HT
+### Fixed
+- Le formulaire de document était cassé à cause d'un champs obligatoire invisible
+
+## v0.7.0 - @noizette
+### Changed
+- Modernisation des formulaires, de la fiche client
+- Liste dynamiques des documents et des clients + export CSV/ODS
+- Numérotation automatique des documents
+- Divers fixes
+- Changements de la gestion des CERFA :
+ - organisation du champ `contenu` pour gérer les paramètres de CERFA sous la forme {"forme":"3","nature":"1","texte":"1"}
+ - ajout d'une table `plugin_facturation_txt_cerfa` pour stocker les textes explicatifs additionnels
+ - formulaires adaptés aux CERFA pour permettre le choix de la forme, de la nature, du mode de versement et du texte explicatif éventuel
+### Added
+- Ajout du bouton Dupliquer sur les documents
+
+## v0.6.0 - @noizette
+### Changed
+- Génération des PDF par Garradin, on se débarasse de mPDF et l'installation du plugin devient standard
+- Possibilité de supprimer un document
+### Fixed
+- Fix #32 (prix total affiché incorrect), en stockant les prix sous formes d'entiers à la manière de Garradin
+- Fix #34, problème sélection membre
+
+## v0.5.0 - @noizette
+### Added
+Mise à jour rapide du plugin pour Garradin 1.1.
+### Changed
+- La gestion de la signature dans les reçus fiscaux a été désactivés
+ pour l'instant (changements de méthodes avec Garradin 1.1, flemme de
+ m'y pencher pour le moment)
+
+## v0.4.1 - @noizette
+### Fixed
+- Release mineure qui corrige un problème qui apparaît, selon la
+ configuration de PHP (?), lors de la migration depuis une version
+ précédente.
+
+## v0.4.0 - @noizette
+### Changed
+- Cette version a pour principal but d'être compatible avec Garradin
+ 1.0 et de ne pas empêcher la mise à jour d'une ancienne installation
+ comprenant une ancienne version du plugin.
+- Le formulaire de création/édition de document a été modifié pour
+ simplifier l'expérience utilisateur : tout les types de documents se
+ font depuis le même formulaire, suivi des évolutions
+ graphiques/ergonomiques de Garradin.
+
+## v0.3.0 - @noizette
+### Added
+- Ajouts des reçus fiscaux et des reçus sur des cotisations :
+- Génération du cerfa pour reçu fiscaux, paramètres disponibles dans la config
+- Ajout d'une page d'aide
+- Ajout du champs de numéro RNA
+### Changed
+- L'identité des destinataires membres est maintenant définie selon la
+ configuration de Garradin, et non plus de manière statique sur la
+ colonne "nom"
+### Removed
+- Suppression de la classe Facturation\Config pour utiliser celle que
+ propose Garradin
+
+## v0.2.0 - @noizette
+### Added
+- Stockage des désignations des documents changé de serialize à json_decode
+### Changed
+- Petites améliorations sur les formulaires
diff --git a/admin/_facture_common.php b/admin/_facture_common.php
index 9fbb19c..2be8c6b 100644
--- a/admin/_facture_common.php
+++ b/admin/_facture_common.php
@@ -4,30 +4,8 @@ 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?
+ throw new \LogicException('Appel interne invalide du formulaire de document.');
} else {
$target = ($target === 'new' ? true:false);
}
@@ -35,7 +13,6 @@ if (!isset($target) || !in_array( $target, ['new', 'edit'])) {
$session->requireAccess($session::SECTION_ACCOUNTING, $session::ACCESS_WRITE);
use Paheko\DB;
-use stdClass;
use const \Paheko\Plugin\Facturation\PATTERNS_LIST;
$db = DB::getInstance();
@@ -69,21 +46,18 @@ if ( !$target ) {
throw new UserException("Ce document n'existe pas.");
}
}
-if (! $target && $f->archivee)
+if (!$target && $f->archivee)
{
throw new UserException("Ce document est archivé, vous n'avez pas le droit de le modifier");
}
-// Traitement
+// Traitement
$data=[];
$form->runIf(f('save') && !$form->hasErrors(),
- function () use ($client, &$data, $form)
+ function () use (&$data, $form)
{
try
{
- if ( count(f('designation')) !== count(f('prix')) )
- {
- throw new UserException('Nombre de désignations et de prix reçus différent.');
- }
+ $type = (int) f('type');
$data = [
'numero' => f('numero_facture'),
@@ -93,37 +67,51 @@ $form->runIf(f('save') && !$form->hasErrors(),
'archivee' => f('archivee') == 1?1:0,
'moyen_paiement' => f('moyen_paiement'),
'nom_contact' => f('nom_contact'),
- 'toto' => 0
+ 'numero_commande' => f('numero_commande') ?: null,
+ 'reference_acheteur' => f('reference_acheteur') ?: null,
];
- $data['type_facture'] = f('type');
- if (in_array(f('type'), [DEVIS, FACT]))
+
+ $data['type_facture'] = $type;
+
+ if (in_array($type, [DEVIS, FACT], true))
{
- foreach(f('designation') as $k=>$value)
+ $designations = (array) f('designation');
+ $prix = (array) f('prix');
+
+ if (count($designations) !== count($prix))
+ {
+ throw new UserException('Nombre de désignations et de prix reçus différent.');
+ }
+
+ $total = 0;
+
+ foreach($designations as $k=>$value)
{
- if (empty($value) && f('prix')[$k] != null) {
- throw new UserException("Il manque la désignation de la ligne " . $k+1 . " !!");
+ $prix_ligne = $prix[$k] ?? null;
+
+ if (empty($value) && $prix_ligne !== null && $prix_ligne !== '') {
+ 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) {
+ elseif ($value != '' && ($prix_ligne === null || $prix_ligne === '')) {
+ throw new UserException('Il manque le prix sur la ligne '. ($k + 1) . ' !!');
+ }
+ elseif (empty($value) && ($prix_ligne === null || $prix_ligne === '')) {
continue;
}
+ $prix_ligne = Utils::moneyToInteger($prix_ligne);
$data['contenu'][$k]['designation'] = $value;
- $data['contenu'][$k]['prix'] = Utils::moneyToInteger(f('prix')[$k]);
- $data['toto'] += Utils::moneyToInteger(f('prix')[$k]);
+ $data['contenu'][$k]['prix'] = $prix_ligne;
+ $total += $prix_ligne;
}
- $data['total'] = $data['toto'];
- unset($data['toto']);
+
+ $data['total'] = $total;
+
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 )
+ elseif ($type === CERFA)
{
$data['moyen_paiement'] = f('moyen_paiement_cerfa');
$data['contenu'] = [
@@ -131,8 +119,12 @@ $form->runIf(f('save') && !$form->hasErrors(),
'nature' => f('nature_don'),
'texte' => f('texte_don')];
$data['total'] = Utils::moneyToInteger(f('total'));
- unset($data['toto']);
}
+ else
+ {
+ throw new UserException('Ce type de document doit être créé avec son formulaire dédié.');
+ }
+
if (f('base_receveur') == 'client')
{
$data['receveur_membre'] = 0;
@@ -157,18 +149,20 @@ $form->runIf(f('save') && !$form->hasErrors(),
}, $csrf_key);
$form->runIf(f('select_cotis') && !$form->hasErrors(),
- function () use ($step)
+ function () use (&$step)
{
$step = true;
}, 'add_cotis_1');
$form->runIf(f('add_cotis') && !$form->hasErrors(),
- function () use ($radio, $fields, $facture, $form)
+ function () use (&$data, &$radio, $fields, $facture, $form)
{
$radio['type'] = f('cotisation');
try
{
$num = (int) str_replace('cotis_', '', $radio['type']);
+ $cotis = [];
+
foreach($fields as $field)
{
$cotis[$field] = f($field.'_'.$num);
@@ -183,8 +177,12 @@ $form->runIf(f('add_cotis') && !$form->hasErrors(),
'receveur_membre' => 1,
'receveur_id' => f('membre_cotis'),
'date_emission' => f('date_emission'),
+ 'date_echeance' => f('date_echeance') ?: f('date_emission'),
+ 'reglee' => 1,
+ 'archivee' => 0,
'moyen_paiement' => 'AU',
'total' => $r->paid_amount ?? $r->amount,
+ 'nom_contact' => null,
'contenu' => ['id' => $cotis['id'],
'intitule' => $cotis['label'],
'souscription' => $cotis['date'],
@@ -264,7 +262,7 @@ if ($target)
} // ... s'il est défini dans le document copié
elseif (isset($doc['type'])) {
$radio['type'] = $doc['type'];
- } // ... ou par défaut
+ } // ... ou par défaut
else
{
$radio['type'] = FACT;
@@ -284,9 +282,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;
+ $doc['nom_contact'] = $f->nom_contact ?? null;
+ $doc['numero_commande'] = $f->numero_commande ?? null;
+ $doc['reference_acheteur'] = $f->reference_acheteur ?? null;
/* modif DD -- CERFA -------------------------------------- */
if ( $f->type_facture == CERFA ) {
$doc['total'] = $f->total;
@@ -346,11 +344,11 @@ $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', 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('users', iterator_to_array(Users\Users::iterateAssocByCategory()));
$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')]);
+$tpl->assign('number_pattern', PATTERNS_LIST[$plugin->getConfig('pattern')] ?? PATTERNS_LIST['']);
if ($target) {
$tpl->display(PLUGIN_ROOT . '/templates/facture_ajouter.tpl');
diff --git a/admin/_inc.php b/admin/_inc.php
index f11fc22..b0f7f07 100644
--- a/admin/_inc.php
+++ b/admin/_inc.php
@@ -22,6 +22,42 @@ const PATTERNS_LIST = [
'%06{id}' => 'Numéro unique du document sur 6 chiffres ("000042")',
];
+function ensureSchemaColumns(): void
+{
+ $db = \Paheko\DB::getInstance();
+
+ $tables = [
+ 'plugin_facturation_clients' => [
+ 'siret' => 'siret TEXT',
+ 'telephone' => 'telephone TEXT',
+ 'email' => 'email TEXT',
+ 'nom_contact' => 'nom_contact TEXT',
+ 'note' => 'note TEXT',
+ ],
+ 'plugin_facturation_factures' => [
+ 'nom_contact' => 'nom_contact TEXT',
+ 'numero_commande' => 'numero_commande TEXT',
+ 'reference_acheteur' => 'reference_acheteur TEXT',
+ ],
+ ];
+
+ foreach ($tables as $table => $columns) {
+ $schema = $db->getTableSchema($table);
+
+ if (!$schema) {
+ continue;
+ }
+
+ foreach ($columns as $column => $definition) {
+ if (!isset($schema['columns'][$column])) {
+ $db->exec(sprintf('ALTER TABLE %s ADD COLUMN %s;', $db->quoteIdentifier($table), $definition));
+ }
+ }
+ }
+}
+
+ensureSchemaColumns();
+
$client = new Client;
$facture = new Facture;
@@ -63,7 +99,7 @@ $tpl->register_function('money_fac', function (array $params)
$current_value = htmlspecialchars($current_value, ENT_QUOTES, 'UTF-8');
}
- $currency = Config::getInstance()->get('monnaie');
+ $currency = Config::getInstance()->get('currency');
return sprintf('
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} €. 111
- 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,
-
-
-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;
+
Nous accusons réception de votre cotisation « {$h($intitule)} » reçue le {$h($emission)} et nous vous en remercions.
+
Nous reconnaissons que vous avez acquitté la somme de {$h($total)} {$h($currency)}. Votre adhésion sera donc effective à compter du {$h($souscription)} jusqu'à {$h($expiration)}.
+
Nous vous prions de recevoir nos meilleures salutations.
+
Pour {$h($config->get('org_name'))}
+
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.