Comment: | Fusion des changements et correctifs effectués dans le trunk |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | dev |
Files: | files | file ages | folders |
SHA1: |
c0a510c18ccc47ffa348224a80092970 |
User & Date: | bohwaz on 2019-09-23 21:30:20 |
Other Links: | branch diff | manifest | tags |
2019-12-17
| ||
16:02 | Merge avec trunk check-in: 12a00549c1 user: bohwaz tags: dev | |
2019-09-23
| ||
21:30 | Fusion des changements et correctifs effectués dans le trunk check-in: c0a510c18c user: bohwaz tags: dev | |
20:47 | Mise à jour version check-in: 1d2b0786d4 user: bohwaz tags: trunk, stable, 0.9.3 | |
2019-03-08
| ||
17:03 | Ajout entité compte bancaire check-in: 80bb6a9ff8 user: bohwaz tags: dev | |
Modified src/Makefile from [054872df85] to [7b30622c74].
︙ | ︙ | |||
16 17 18 19 20 21 22 | php -S localhost:8082 -t www www/_route.php test: find . -name '*.php' -print0 | xargs -0 -n1 php -l > /dev/null release: test $(eval VERSION=$(shell cat VERSION)) | | | | | > > > | | | > > | | > | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | php -S localhost:8082 -t www www/_route.php test: find . -name '*.php' -print0 | xargs -0 -n1 php -l > /dev/null release: test $(eval VERSION=$(shell cat VERSION)) rm -rf /tmp/garradin-build mkdir -p /tmp/garradin-build fossil zip ${VERSION} /tmp/garradin-build/src.zip --name garradin unzip -d /tmp/garradin-build /tmp/garradin-build/src.zip cd include/lib; rsync --files-from=dependencies.list -r ./ /tmp/garradin-build/garradin/src/include/lib/ mv /tmp/garradin-build/garradin/src /tmp/garradin-build/garradin-${VERSION} @#cd /tmp/garradin-build/; zip -r -9 garradin-${VERSION}.zip garradin-${VERSION}; @#mv -f /tmp/garradin-build/garradin-${VERSION}.zip ./ tar cjvfh garradin-${VERSION}.tar.bz2 -C /tmp/garradin-build garradin-${VERSION} deb: cd ../debian; ./makedeb.sh publish: release deb $(eval VERSION=$(shell cat VERSION)) fossil uv sync # fossil uv ls | fgrep -v 'garradin-0.8.5' | grep -E '^garradin-.*\.(tar\.bz2|deb)' | xargs fossil uv rm fossil uv add garradin-${VERSION}.tar.bz2 cd ../debian && fossil uv add garradin-${VERSION}-*.deb fossil uv sync check-dependencies: grep -hEo '^use \\?KD2\\\w+|\\KD2\\\w+' -R include/lib/Garradin www | sed -r 's/^use \\?KD2\\|^\\KD2\\//' | sort | uniq |
Modified src/VERSION from [ef2e10f968] to [a416ca4e18].
|
| | | 1 | 0.9.3 |
Modified src/config.dist.php from [dcde08c471] to [1e67c15c59].
︙ | ︙ | |||
281 282 283 284 285 286 287 | * soit à l'affichage de la page d'accueil (si nécessaire). * * Voir paramètre USE_CRON aussi * * Défaut : true */ const ENABLE_AUTOMATIC_BACKUPS = true; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | * soit à l'affichage de la page d'accueil (si nécessaire). * * Voir paramètre USE_CRON aussi * * Défaut : true */ const ENABLE_AUTOMATIC_BACKUPS = true; /** * Couleur primaire de l'interface admin par défaut * (peut être personnalisée dans la configuration) * * Défaut : #9c4f15 */ //const ADMIN_COLOR1 = '#20787a'; /** * Couleur secondaire de l'interface admin * Défaut : #d98628 */ //const ADMIN_COLOR2 = '#85b9ba'; /** * Image de fond par défaut de l'interface admin * * Cette URL doit être absolue (http://...) ou relative à l'admin (/admin/static...) * * Attention si l'image est sur un domaine différent vous devrez activer l'entête CORS: * Access-Control-Allow-Origin "*" * * sinon la personnalisation des couleurs ne fonctionnera pas * * Défaut : [ADMIN_URL]static/gdin_bg.png */ //const ADMIN_BACKGROUND_IMAGE = 'http://mon-asso.fr/fond_garradin.png'; |
Modified src/include/data/0.8.0.sql from [d1406fb553] to [34e1625504].
︙ | ︙ | |||
62 63 64 65 66 67 68 | INSERT INTO compta_categories SELECT * FROM compta_categories_old; INSERT INTO compta_comptes_bancaires SELECT * FROM compta_comptes_bancaires_old; INSERT INTO compta_exercices SELECT * FROM compta_exercices_old; INSERT INTO compta_journal SELECT *, NULL FROM compta_journal_old; INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old; INSERT INTO fichiers SELECT * FROM fichiers_old; INSERT INTO membres_operations SELECT * FROM membres_operations_old; | | > | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | INSERT INTO compta_categories SELECT * FROM compta_categories_old; INSERT INTO compta_comptes_bancaires SELECT * FROM compta_comptes_bancaires_old; INSERT INTO compta_exercices SELECT * FROM compta_exercices_old; INSERT INTO compta_journal SELECT *, NULL FROM compta_journal_old; INSERT INTO compta_rapprochement SELECT * FROM compta_rapprochement_old; INSERT INTO fichiers SELECT * FROM fichiers_old; INSERT INTO membres_operations SELECT * FROM membres_operations_old; INSERT INTO membres_categories SELECT id, nom, droit_wiki, droit_membres, droit_compta, droit_inscription, droit_connexion, droit_config, cacher, id_cotisation_obligatoire FROM membres_categories_old; -- Suppression des anciennes tables DROP TABLE cotisations_membres_old; DROP TABLE rappels_old; DROP TABLE rappels_envoyes_old; DROP TABLE wiki_pages_old; DROP TABLE wiki_revisions_old; |
︙ | ︙ |
Modified src/include/data/champs_membres.ini from [e4dcbd25bd] to [f5ad8e1d8e].
︙ | ︙ | |||
57 58 59 60 61 62 63 | title = "Nom & prénom" mandatory = true install = true editable = true list_row = 2 [email] | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | title = "Nom & prénom" mandatory = true install = true editable = true list_row = 2 [email] ; ce champ est facultatif et de type 'email' type = email title = "Adresse E-Mail" mandatory = false install = true editable = true [passe] ; ce champ est obligatoirement présent et de type 'password' ; le titre ne peut être modifié type = password |
︙ | ︙ |
Modified src/include/init.php from [0f77762847] to [f08b2c5f34].
︙ | ︙ | |||
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 'SMTP_USER' => null, 'SMTP_PASSWORD' => null, 'SMTP_PORT' => 587, 'SMTP_SECURITY' => 'STARTTLS', 'ADMIN_URL' => WWW_URL . 'admin/', 'NTP_SERVER' => 'fr.pool.ntp.org', 'ENABLE_AUTOMATIC_BACKUPS' => true, ]; foreach ($default_config as $const => $value) { $const = sprintf('Garradin\\%s', $const); if (!defined($const)) { define($const, $value); } } const WEBSITE = 'https://garradin.eu/'; const PLUGINS_URL = 'https://garradin.eu/plugins/list.json'; | > > > > > > | > | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | 'SMTP_USER' => null, 'SMTP_PASSWORD' => null, 'SMTP_PORT' => 587, 'SMTP_SECURITY' => 'STARTTLS', 'ADMIN_URL' => WWW_URL . 'admin/', 'NTP_SERVER' => 'fr.pool.ntp.org', 'ENABLE_AUTOMATIC_BACKUPS' => true, 'ADMIN_COLOR1' => '#9c4f15', 'ADMIN_COLOR2' => '#d98628', ]; foreach ($default_config as $const => $value) { $const = sprintf('Garradin\\%s', $const); if (!defined($const)) { define($const, $value); } } if (!defined('Garradin\\ADMIN_BACKGROUND_IMAGE')) { define('Garradin\\ADMIN_BACKGROUND_IMAGE', ADMIN_URL . 'static/gdin_bg.png'); } const WEBSITE = 'https://garradin.eu/'; const PLUGINS_URL = 'https://garradin.eu/plugins/list.json'; #const DEFAULT_REPORT_URL = 'http://henga.test/report/?p=ABCD'; const DEFAULT_REPORT_URL = null; // PHP devrait être assez intelligent pour chopper la TZ système mais nan // il sait pas faire (sauf sur Debian qui a le bon patch pour ça), donc pour // éviter le message d'erreur à la con on définit une timezone par défaut // Pour utiliser une autre timezone, il suffit de définir date.timezone dans // un .htaccess ou dans config.local.php if (!ini_get('date.timezone')) |
︙ | ︙ |
Modified src/include/lib/Garradin/Compta/Categories.php from [1997e6a481] to [aacf281b4b].
︙ | ︙ | |||
106 107 108 109 110 111 112 | FROM compta_categories AS cat INNER JOIN compta_comptes AS cc ON cc.id = cat.compte WHERE %s ORDER BY cat.intitule;', $where); return $db->getGrouped($query); } | | > | > > > > > > > | 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | FROM compta_categories AS cat INNER JOIN compta_comptes AS cc ON cc.id = cat.compte WHERE %s ORDER BY cat.intitule;', $where); return $db->getGrouped($query); } public function listMoyensPaiement($assoc = false) { $db = DB::getInstance(); $query = 'SELECT code, nom FROM compta_moyens_paiement ORDER BY nom COLLATE NOCASE;'; if ($assoc) { return $db->getAssoc($query); } else { return $db->getGrouped($query); } } public function getMoyenPaiement($code) { $db = DB::getInstance(); return $db->firstColumn('SELECT nom FROM compta_moyens_paiement WHERE code = ?;', $code); } |
︙ | ︙ |
Modified src/include/lib/Garradin/Compta/Comptes.php from [8786b38bca] to [9bf36bdeef].
︙ | ︙ | |||
14 15 16 17 18 19 20 | const CARTE_A_ENCAISSER = '5115'; const PASSIF = 0x01; const ACTIF = 0x02; const PRODUIT = 0x04; const CHARGE = 0x08; | > > > > > > > > > > | > > > > > > > > | > > > > > | > | > | | > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | const CARTE_A_ENCAISSER = '5115'; const PASSIF = 0x01; const ACTIF = 0x02; const PRODUIT = 0x04; const CHARGE = 0x08; /** * Importe un plan comptable * @param string $source_file Chemin du fichier à importer. * @param boolean $delete_all True active la suppression des tous les anciens comptes (peu importe plan_comptable) * @return boolean/array Retourne un array des comptes non-supprimés avec leur raison, s'il y en a. Sinon true. * * Accepte 0 ou 1 argument : soit un chemin, soit true. * Sans arguments : importe le plan par défaut et ne supprime que les comptes * plus présent appartenants au plan d'origine (WHERE plan_comptable = 1) */ public function importPlan($source_file = null, $delete_all = false) { $reset = false; if(null == $source_file) { $reset = true; $source_file = \Garradin\ROOT . '/include/data/plan_comptable.json'; } $plan = json_decode(file_get_contents($source_file)); if(is_null($plan)) { throw new UserException('Le fichier n\'est pas du JSON ou n\'a pas pu être décodé.'); } $db = DB::getInstance(); $db->begin(); $ids = []; foreach ($plan as $id=>$compte) { $ids[] = $id; if ($db->test('compta_comptes', $db->where('id', $id))) { $db->update('compta_comptes', [ 'parent' => $compte->parent, 'libelle' => $compte->nom, 'position' => $compte->position, 'plan_comptable' => $reset || !empty($compte->plan_comptable) ? 1 : 0, 'desactive' => !empty($compte->desactive) ? 1 : 0, ], $db->where('id', $id)); } else { $db->insert('compta_comptes', [ 'id' => $id, 'parent' => $compte->parent, 'libelle' => $compte->nom, 'position' => $compte->position, 'plan_comptable' => $reset || !empty($compte->plan_comptable) ? 1 : 0, 'desactive' => !empty($compte->desactive) ? 1 : 0, ]); } } // Effacer les comptes du plan comptable s'ils ne sont pas utilisés ailleurs // et qu'ils ne sont pas dans le nouveau plan comptable qu'on vient d'importer $sql = 'DELETE FROM compta_comptes WHERE id NOT IN ( SELECT id FROM compta_comptes_bancaires UNION SELECT compte_credit FROM compta_journal UNION SELECT compte_debit FROM compta_journal UNION SELECT id FROM compta_categories) AND '. $db->where('id', 'NOT IN', $ids); // Si on ne fait qu'importer une mise à jour du plan comptable, // ne supprimer que les comptes qui n'ont pas été créés par l'usager if (!$delete_all) { $sql .= ' AND ' . $db->where('plan_comptable', 1); } $db->commit(); return true; } public function exportPlan() { $name = 'plan_comptable'; header('Content-type: application/json'); header(sprintf('Content-Disposition: attachment; filename="%s.json"', $name)); $liste = $this->listTree(0, true); $export = []; foreach ($liste as $k => $v) { $export[$v->id] = [ 'code' => $v->id, 'nom' => $v->libelle, 'parent' => $v->parent, 'position' => $v->position, 'plan_comptable' => $v->plan_comptable, 'desactive' => $v->desactive, ]; } file_put_contents('php://output', json_encode($export, JSON_PRETTY_PRINT)); return true; } public function add($data) { $this->_checkFields($data, true); |
︙ | ︙ | |||
95 96 97 98 99 100 101 | $parent = false; $id = $new_id; // Vérification que c'est bien le bon parent ! // Sinon risque par exemple d'avoir parent = 5 et id = 512A ! while (!$parent && strlen($id)) { | | | | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | $parent = false; $id = $new_id; // Vérification que c'est bien le bon parent ! // Sinon risque par exemple d'avoir parent = 5 et id = 512A ! while (!$parent && strlen($id)) { // On enlève un caractère à la fin jusqu'à trouver un compte parent $id = substr($id, 0, -1); $parent = $db->firstColumn('SELECT id FROM compta_comptes WHERE id = ?;', $id); } if (!$parent || $parent != $data['parent']) { throw new UserException('Le compte parent sélectionné est incorrect, par exemple pour créer un compte 512A il faut sélectionner 512 comme compte parent.'); } } // Vérification que le compte n'existe pas déjà if ($db->test('compta_comptes', 'id = ?', $new_id)) { throw new UserException('Ce numéro de compte existe déjà dans le plan comptable : ' . $new_id); } if (isset($data['position'])) { $position = (int) $data['position']; } else |
︙ | ︙ |
Modified src/include/lib/Garradin/Compta/Import.php from [d8cc440c1c] to [2b6a446835].
︙ | ︙ | |||
85 86 87 88 89 90 91 | $db = DB::getInstance(); $db->begin(); $cats = new Categories; $journal = new Journal; $columns = array_flip($this->header); $liste_cats = $db->getAssoc('SELECT intitule, id FROM compta_categories;'); | > | | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | $db = DB::getInstance(); $db->begin(); $cats = new Categories; $journal = new Journal; $columns = array_flip($this->header); $liste_cats = $db->getAssoc('SELECT intitule, id FROM compta_categories;'); // Liste des moyens sous la forme nom -> code $liste_moyens = array_flip($cats->listMoyensPaiement(true)); $col = function($column) use (&$row, &$columns) { if (!isset($columns[$column])) return null; if (!isset($row[$columns[$column]])) |
︙ | ︙ | |||
118 119 120 121 122 123 124 | if ($line === 1) { if (trim($row[0]) != 'Numéro mouvement') { throw new UserException('Erreur sur la ligne ' . $line . ' : l\'entête des colonnes est absent ou incorrect.'); } | | | | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | if ($line === 1) { if (trim($row[0]) != 'Numéro mouvement') { throw new UserException('Erreur sur la ligne ' . $line . ' : l\'entête des colonnes est absent ou incorrect.'); } continue; } if (count($row) != count($columns)) { $db->rollback(); throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.'); } if (trim($row[0]) !== '' && !is_numeric($row[0])) |
︙ | ︙ | |||
155 156 157 158 159 160 161 | { continue; } $debit = $col('Compte de débit - numéro'); $credit = $col('Compte de crédit - numéro'); | < < < < < < < < < > | > > > > > > > | 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | { continue; } $debit = $col('Compte de débit - numéro'); $credit = $col('Compte de crédit - numéro'); $cat = $col('Catégorie'); $moyen = strtoupper(substr($col('Moyen de paiement'), 0, 2)); // Association du moyen de paiement par nom if ($moyen && array_key_exists($moyen, $liste_moyens)) { $moyen = $liste_moyens[$moyen]; } // Vérification de l'existence du moyen de paiement // s'il n'est pas valide, on ne peut pas avoir de catégorie non plus if (!$moyen || !in_array($moyen, $liste_moyens, true)) { $moyen = false; $cat = false; } if ($cat && !array_key_exists($cat, $liste_cats)) { |
︙ | ︙ | |||
300 301 302 303 304 305 306 307 308 309 310 311 312 313 | if (empty($row)) { continue; } if (empty($columns)) { $columns = $row; $columns = array_flip($columns); continue; } $date = $col('Date'); $date = \DateTime::createFromFormat('d/m/Y', $date); | > > > > > | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | if (empty($row)) { continue; } if (empty($columns)) { if (empty($row[0])) { throw new UserException(sprintf('Erreur sur la ligne %d : la ligne est vide ?', $line)); } $columns = $row; $columns = array_flip($columns); continue; } $date = $col('Date'); $date = \DateTime::createFromFormat('d/m/Y', $date); |
︙ | ︙ |
Modified src/include/lib/Garradin/Compta/Journal.php from [2a385b6769] to [88e9a2c624].
︙ | ︙ | |||
31 32 33 34 35 36 37 | { if (is_null($id)) return true; return DB::getInstance()->test('compta_exercices', 'cloture = 0 AND id = ?', (int)$id); } | | | | 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | { if (is_null($id)) return true; return DB::getInstance()->test('compta_exercices', 'cloture = 0 AND id = ?', (int)$id); } public function getSolde($id_compte, $inclure_sous_comptes = false, $exercice = null) { $db = DB::getInstance(); $exercice = (int) $exercice ?: $this->_getCurrentExercice(); $compte = $inclure_sous_comptes ? 'LIKE \'' . $db->escapeString(trim($id_compte)) . '%\'' : '= \'' . $db->escapeString(trim($id_compte)) . '\''; $debit = 'COALESCE((SELECT SUM(montant) FROM compta_journal WHERE compte_debit '.$compte.' AND id_exercice = '.(int)$exercice.'), 0)'; $credit = 'COALESCE((SELECT SUM(montant) FROM compta_journal WHERE compte_credit '.$compte.' AND id_exercice = '.(int)$exercice.'), 0)'; |
︙ | ︙ | |||
57 58 59 60 61 62 63 | { $query = $credit . ' - ' . $debit; } return $db->firstColumn('SELECT ' . $query . ';'); } | | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | { $query = $credit . ' - ' . $debit; } return $db->firstColumn('SELECT ' . $query . ';'); } public function getJournalCompte($compte, $inclure_sous_comptes = false, $exercice = null) { $db = DB::getInstance(); $position = $db->firstColumn('SELECT position FROM compta_comptes WHERE id = ?;', $compte); $exercice = (int) $exercice ?: $this->_getCurrentExercice(); $compte = $inclure_sous_comptes ? 'LIKE \'' . $db->escapeString(trim($compte)) . '%\'' : '= \'' . $db->escapeString(trim($compte)) . '\''; // L'actif et les charges augmentent au débit, le passif et les produits au crédit if (($position & Comptes::ACTIF) || ($position & Comptes::CHARGE)) { |
︙ | ︙ | |||
273 274 275 276 277 278 279 | } else { $data[$champ] = trim($data[$champ]); } } | < < | < < | | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | } else { $data[$champ] = trim($data[$champ]); } } if (empty($data['compte_debit']) || !$db->test('compta_comptes', $db->where('id', $data['compte_debit']))) { throw new UserException('Compte débité inconnu.'); } if (empty($data['compte_credit']) || !$db->test('compta_comptes', $db->where('id', $data['compte_credit']))) { throw new UserException('Compte crédité inconnu.'); } $data['compte_credit'] = strtoupper(trim($data['compte_credit'])); $data['compte_debit'] = strtoupper(trim($data['compte_debit'])); if ($data['compte_credit'] == $data['compte_debit']) { throw new UserException('Compte crédité identique au compte débité.'); } if (isset($data['id_categorie'])) |
︙ | ︙ |
Modified src/include/lib/Garradin/Form.php from [e13d9531e0] to [5a5ce58fea].
︙ | ︙ | |||
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | return sprintf('La vérification du champ %s n\'est pas identique au champ lui-même.', $element); case 'date_format': return sprintf('Format de date invalide dans le champ %s.', $element); case 'numeric': return sprintf('Le champ %s doit être un nombre.', $element); case 'money': return sprintf('Le champ %s n\'est pas un nombre valide.', $element); default: return sprintf('Erreur "%s" dans le champ "%s"', $rule, $element); } } public function __invoke($key) { return \KD2\Form::get($key); } } | > > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | return sprintf('La vérification du champ %s n\'est pas identique au champ lui-même.', $element); case 'date_format': return sprintf('Format de date invalide dans le champ %s.', $element); case 'numeric': return sprintf('Le champ %s doit être un nombre.', $element); case 'money': return sprintf('Le champ %s n\'est pas un nombre valide.', $element); case 'in': return sprintf('Valeur invalide dans le champ \'%s\'.', $element); default: return sprintf('Erreur "%s" dans le champ "%s"', $rule, $element); } } public function __invoke($key) { return \KD2\Form::get($key); } } |
Modified src/include/lib/Garradin/Membres.php from [89209054f9] to [84b4e80ec3].
︙ | ︙ | |||
325 326 327 328 329 330 331 | return $fields; } public function sendMessage(array $recipients, $subject, $message, $send_copy) { $config = Config::getInstance(); | | > > > > > > > > > | | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 | return $fields; } public function sendMessage(array $recipients, $subject, $message, $send_copy) { $config = Config::getInstance(); foreach ($recipients as $key => $recipient) { // Ignorer les destinataires avec une adresse email vide if (empty($recipient->email)) { unset($recipients[$key]); continue; } // Refuser d'envoyer un mail à une adresse invalide, sans vérifier le MX // sinon ça serait trop lent if (!SMTP::checkEmailIsValid($recipient->email, false)) { throw new UserException(sprintf('Adresse email invalide : "%s". Aucun message n\'a été envoyé.', $recipient->email)); } } foreach ($recipients as $recipient) { |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Champs.php from [a027cb81e3] to [9b116040de].
︙ | ︙ | |||
225 226 227 228 229 230 231 | $rules = []; if (!empty($config->mandatory) && !($name == 'passe' && $mode != 'create')) { $rules[] = 'required'; } | | < < < < | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | $rules = []; if (!empty($config->mandatory) && !($name == 'passe' && $mode != 'create')) { $rules[] = 'required'; } if ($config->type == 'email') { $rules[] = 'email'; } elseif ($config->type == 'url') { $rules[] = 'url'; } elseif ($config->type == 'date') { $rules[] = 'date_format:Y-m-d'; } elseif ($config->type == 'date') { $rules[] = 'date_format:Y-m-d H\:i'; } elseif ($config->type == 'number' || $config->type == 'multiple') { $rules[] = 'numeric'; } elseif ($config->type == 'checkbox') { $rules[] = 'boolean'; } if ($name == 'passe') { |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Cotisations.php from [86b67dc8e7] to [cf23856e38].
︙ | ︙ | |||
86 87 88 89 90 91 92 | if ($co->id_categorie_compta) { $membre = (new Membres)->getNom($data['id_membre']); try { $data_compta = array_merge($data_compta, [ 'id_categorie' => $co->id_categorie_compta, | | | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | if ($co->id_categorie_compta) { $membre = (new Membres)->getNom($data['id_membre']); try { $data_compta = array_merge($data_compta, [ 'id_categorie' => $co->id_categorie_compta, 'libelle' => sprintf('%s - %s', $co->intitule, $membre), 'date' => $data['date'], 'id_auteur' => $data['id_auteur'], 'id_membre' => $data['id_membre'], ]); $id_operation = $this->addOperationCompta($id, $data_compta); } |
︙ | ︙ | |||
253 254 255 256 257 258 259 | } /** * Liste des membres qui sont inscrits à une cotisation * @param integer $id Numéro de la cotisation * @return array Liste des membres */ | | | 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | } /** * Liste des membres qui sont inscrits à une cotisation * @param integer $id Numéro de la cotisation * @return array Liste des membres */ public function listMembersForCotisation($id, $include_category, $page = 1, $order = null, $desc = true) { $begin = ($page - 1) * self::ITEMS_PER_PAGE; $db = DB::getInstance(); $champ_id = Config::getInstance()->get('champ_identite'); if (empty($order)) |
︙ | ︙ | |||
279 280 281 282 283 284 285 286 287 288 289 | break; default: $order = 'cm.id_membre'; break; } $desc = $desc ? 'DESC' : 'ASC'; return $db->get('SELECT cm.id_membre, cm.date, cm.id, m.numero, m.'.$champ_id.' AS nom, c.montant, CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date() | > > > > > > > > > > > > > > > > > > > > | > | 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | break; default: $order = 'cm.id_membre'; break; } $desc = $desc ? 'DESC' : 'ASC'; // Renvoyer la liste avec tous les membres des catégories dont la cotisation obligatoire est celle-ci if ($include_category) { $cats_obligatoires = $db->getAssoc('SELECT id, id FROM membres_categories WHERE id_cotisation_obligatoire = ? AND cacher = 0;', $id); return $db->get('SELECT m.id AS id_membre, cm.date, cm.id, m.numero, m.'.$champ_id.' AS nom, c.montant, CASE WHEN cm.id IS NULL THEN 0 WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date() WHEN c.fin IS NOT NULL THEN (cm.date <= c.fin AND cm.date >= c.debut) ELSE 1 END AS a_jour FROM membres AS m LEFT JOIN cotisations_membres AS cm ON cm.id_membre = m.id AND cm.id_cotisation = ? LEFT JOIN cotisations AS c ON c.id = cm.id_cotisation WHERE '.$db->where('m.id_categorie', $cats_obligatoires) . ' GROUP BY m.id ORDER BY '.$order.' '.$desc.' LIMIT ?,?;', $id, $begin, self::ITEMS_PER_PAGE); } return $db->get('SELECT cm.id_membre, cm.date, cm.id, m.numero, m.'.$champ_id.' AS nom, c.montant, CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date() WHEN c.fin IS NOT NULL THEN (cm.date <= c.fin AND cm.date >= c.debut) ELSE 1 END AS a_jour FROM cotisations_membres AS cm INNER JOIN cotisations AS c ON c.id = cm.id_cotisation INNER JOIN membres AS m ON m.id = cm.id_membre WHERE cm.id_cotisation = ? AND m.id_categorie NOT IN (SELECT mc.id FROM membres_categories AS mc WHERE mc.cacher = 1) GROUP BY cm.id_membre ORDER BY '.$order.' '.$desc.' LIMIT ?,?;', |
︙ | ︙ | |||
323 324 325 326 327 328 329 | * @return array Liste des cotisations en cours de validité */ public function listSubscriptionsForMember($id) { $db = DB::getInstance(); return $db->get('SELECT c.*, CASE WHEN c.duree IS NOT NULL THEN date(cm.date, \'+\'||c.duree||\' days\') >= date() | | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 | * @return array Liste des cotisations en cours de validité */ public function listSubscriptionsForMember($id) { $db = DB::getInstance(); return $db->get('SELECT c.*, 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, 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)$id); } /** * Ce membre est-il à jour sur cette cotisation ? * @param integer $id Numéro de membre |
︙ | ︙ |
Modified src/include/lib/Garradin/Membres/Import.php from [db87ef00f2] to [7b54b35f93].
︙ | ︙ | |||
211 212 213 214 215 216 217 | if (empty($row)) { continue; } if ($line == 1) { | | | | 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | if (empty($row)) { continue; } if ($line == 1) { if (empty($row[0]) || !is_string($row[0]) || is_numeric($row[0])) { $db->rollback(); throw new UserException('Erreur sur la ligne 1 : devrait contenir l\'en-tête des colonnes.'); } $columns = array_flip($row); continue; } if (count($row) != count($columns)) { $db->rollback(); throw new UserException('Erreur sur la ligne ' . $line . ' : le nombre de colonnes est incorrect.'); } $data = []; foreach ($columns as $name=>$id) { $name = trim($name); // Champs qui n'existent pas dans le schéma actuel if (!in_array($name, $champs)) continue; if (trim($row[$id]) !== '') $data[$name] = $row[$id]; } |
︙ | ︙ |
Modified src/include/lib/Garradin/Recherche.php from [0325ea49c7] to [35a5a3057c].
︙ | ︙ | |||
135 136 137 138 139 140 141 | WHERE (id_membre IS NULL OR id_membre = ?) AND cible = ? ORDER BY intitule;', (int)$id_membre, $cible); } /** * Lancer une recherche enregistrée */ | | | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | WHERE (id_membre IS NULL OR id_membre = ?) AND cible = ? ORDER BY intitule;', (int)$id_membre, $cible); } /** * Lancer une recherche enregistrée */ public function search($id, array $force_select = null, $no_limit = false) { $search = $this->get($id); if (!$search) { return false; } if ($search->type == self::TYPE_JSON) { $search->contenu = $this->buildQuery($search->cible, $search->query, $search->order, $search->desc, $no_limit ? 10000 : $search->limit); } return $this->searchSQL($search->cible, $search->contenu, $force_select, $no_limit); } /** * Renvoie la liste des colonnes d'une cible */ public function getColumns($target) { |
︙ | ︙ | |||
385 386 387 388 389 390 391 | return $sql_query; } /** * Lancer une recherche SQL */ | | | | | | > > > > > > > | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | return $sql_query; } /** * Lancer une recherche SQL */ public function searchSQL($target, $query, array $force_select = null, $no_limit = false) { if (!in_array($target, self::TARGETS, true)) { throw new \InvalidArgumentException('Cible inconnue : ' . $target); } if (null !== $force_select) { $query = preg_replace('/^\s*SELECT.*FROM\s+/Ui', 'SELECT ' . implode(', ', $force_select) . ' FROM ', $query); } if (!$no_limit && !preg_match('/LIMIT\s+\d+/i', $query)) { $query = preg_replace('/;?\s*$/', '', $query); $query .= ' LIMIT 100'; } try { return DB::getInstance()->userSelectGet($query); } catch (\Exception $e) { $message = 'Erreur dans la requête : ' . $e->getMessage(); if (null !== $force_select) { $message .= "\nVérifiez que votre requête sélectionne bien les colonnes suivantes : " . implode(', ', $force_select); } throw new UserException($message); } } public function schema($target) { $db = DB::getInstance(); |
︙ | ︙ |
Modified src/include/lib/Garradin/Sauvegarde.php from [7513189b78] to [41b6845214].
︙ | ︙ | |||
391 392 393 394 395 396 397 | $db = DB::getInstance(); $db->update('membres_categories', [ 'droit_membres' => Membres::DROIT_ADMIN, 'droit_connexion' => Membres::DROIT_ACCES ]); } | < < < > > > > > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | $db = DB::getInstance(); $db->update('membres_categories', [ 'droit_membres' => Membres::DROIT_ADMIN, 'droit_connexion' => Membres::DROIT_ACCES ]); } if ($version != garradin_version()) { $return |= self::NEED_UPGRADE; } else { // Force l'installation de plugin système si non existant dans la sauvegarde existante // si une mise à jour est nécessaire, normalement ça sera fait après la mise à jour Plugin::checkAndInstallSystemPlugins(); } return $return; } /** * Taille de la base de données actuelle * @return integer Taille en octets du fichier SQLite |
︙ | ︙ |
Modified src/include/lib/Garradin/Template.php from [682f3b4c7a] to [3def9bc1cf].
︙ | ︙ | |||
216 217 218 219 220 221 222 | return $n; } protected function customColors() { $config = Config::getInstance(); | | < > | | | < < | | | > | | | | < | | | > > > > | | > > > | 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | return $n; } protected function customColors() { $config = Config::getInstance(); $couleur1 = $config->get('couleur1') ?: ADMIN_COLOR1; $couleur2 = $config->get('couleur2') ?: ADMIN_COLOR2; $image_fond = ADMIN_BACKGROUND_IMAGE; if ($config->get('image_fond')) { try { $f = new Fichiers($config->get('image_fond')); $image_fond = $f->getURL(); } catch (\InvalidArgumentException $e) { // Fichier qui n'existe pas/plus } } // Transformation Hexa vers décimal $couleur1 = implode(', ', sscanf($couleur1, '#%02x%02x%02x')); $couleur2 = implode(', ', sscanf($couleur2, '#%02x%02x%02x')); $out = ' <style type="text/css"> :root { --gMainColor: %s; --gSecondColor: %s; } @media screen, handheld { .header .menu, body { background-image: url("%s"); } } </style>'; return sprintf($out, $couleur1, $couleur2, $image_fond); } protected function displayChampMembre($v, $config) { switch ($config->type) { case 'checkbox': return $v ? 'Oui' : 'Non'; case 'email': return '<a href="mailto:' . rawurlencode($v) . '">' . htmlspecialchars($v) . '</a>'; case 'tel': return '<a href="tel:' . rawurlencode($v) . '">' . htmlspecialchars($v) . '</a>'; case 'url': return '<a href="' . htmlspecialchars($v) . '">' . htmlspecialchars($v) . '</a>'; case 'country': return Utils::getCountryName($v); case 'date': return Utils::sqliteDateToFrench($v); case 'multiple': $out = []; foreach ($config->options as $b => $name) { if ($v & (0x01 << $b)) $out[] = $name; |
︙ | ︙ |
Modified src/include/lib/Garradin/Utils.php from [ac43981659] to [c134309b5d].
︙ | ︙ | |||
297 298 299 300 301 302 303 | $str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères $str = preg_replace('![^[:ascii:]]+!', '', $str); return $str; } | < < < < < < < < < < | 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | $str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères $str = preg_replace('![^[:ascii:]]+!', '', $str); return $str; } /** * Transforme un texte SkrivML en HTML * @param string $str Texte SkrivML * @return string Texte HTML */ static public function SkrivToHTML($str) { |
︙ | ︙ |
Added src/templates/admin/compta/comptes/classe.tpl version [45939485c2].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | {include file="admin/_head.tpl" title=$classe_compte.libelle current="compta/categories"} <ul class="actions"> <li><a href="{$admin_url}compta/comptes/">Liste des classes</a></li> <li><a href="{$admin_url}compta/comptes/ajouter.php?classe={$classe}">Ajouter un compte dans cette classe</a></li> </ul> <p class="help"> Les comptes avec la mention <em>*</em> font partie du plan comptable standard et ne peuvent être modifiés ou supprimés. </p> {if !empty($liste)} <table class="list accountList"> {foreach from=$liste item="compte"} <tr class="niveau_{$compte.id|strlen}"> <th>{$compte.id}</th> <td class="libelle">{$compte.libelle}</td> <td> {if !empty($compte.desactive)} <em>Désactivé</em> {else} {$compte.position|get_position} {/if} </td> <td class="actions"> {if empty($compte.desactive)} {if !$compte.plan_comptable} <a class="icn" href="{$admin_url}compta/comptes/modifier.php?id={$compte.id}" title="Modifier">✎</a> <a class="icn" href="{$admin_url}compta/comptes/supprimer.php?id={$compte.id}" title="Supprimer">✘</a> {else} <em>*</em> {/if} {/if} </td> </tr> {/foreach} </table> {else} <p class="alert"> Aucun compte trouvé. </p> {/if} {include file="admin/_foot.tpl"} |
Added src/templates/admin/compta/comptes/import.tpl version [99c4dfd495].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | {include file="admin/_head.tpl" title="Plan comptable" current="compta/categories"} <ul class="actions"> <li><a href="{$admin_url}compta/comptes/">Plan comptable</a></li> <li class="current"><a href="?import">Import / remise à zéro</a></li> <li><a href="?export=plan">Exporter le plan en format JSON</a></li> </ul> {form_errors} {if $confirm} <p class="confirm"> {if $confirm == 'import'}L'import s'est correctement déroulé. {elseif $confirm == 'reset'}Le plan comptable a bien été remis à zéro.{/if} </p> {/if} <form method="post" action="{$self_url}" enctype="multipart/form-data"> <fieldset> <legend>Importer un plan comptable</legend> <p class="help"> Toute modification actuelle du plan comptable sera perdue.<br /> Les comptes associés à des écritures ou des comptes bancaires ne seront pas supprimés. </p> <dl> <dt><label for="f_file">Fichier à importer</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd><input type="file" name="upload" id="f_file" required="required" /></dd> <dt><label for="f_type">Format de fichier</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> <input type="radio" name="format" id="f_format_json" value="json" {*form_field name="format" checked="json"*} checked="checked" /> <label for="f_format_json">Plan comptable au format JSON de plan comptable Garradin</label> </dd> </dl> <p class="submit"> {csrf_field key="plan_import"} <input type="submit" name="import" value="Importer →" /> </p> </fieldset> </form> <form method="post" action="{$self_url}"> <fieldset> <legend>Remise à zéro du plan comptable</legend> <p class="help"> Permet de rétablir le plan comptable par défaut de Garradin.<br /> Vos modifications personnelles seront perdues, assurez-vous d'en avoir une copie avant en cas de problèmes (bouton « Exporter le plan »). </p> <p class="submit"> {csrf_field key="plan_reset"} <input type="submit" name="reset" value="Rétablir le plan comptable →" /> </p> </fieldset> </form> |
Modified src/templates/admin/compta/comptes/index.tpl from [452d349397] to [4936874101].
|
| < | < < < < < < < | | | > | | < < < < < < | < < < < < < < < < < < < < | < < < < < < < | < < < < < | < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | {include file="admin/_head.tpl" title="Plan comptable" current="compta/categories"} <ul class="actions"> <li class="current"><a href="{$admin_url}compta/comptes/">Plan comptable</a></li> <li><a href="?import">Import / remise à zéro</a></li> <li><a href="?export=plan">Exporter le plan en format JSON</a></li> </ul> <ul class="accountList"> {foreach from=$classes item="_classe"} <li><h4><a href="{$admin_url}compta/comptes/?classe={$_classe.id}">{$_classe.libelle}</a></h4></li> {/foreach} </ul> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/compta/comptes/journal.tpl from [76d3a0a881] to [03e8b58484].
|
| | | > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | {if null !== $suivi} {include file="admin/_head.tpl" title="Journal : %s - %s"|args:$compte.id:$compte.libelle current="compta/banques" body_id="rapport"} <ul class="actions"> <li><a href="{$admin_url}compta/banques/">Comptes bancaires</a></li> <li{if $compte.id == Compta\Comptes::CAISSE} class="current"{/if}><a href="{$admin_url}compta/comptes/journal.php?id={$id_caisse}&suivi">Journal de caisse</a></li> <li{if $compte.id == Compta\Comptes::CHEQUE_A_ENCAISSER} class="current"{/if}><a href="{$admin_url}compta/comptes/journal.php?id={$id_cheque_a_encaisser}&suivi">Chèques à encaisser</a></li> <li{if $compte.id == Compta\Comptes::CARTE_A_ENCAISSER} class="current"{/if}><a href="{$admin_url}compta/comptes/journal.php?id={$id_carte_a_encaisser}&suivi">Paiements par carte à encaisser</a></li> </ul> {else} {include file="admin/_head.tpl" title="Journal : %s - %s"|args:$compte.id:$compte.libelle current="compta/gestion" body_id="rapport"} {/if} {if count($exercices)} <form action="{$self_url_no_qs}" method="get" class="shortFormRight"> <fieldset> <legend><label for="f_exercice">Afficher le journal de l'exercice suivant :</label></legend> <p> <select name="exercice" id="f_exercice" onchange="this.form.submit();"> {foreach from=$exercices item="exercice"} <option value="{$exercice.id}"{if $exercice_selectionne == $exercice.id} selected="selected"{/if}>{$exercice.libelle}</option> {/foreach} </select> <input type="hidden" name="id" value="{$compte.id}" /> {if null !== $suivi}<input type="hidden" name="suivi" value=""/>{/if} <noscript><input type="submit" value="Afficher"/></noscript> </p> </fieldset> </form> {/if} <table class="list"> <colgroup> <col width="3%" /> <col width="3%" /> <col width="12%" /> <col width="10%" /> |
︙ | ︙ |
Modified src/templates/admin/config/index.tpl from [6078c55f63] to [f4c6ed1cb3].
︙ | ︙ | |||
108 109 110 111 112 113 114 | <legend>Personnalisation de l'interface</legend> <dl> <dt><label for="f_couleur1">Couleur principale</label></dt> <dd><input type="color" pattern="#[a-f0-9]{ldelim}6{rdelim}" title="Couleur au format hexadécimal" placeholder="{$couleurs_defaut[0]}" name="couleur1" value="{form_field name=couleur1 default=$couleur1}" id="f_couleur1" /></dd> <dt><label for="f_couleur2">Couleur secondaire</label></dt> <dd><input type="color" pattern="#[a-f0-9]{ldelim}6{rdelim}" title="Couleur au format hexadécimal" placeholder="{$couleurs_defaut[1]}" name="couleur2" value="{form_field name=couleur2 default=$couleur2}" id="f_couleur2" /></dd> </dl> | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | <legend>Personnalisation de l'interface</legend> <dl> <dt><label for="f_couleur1">Couleur principale</label></dt> <dd><input type="color" pattern="#[a-f0-9]{ldelim}6{rdelim}" title="Couleur au format hexadécimal" placeholder="{$couleurs_defaut[0]}" name="couleur1" value="{form_field name=couleur1 default=$couleur1}" id="f_couleur1" /></dd> <dt><label for="f_couleur2">Couleur secondaire</label></dt> <dd><input type="color" pattern="#[a-f0-9]{ldelim}6{rdelim}" title="Couleur au format hexadécimal" placeholder="{$couleurs_defaut[1]}" name="couleur2" value="{form_field name=couleur2 default=$couleur2}" id="f_couleur2" /></dd> </dl> <input type="hidden" name="image_fond" id="f_image_fond" data-source="{$background_image_source}" value="{form_field name=image_fond}" /> </fieldset> <p class="submit"> {csrf_field key="config"} <input type="submit" name="save" value="Enregistrer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/admin/membres/cotisations/voir.tpl from [3ab24d7fdd] to [79533ebb65].
︙ | ︙ | |||
18 19 20 21 22 23 24 | {elseif $cotisation.debut} du {$cotisation.debut|format_sqlite_date_to_french} au {$cotisation.fin|format_sqlite_date_to_french} {else} ponctuelle {/if} — {$cotisation.montant|escape|html_money} {$config.monnaie} </dd> | > > > > > > | | | | | > | < | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | {elseif $cotisation.debut} du {$cotisation.debut|format_sqlite_date_to_french} au {$cotisation.fin|format_sqlite_date_to_french} {else} ponctuelle {/if} — {$cotisation.montant|escape|html_money} {$config.monnaie} </dd> <dd> {if !$cats} <a href="?id={$cotisation.id}&cats=1">Afficher les membres des catégories pour lesquelles cette cotisation est obligatoire</a> {else} <a href="?id={$cotisation.id}">Afficher seulement les membres à jour (ou qui ont déjà payé, mais ne sont plus à jour)</a> {/if} </dd> <dt>Nombre de membres ayant cotisé</dt> <dd> {$cotisation.nb_membres} <small class="help">(incluant les membres des catégories cachées)</small> </dd> </dl> {if !empty($liste)} <table class="list"> <thead class="userOrder"> <tr> <td class="{if $order == "id"} cur {if $desc}desc{else}asc{/if}{/if}"><a href="?id={$cotisation.id}&o=id&a&cats={$cats}" class="icn up">↑</a><a href="?id={$cotisation.id}&o=id&d&cats={$cats}" class="icn dn">↓</a></td> <th class="{if $order == "identite"} cur {if $desc}desc{else}asc{/if}{/if}">Membre <a href="?id={$cotisation.id}&o=identite&a&cats={$cats}" class="icn up">↑</a><a href="?id={$cotisation.id}&o=identite&d&cats={$cats}" class="icn dn">↓</a></th> <td class="{if $order == "a_jour"} cur {if $desc}desc{else}asc{/if}{/if}">Statut <a href="?id={$cotisation.id}&o=a_jour&a&cats={$cats}" class="icn up">↑</a><a href="?id={$cotisation.id}&o=a_jour&d&cats={$cats}" class="icn dn">↓</a></td> <td class="{if $order == "date"} cur {if $desc}desc{else}asc{/if}{/if}">Date de cotisation <a href="?id={$cotisation.id}&o=date&a" class="icn up">↑</a><a href="?id={$cotisation.id}&o=date&d&cats={$cats}" class="icn dn">↓</a></td> <td></td> </tr> </thead> <tbody> {foreach from=$liste item="co"} <tr> <td class="num">{$co.numero}</td> <th><a href="{$admin_url}membres/fiche.php?id={$co.id_membre}" class="icn">{$co.nom}</a></th> <td>{if $co.a_jour}<b class="confirm">À jour</b>{else}<b class="error">En retard</b>{/if}</td> <td>{$co.date|format_sqlite_date_to_french}</td> <td class="actions"> {if $session->canAccess('membres', Membres::DROIT_ECRITURE)} <a class="icn" href="{$admin_url}membres/cotisations/ajout.php?id={$co.id_membre}&cotisation={$cotisation.id}" title="Saisir une cotisation">➕</a> {/if} <a class="icn" href="{$admin_url}membres/cotisations.php?id={$co.id_membre}" title="Voir toutes les cotisations de ce membre">𝍢</a> |
︙ | ︙ |
Modified src/templates/admin/membres/fiche.tpl from [afe9db5157] to [747af1b2b4].
︙ | ︙ | |||
67 68 69 70 71 72 73 | <dd>{if empty($membre.date_connexion)}Jamais{else}{$membre.date_connexion|date_fr:'d/m/Y à H:i'}{/if}</dd> <dt>Mot de passe</dt> <dd> {if empty($membre.passe)} Pas de mot de passe configuré {else} <b class="icn">☑</b> Oui | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | <dd>{if empty($membre.date_connexion)}Jamais{else}{$membre.date_connexion|date_fr:'d/m/Y à H:i'}{/if}</dd> <dt>Mot de passe</dt> <dd> {if empty($membre.passe)} Pas de mot de passe configuré {else} <b class="icn">☑</b> Oui {if !empty($membre.secret_otp)} (<b class="icn">🔒</b> avec second facteur) {else} (<b class="icn">🔓</b> sans second facteur) {/if} {/if} </dd> </dl> |
︙ | ︙ |
Modified src/templates/admin/membres/modifier.tpl from [02f4db1009] to [8fb5353cd6].
︙ | ︙ | |||
40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" /> </dd> <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern="{$password_pattern}" /></dd> <dt><label for="f_repasse">Encore le mot de passe</label> (vérification){if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt> <dd><input type="password" name="passe_confirmed" id="f_repasse" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" /></dd> </dl> </fieldset> {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id} <fieldset> <legend>Général</legend> <dl> <dt><label for="f_cat">Catégorie du membre</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> | > > > > > > > > > > > > > > | 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <input type="text" readonly="readonly" title="Cliquer pour utiliser cette suggestion comme mot de passe" id="pw_suggest" value="{$passphrase}" autocomplete="off" /> </dd> <dd><input type="password" name="passe" id="f_passe" value="{form_field name=passe}" pattern="{$password_pattern}" /></dd> <dt><label for="f_repasse">Encore le mot de passe</label> (vérification){if $champs.passe.mandatory} <b title="(Champ obligatoire)">obligatoire</b>{/if}</dt> <dd><input type="password" name="passe_confirmed" id="f_repasse" value="{form_field name=passe_confirmed}" pattern="{$password_pattern}" /></dd> </dl> </fieldset> {if $membre.secret_otp || $membre.clef_pgp} <fieldset> <legend>Options de sécurité</legend> <dl> {if $membre.secret_otp} <dt><label><input type="checkbox" name="clear_otp" value="1" /> Désactiver l'authentification à double facteur TOTP</label></dt> {/if} {if $membre.clef_pgp} <dt><label><input type="checkbox" name="clear_pgp" value="1" /> Supprimer la clé PGP associée au membre</label></dt> {/if} </dl> </fieldset> {/if} {if $session->canAccess('membres', Membres::DROIT_ADMIN) && $user.id != $membre.id} <fieldset> <legend>Général</legend> <dl> <dt><label for="f_cat">Catégorie du membre</label> <b title="(Champ obligatoire)">obligatoire</b></dt> <dd> |
︙ | ︙ |
Modified src/templates/error.tpl from [52bccc1e68] to [5457db8bcb].
|
| | | | 1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta charset="utf-8" /> <title>{if empty($title)}Erreur{else}{$title}{/if}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <style type="text/css"> {literal} * { margin: 0; padding: 0; } html { width: 100%; height: 100%; } |
︙ | ︙ | |||
34 35 36 37 38 39 40 | <h1>{if empty($title)}Erreur{else}{$title}{/if}</h1> <p class="error"> {$error|escape|nl2br} </p> <p> | | | 34 35 36 37 38 39 40 41 42 43 44 45 | <h1>{if empty($title)}Erreur{else}{$title}{/if}</h1> <p class="error"> {$error|escape|nl2br} </p> <p> <a href="{$admin_url}" onclick="history.back(); return false;">← Retour</a> </p> </body> </html> |
Deleted src/templates/index.tpl version [e30875923e].
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < |
Modified src/www/admin/compta/comptes/index.php from [8422c33bbc] to [7140f6c1ad].
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $classe = (int) qg('classe'); $tpl->assign('classe', $classe); if (!$classe) { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | > > > > > > > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | <?php namespace Garradin; require_once __DIR__ . '/../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); if (qg('export') == 'plan') { $comptes->exportPlan(); exit; } $tpl->assign('confirm', qg('confirm')); if (f('import') && $form->check('plan_import', ['upload' => 'file|required', 'format' => 'required|in:json'])) { try { $comptes->importPlan($_FILES['upload']['tmp_name'], true); Utils::redirect(ADMIN_URL . 'compta/comptes/?import&confirm=import'); } catch (UserException $e) { $form->addError($e->getMessage()); } } elseif (f('reset') && $form->check('plan_reset')) { try { $comptes->importPlan(null, true); Utils::redirect(ADMIN_URL . 'compta/comptes/?import&confirm=reset'); } catch (UserException $e) { $form->addError($e->getMessage()); } } $classe = (int) qg('classe'); $tpl->assign('classe', $classe); if (!$classe) { $tpl->assign('classes', $comptes->listTree(0, false)); } else { $positions = $comptes->getPositions(); $tpl->assign('classe_compte', $comptes->get($classe)); $tpl->assign('liste', $comptes->listTree($classe)); } function tpl_get_position($pos) { global $positions; return $positions[$pos]; } $tpl->register_modifier('get_position', 'Garradin\tpl_get_position'); $template = 'index'; if ($classe) { $template = 'classe'; } elseif (qg('import') !== null) { $template = 'import'; $tpl->assign('confirm', qg('confirm')); } $tpl->display(sprintf('admin/compta/comptes/%s.tpl', $template)); |
Modified src/www/admin/compta/comptes/journal.php from [82a2dbba77] to [768483fe88].
︙ | ︙ | |||
8 9 10 11 12 13 14 | if (!$compte) { throw new UserException("Le compte demandé n'existe pas."); } $journal = new Compta\Journal; | > > > > | > > > | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | if (!$compte) { throw new UserException("Le compte demandé n'existe pas."); } $journal = new Compta\Journal; // Récupération de l'exercice courant et sélectionné $exercices = new Compta\Exercices; $exercice = (int) qg('exercice') ?: $exercices->getCurrent()->id; $solde = $journal->getSolde($compte->id, false, $exercice); if (($compte->position & Compta\Comptes::ACTIF) || ($compte->position & Compta\Comptes::CHARGE)) { $tpl->assign('credit', '-'); $tpl->assign('debit', '+'); } else { $tpl->assign('credit', '+'); $tpl->assign('debit', '-'); } $tpl->assign('exercices', $exercices->getList()); $tpl->assign('exercice_selectionne', $exercice); $tpl->assign('compte', $compte); $tpl->assign('solde', $solde); $tpl->assign('journal', $journal->getJournalCompte($compte->id, false, $exercice)); $tpl->assign('suivi', qg('suivi')); $tpl->display('admin/compta/comptes/journal.tpl'); |
Modified src/www/admin/config/index.php from [402547d004] to [149f2778eb].
1 2 3 4 5 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; | < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php namespace Garradin; require_once __DIR__ . '/_inc.php'; if (f('save') && $form->check('config')) { try { $config->set('nom_asso', f('nom_asso')); $config->set('email_asso', f('email_asso')); $config->set('adresse_asso', f('adresse_asso')); $config->set('site_asso', f('site_asso')); $config->set('accueil_wiki', f('accueil_wiki')); $config->set('accueil_connexion', f('accueil_connexion')); $config->set('categorie_membres', f('categorie_membres')); $config->set('champ_identite', f('champ_identite')); $config->set('champ_identifiant', f('champ_identifiant')); $config->set('pays', f('pays')); $config->set('monnaie', f('monnaie')); // N'enregistrer les couleurs que si ce ne sont pas les couleurs par défaut if (f('couleur1') != ADMIN_COLOR1 || f('couleur2') != ADMIN_COLOR2) { $config->set('couleur1', f('couleur1')); $config->set('couleur2', f('couleur2')); if (f('image_fond')) { $config->set('image_fond', f('image_fond')); |
︙ | ︙ | |||
66 67 68 69 70 71 72 | $tpl->assign('pays', Utils::getCountryList()); $cats = new Membres\Categories; $tpl->assign('membres_cats', $cats->listSimple()); $tpl->assign('champs', $config->get('champs_membres')->getList()); | | | > | | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | $tpl->assign('pays', Utils::getCountryList()); $cats = new Membres\Categories; $tpl->assign('membres_cats', $cats->listSimple()); $tpl->assign('champs', $config->get('champs_membres')->getList()); $tpl->assign('couleur1', $config->get('couleur1') ?: ADMIN_COLOR1); $tpl->assign('couleur2', $config->get('couleur2') ?: ADMIN_COLOR2); $tpl->assign('background_image_source', ADMIN_BACKGROUND_IMAGE); $tpl->assign('couleurs_defaut', [ADMIN_COLOR1, ADMIN_COLOR2]); $tpl->assign('custom_js', ['color_helper.js']); $tpl->display('admin/config/index.tpl'); |
Modified src/www/admin/membres/cotisations/voir.php from [db337019a9] to [8935c9e002].
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | if (!$co) { throw new UserException("Cette cotisation n'existe pas."); } $page = (int) qg('p') ?: 1; $tpl->assign('page', $page); $tpl->assign('bypage', Membres\Cotisations::ITEMS_PER_PAGE); $tpl->assign('total', $m_cotisations->countMembersForCotisation($co->id)); $tpl->assign('pagination_url', Utils::getSelfUrl([ 'id' => $co->id, 'o' => qg('o'), (qg('a') !== null ? 'a' : 'd') => '', 'p' => '[ID]', ])); $tpl->assign('cotisation', $co); $tpl->assign('order', qg('o') ?: 'date'); | > > > | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | if (!$co) { throw new UserException("Cette cotisation n'existe pas."); } $page = (int) qg('p') ?: 1; $categories = (int) qg('cats'); $tpl->assign('cats', $categories); $tpl->assign('page', $page); $tpl->assign('bypage', Membres\Cotisations::ITEMS_PER_PAGE); $tpl->assign('total', $m_cotisations->countMembersForCotisation($co->id)); $tpl->assign('pagination_url', Utils::getSelfUrl([ 'id' => $co->id, 'o' => qg('o'), (qg('a') !== null ? 'a' : 'd') => '', 'p' => '[ID]', 'cats' => $categories, ])); $tpl->assign('cotisation', $co); $tpl->assign('order', qg('o') ?: 'date'); $tpl->assign('desc', null === qg('a')); $tpl->assign('liste', $m_cotisations->listMembersForCotisation( $co->id, $categories, $page, qg('o'), null !== qg('a') ? false : true)); $tpl->display('admin/membres/cotisations/voir.tpl'); |
Modified src/www/admin/membres/message_collectif.php from [4372383f21] to [e6c89479ee].
︙ | ︙ | |||
18 19 20 21 22 23 24 | { if ($match[1] == 'categorie') { $recipients = $membres->listAllByCategory($match[2], true); } else { | > | | > > | > > | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | { if ($match[1] == 'categorie') { $recipients = $membres->listAllByCategory($match[2], true); } else { try { $recipients = $recherche->search($match[2], ['id', 'email'], true); } catch (UserException $e) { $form->addError($e->getMessage()); } } if (isset($recipients) && (!count($recipients) || !isset($recipients[0]->email))) { $form->addError('Aucun membre dans la liste.'); } } else { $form->addErrror('Destinataires invalides : ' . f('recipients')); } if (!$form->hasErrors()) { try { $membres->sendMessage($recipients, f('sujet'), f('message'), (bool) f('copie')); |
︙ | ︙ |
Modified src/www/admin/membres/modifier.php from [1cc5572967] to [87a063a4f2].
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 58 59 | } if ($session->canAccess('membres', Membres::DROIT_ADMIN) && $user->id != $membre->id) { $data['id_categorie'] = f('id_categorie'); $data['id'] = f('id'); } $membres->edit($id, $data); if (isset($data['id']) && $data['id'] != $id) { $id = (int)$data['id']; } | > > > > > > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | } if ($session->canAccess('membres', Membres::DROIT_ADMIN) && $user->id != $membre->id) { $data['id_categorie'] = f('id_categorie'); $data['id'] = f('id'); } if (f('clear_otp')) { $data['secret_otp'] = null; } if (f('clear_pgp')) { $data['clef_pgp'] = null; } $membres->edit($id, $data); if (isset($data['id']) && $data['id'] != $id) { $id = (int)$data['id']; } |
︙ | ︙ |
Modified src/www/admin/membres/recherche.php from [d259486866] to [ed8d36c24a].
︙ | ︙ | |||
54 55 56 57 58 59 60 | { throw new UserException('Recherche inconnue ou invalide'); } $query = $r->query; $order = $r->order; $desc = $r->desc; | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | { throw new UserException('Recherche inconnue ou invalide'); } $query = $r->query; $order = $r->order; $desc = $r->desc; $limit = (int) f('limit') ?: $r->limit; $tpl->assign('recherche', $r); } if (f('q') !== null) { $query = json_decode(f('q'), true); |
︙ | ︙ |
Modified src/www/admin/static/print.css from [e54ede2290] to [3d3e25b3f9].
︙ | ︙ | |||
64 65 66 67 68 69 70 | #rapport .parent { background: #ccc; } .noprint { display: none; } | > > > | 64 65 66 67 68 69 70 71 72 73 | #rapport .parent { background: #ccc; } .noprint { display: none; } td.actions * { display: none; } |
Modified src/www/admin/static/scripts/color_helper.js from [1f3037b2de] to [e3dcda260f].
︙ | ︙ | |||
26 27 28 29 30 31 32 | applyLogoColors(); } function applyLogoColors() { var color = colorToRGB(document.getElementById('f_couleur2').value); | | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | applyLogoColors(); } function applyLogoColors() { var color = colorToRGB(document.getElementById('f_couleur2').value); var img = new Image; img.crossOrigin = "Anonymous"; img.onload = function() { var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, img.width, img.height); |
︙ | ︙ | |||
63 64 65 66 67 68 69 70 71 72 73 74 75 76 | document.getElementById('f_image_fond').value = i.substr(i.indexOf(',')+1); delete canvas2; delete canvas; delete ctx; }; } garradin.onload(function () { var couleurs = {'couleur1': 'gMainColor', 'couleur2': 'gSecondColor'}; for (var couleur in couleurs) { | > > | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | document.getElementById('f_image_fond').value = i.substr(i.indexOf(',')+1); delete canvas2; delete canvas; delete ctx; }; img.src = document.getElementById('f_image_fond').getAttribute('data-source'); } garradin.onload(function () { var couleurs = {'couleur1': 'gMainColor', 'couleur2': 'gSecondColor'}; for (var couleur in couleurs) { |
︙ | ︙ |