Comment: | Merge with trunk |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | templates |
Files: | files | file ages | folders |
SHA3-256: |
6a4f6f6abc066bc6e18facd808565bcb |
User & Date: | bohwaz on 2021-12-22 22:04:13 |
Other Links: | branch diff | manifest | tags |
2021-12-24
| ||
02:14 | Allow to update JSON data, but for validation we need to fetch and decode JSON first check-in: 2ea97a9a6d user: bohwaz tags: templates | |
2021-12-22
| ||
22:04 | Merge with trunk check-in: 6a4f6f6abc user: bohwaz tags: templates | |
19:57 | Avoid duplicates when copying a service check-in: a9cf5c62d0 user: bohwaz tags: trunk, stable | |
2021-12-21
| ||
02:30 | Duplicate after merge check-in: f9dd9435f9 user: bohwaz tags: templates | |
Modified src/include/lib/Garradin/Accounting/Accounts.php from [9d40c3912e] to [be892e76e5].
︙ | ︙ | |||
81 82 83 84 85 86 87 | } /** * Return only analytical accounts */ public function listAnalytical(): array { | | | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | } /** * Return only analytical accounts */ public function listAnalytical(): array { return $this->em->DB()->getAssoc($this->em->formatQuery('SELECT id, label FROM @TABLE WHERE id_chart = ? AND type = ? ORDER BY label COLLATE NOCASE;'), $this->chart_id, Account::TYPE_ANALYTICAL); } /** * Return only analytical accounts */ public function listVolunteering(): array { |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Accounting/Account.php from [cacd2727a4] to [71842e7b88].
︙ | ︙ | |||
184 185 186 187 188 189 190 | $this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide'); $this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide'); $this->assert($this->user === 0 || $this->user === 1); parent::selfCheck(); } | | > > > > > > > > > > | 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | $this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide'); $this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide'); $this->assert($this->user === 0 || $this->user === 1); parent::selfCheck(); } public function listJournal(int $year_id, bool $simple = false, ?DateTimeInterface $start = null, ?DateTimeInterface $end = null) { $db = DB::getInstance(); $columns = self::LIST_COLUMNS; $tables = 'acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction LEFT JOIN acc_accounts b ON b.id = l.id_analytical'; $conditions = sprintf('l.id_account = %d AND t.id_year = %d', $this->id(), $year_id); $sum = 0; $reverse = $simple && self::isReversed($this->type) ? -1 : 1; if ($start) { $conditions .= sprintf(' AND t.date >= %s', $db->quote($start->format('Y-m-d'))); $sum = $this->getSumAtDate($year_id, $start) * $reverse; } if ($end) { $conditions .= sprintf(' AND t.date <= %s', $db->quote($end->format('Y-m-d'))); } if ($simple) { unset($columns['debit']['label'], $columns['credit']['label'], $columns['line_label']); $columns['line_reference']['label'] = 'Réf. paiement'; $columns['change']['select'] = sprintf($columns['change']['select'], $reverse); } else { |
︙ | ︙ | |||
444 445 446 447 448 449 450 | public function getSumAtDate(int $year_id, DateTimeInterface $date, bool $reconciled_only = false): int { $sql = sprintf('SELECT SUM(l.credit) - SUM(l.debit) FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction | | | 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 | public function getSumAtDate(int $year_id, DateTimeInterface $date, bool $reconciled_only = false): int { $sql = sprintf('SELECT SUM(l.credit) - SUM(l.debit) FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction WHERE l.id_account = ? AND t.id_year = ? AND t.date < ? %s;', $reconciled_only ? 'AND l.reconciled = 1' : ''); return (int) DB::getInstance()->firstColumn($sql, $this->id(), $year_id, $date->format('Y-m-d')); } public function importSimpleForm(array $translate_type_position, array $translate_type_codes, ?array $source = null) { if (null === $source) { |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Accounting/Transaction.php from [c396fad605] to [fac4ec7e24].
︙ | ︙ | |||
820 821 822 823 824 825 826 | $account->targets_string = implode(':', $account->targets); } } return $details; } | | | | 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 | $account->targets_string = implode(':', $account->targets); } } return $details; } public function payOffFrom(int $id): ?\stdClass { $this->_related = EntityManager::findOneById(self::class, $id); if (!$this->_related) { return null; } $this->id_related = $this->_related->id(); $this->label = ($this->_related->type == Transaction::TYPE_DEBT ? 'Règlement de dette : ' : 'Règlement de créance : ') . $this->_related->label; $this->type = $this->_related->type; $out = (object) [ |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Services/Service.php from [1865b4e6a7] to [bac627a89f].
1 2 3 4 5 6 7 8 9 10 11 12 | <?php namespace Garradin\Entities\Services; use Garradin\Config; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; use Garradin\Services\Fees; class Service extends Entity | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | <?php namespace Garradin\Entities\Services; use Garradin\Config; use Garradin\DB; use Garradin\DynamicList; use Garradin\Entity; use Garradin\ValidationException; use Garradin\Utils; use Garradin\Services\Fees; class Service extends Entity |
︙ | ︙ | |||
128 129 130 131 132 133 134 | public function expiredUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_service = %d AND su.expiry_date < date() AND m.id_category NOT IN (SELECT id FROM users_categories WHERE hidden = 1)', $this->id()); $list->setConditions($conditions); return $list; } | | > > > > > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | public function expiredUsersList(): DynamicList { $list = $this->paidUsersList(); $conditions = sprintf('su.id_service = %d AND su.expiry_date < date() AND m.id_category NOT IN (SELECT id FROM users_categories WHERE hidden = 1)', $this->id()); $list->setConditions($conditions); return $list; } public function getUsers(bool $paid_only = false) { $where = $paid_only ? 'AND paid = 1' : ''; $id_field = Config::getInstance()->champ_identite; $sql = sprintf('SELECT su.id_user, u.%s FROM services_users su INNER JOIN membres u ON u.id = su.id_user WHERE su.id_service = ? %s;', $id_field, $where); return DB::getInstance()->getAssoc($sql, $this->id()); } } |
Modified src/include/lib/Garradin/Entities/Services/Service_User.php from [70686305f9] to [9c410c5349].
︙ | ︙ | |||
41 42 43 44 45 46 47 | protected $_service, $_fee; public function selfCheck(): void { $this->paid = (bool) $this->paid; $this->assert($this->id_service, 'Aucune activité spécifiée'); $this->assert($this->id_user, 'Aucun membre spécifié'); | | > | > > > > > > > > > > > > > > > > > > > | 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 | protected $_service, $_fee; public function selfCheck(): void { $this->paid = (bool) $this->paid; $this->assert($this->id_service, 'Aucune activité spécifiée'); $this->assert($this->id_user, 'Aucun membre spécifié'); $this->assert(!$this->isDuplicate(), 'Cette activité a déjà été enregistrée pour ce membre et cette date'); } public function isDuplicate(bool $using_date = true): bool { $params = [ 'id_user' => $this->id_user, 'id_service' => $this->id_service, ]; if ($using_date) { $params['date'] = $this->date->format('Y-m-d'); } if ($this->exists()) { $params['id'] = $this->id(); } $where = array_map(fn($k) => sprintf('%s = ?', $k), array_keys($params)); $where = implode(' AND ', $where); return DB::getInstance()->test(self::TABLE, $where, array_values($params)); } public function importForm(?array $source = null) { if (null === $source) { $source = $_POST; } |
︙ | ︙ | |||
137 138 139 140 141 142 143 | $transaction->importFromNewForm($source); $transaction->save(); $transaction->linkToUser($this->id_user, $this->id()); return $transaction; } | | > | | | > | | | > > > > > > > > > | | | | | | | | | | | | | > | 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 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | $transaction->importFromNewForm($source); $transaction->save(); $transaction->linkToUser($this->id_user, $this->id()); return $transaction; } static public function createFromForm(array $users, int $creator_id, bool $from_copy = false, ?array $source = null) { if (null === $source) { $source = $_POST; } $db = DB::getInstance(); $db->begin(); foreach ($users as $id => $name) { $su = new self; $su->date = new \DateTime; $su->importForm($source); $su->id_user = (int) $id; if ($su->id_fee && $su->fee()->id_account && $su->id_user) { $su->expected_amount = $su->fee()->getAmountForUser($su->id_user); } if ($su->isDuplicate($from_copy ? false : true)) { if ($from_copy) { continue; } else { throw new ValidationException(sprintf('%s : Cette activité a déjà été enregistrée pour ce membre et cette date', $name)); } } $su->save(); if ($su->id_fee && $su->fee()->id_account && !empty($source['amount']) && !empty($source['create_payment'])) { try { $su->addPayment($creator_id, $source); } catch (ValidationException $e) { if ($e->getMessage() == 'Il n\'est pas possible de créer ou modifier une écriture dans un exercice clôturé') { throw new ValidationException('Impossible d\'enregistrer l\'inscription : ce tarif d\'activité est lié à un exercice clôturé. Merci de modifier le tarif et choisir un autre exercice.', 0, $e); } else { throw $e; } } } } $db->commit(); return $su; } } |
Modified src/include/lib/Garradin/UserTemplate/CommonModifiers.php from [ff55855833] to [ec639e95ae].
︙ | ︙ | |||
401 402 403 404 405 406 407 | array_walk($attributes_string, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $v); }); $attributes_string = implode(' ', $attributes_string); | > > > > > > > | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | array_walk($attributes_string, function (&$v, $k) { $v = sprintf('%s="%s"', $k, $v); }); $attributes_string = implode(' ', $attributes_string); if ($type == 'radio-btn') { $radio = self::formInput(array_merge($params, ['type' => 'radio', 'label' => null, 'help' => null])); $out = sprintf('<dd class="radio-btn">%s <label for="f_%s_%s"><div><h3>%s</h3>%s</div></label> </dd>', $radio, htmlspecialchars($name), htmlspecialchars($value), htmlspecialchars($label), isset($params['help']) ? '<p>' . htmlspecialchars($params['help']) . '</p>' : ''); return $out; } elseif ($type == 'select') { $input = sprintf('<select %s>', $attributes_string); foreach ($options as $_key => $_value) { $input .= sprintf('<option value="%s"%s>%s</option>', $_key, $current_value == $_key ? ' selected="selected"' : '', htmlspecialchars($_value)); } $input .= '</select>'; |
︙ | ︙ |
Modified src/include/lib/Garradin/UserTemplate/Functions.php from [733e4434da] to [99cd2b0ba8].
︙ | ︙ | |||
54 55 56 57 58 59 60 | throw new Brindille_Exception('Unique document name could not be found'); } if (empty($params['name']) || !ctype_alnum($params['name'])) { throw new Brindille_Exception('Missing or invalid index name'); } | > > > | > > > > > > > > < | | 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 | throw new Brindille_Exception('Unique document name could not be found'); } if (empty($params['name']) || !ctype_alnum($params['name'])) { throw new Brindille_Exception('Missing or invalid index name'); } $indexes = ['document']; $db = DB::getInstance(); if (empty($params['column'])) { $indexes[] = sprintf('json_extract(value, %s)', $db->quote($params['column'])); } if (empty($params['expression'])) { $indexes[] = $params['expression']; } if (count($indexes) == 1) { throw new Brindille_Exception('Missing or invalid index columns'); } $db->exec(sprintf('CREATE INDEX IF NOT EXISTS documents_%s_%s ON documents_data (%s);', $id, implode(',', $indexes))); } static public function save(array $params, Brindille $tpl, int $line): void { $id = Utils::basename(Utils::dirname($tpl->_tpl_path)); if (!$id) { |
︙ | ︙ | |||
158 159 160 161 162 163 164 | } static public function signature_url(): string { $file = Config::getInstance()->file('signature'); if (!$file) { | | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | } static public function signature_url(): string { $file = Config::getInstance()->file('signature'); if (!$file) { return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; } return 'data:image/png;base64,' . base64_encode($file->fetch()); } static public function include(array $params, UserTemplate $ut, int $line): void { |
︙ | ︙ |
Modified src/include/lib/Garradin/Utils.php from [74b0fa5592] to [1fb8515d7b].
︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | 'Fri' => 'ven', 'Sat' => 'sam', 'Sun' => 'dim', ]; static public function get_datetime($ts) { if (is_object($ts) && $ts instanceof \DateTimeInterface) { return $ts; } elseif (is_numeric($ts)) { $ts = new \DateTime('@' . $ts); $ts->setTimezone(new \DateTimeZone(date_default_timezone_get())); return $ts; } elseif (strlen($ts) == 10) { return \DateTime::createFromFormat('!Y-m-d', $ts); } elseif (strlen($ts) == 19) { return \DateTime::createFromFormat('Y-m-d H:i:s', $ts); } else { | > > > > > > > | 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 | 'Fri' => 'ven', 'Sat' => 'sam', 'Sun' => 'dim', ]; static public function get_datetime($ts) { if (null === $ts) { return null; } if (is_object($ts) && $ts instanceof \DateTimeInterface) { return $ts; } elseif (is_numeric($ts)) { $ts = new \DateTime('@' . $ts); $ts->setTimezone(new \DateTimeZone(date_default_timezone_get())); return $ts; } elseif (preg_match('!^\d{2}/\d{2}/\d{4}$!', $ts)) { return \DateTime::createFromFormat('!d/m/Y', $ts); } elseif (strlen($ts) == 10) { return \DateTime::createFromFormat('!Y-m-d', $ts); } elseif (strlen($ts) == 19) { return \DateTime::createFromFormat('Y-m-d H:i:s', $ts); } else { |
︙ | ︙ |
Modified src/include/lib/dependencies.list from [e9b8ffa0d9] to [aa4290a8f6].
︙ | ︙ | |||
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | KD2/FossilInstaller.php KD2/HTTP.php KD2/Graphics/Image.php KD2/Graphics/QRCode.php KD2/Graphics/SVG/Pie.php KD2/Graphics/SVG/Plot.php KD2/Graphics/SVG/Bar.php KD2/Office/Calc/Writer.php KD2/Security.php KD2/Security_OTP.php KD2/SimpleDiff.php KD2/SkrivLite.php KD2/Smartyer.php KD2/SMTP.php KD2/Translate.php KD2/UserSession.php KD2/ZipWriter.php Parsedown.php | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | KD2/FossilInstaller.php KD2/HTTP.php KD2/Graphics/Image.php KD2/Graphics/QRCode.php KD2/Graphics/SVG/Pie.php KD2/Graphics/SVG/Plot.php KD2/Graphics/SVG/Bar.php KD2/JSONSchema.php KD2/Office/Calc/Writer.php KD2/Security.php KD2/Security_OTP.php KD2/SimpleDiff.php KD2/SkrivLite.php KD2/Smartyer.php KD2/SMTP.php KD2/Translate.php KD2/UserSession.php KD2/ZipWriter.php Parsedown.php |
Modified src/templates/acc/accounts/journal.tpl from [92b1619c26] to [f4432495e8].
︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | {linkbutton href="!acc/transactions/new.php?account=%d"|args:$account.id label="Saisir une écriture dans ce compte" shape="plus"} {/if} </aside> <ul> <li{if $simple} class="current"{/if}><a href="?id={$account.id}&simple=1&year={$year.id}">Vue simplifiée</a></li> <li{if !$simple} class="current"{/if}><a href="?id={$account.id}&simple=0&year={$year.id}">Vue comptable</a></li> </ul> </nav> {/if} <form method="post" action="{$admin_url}acc/transactions/actions.php"> {include file="common/dynamic_list_head.tpl" check=$can_edit} {foreach from=$list->iterate() item="line"} <tr> | > > > > > > > > > > > > > > > > > > > > > > > | 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 | {linkbutton href="!acc/transactions/new.php?account=%d"|args:$account.id label="Saisir une écriture dans ce compte" shape="plus"} {/if} </aside> <ul> <li{if $simple} class="current"{/if}><a href="?id={$account.id}&simple=1&year={$year.id}">Vue simplifiée</a></li> <li{if !$simple} class="current"{/if}><a href="?id={$account.id}&simple=0&year={$year.id}">Vue comptable</a></li> </ul> {if !$filter.start && !$filter.end} <aside> {linkbutton shape="search" href="?start=1" label="Filtrer" onclick="g.toggle('#filterForm', true); this.remove(); return false;"} </aside> {/if} </nav> {/if} <form method="get" action="{$self_url}"{if !$filter.start && !$filter.end} class="hidden"{/if} id="filterForm"> <fieldset> <legend>Filtrer par date</legend> <p> Du {input type="date" name="start" source=$filter default=$year.start_date} au {input type="date" name="end" source=$filter default=$year.end_date} <input type="hidden" name="id" value="{$account.id}" /> <input type="hidden" name="year" value="{$year.id}" /> <input type="hidden" name="simple" value="{$simple}" /> <input type="submit" value="Filtrer" /> </p> </fieldset> </form> <form method="post" action="{$admin_url}acc/transactions/actions.php"> {include file="common/dynamic_list_head.tpl" check=$can_edit} {foreach from=$list->iterate() item="line"} <tr> |
︙ | ︙ | |||
111 112 113 114 115 116 117 | </tbody> <tfoot> <tr> {if $can_edit} <td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td> {/if} {if !$simple}<td></td>{/if} | > | | > > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | </tbody> <tfoot> <tr> {if $can_edit} <td class="check"><input type="checkbox" value="Tout cocher / décocher" id="f_all2" /><label for="f_all2"></label></td> {/if} {if !$simple}<td></td>{/if} {if null !== $sum} <td colspan="3">Solde</td> <td class="money">{$sum|raw|money:false}</td> {else} <td colspan="4"></td> {/if} {if !$simple}<td></td>{/if} <td class="actions" colspan="5"> {if $can_edit} <em>Pour les écritures cochées :</em> <input type="hidden" name="from" value="{$self_url}" /> <input type="hidden" name="year" value="{$year.id}" /> {csrf_field key="projects_action"} |
︙ | ︙ |
Modified src/templates/admin/membres/_list_actions.tpl from [70c6941282] to [b514dbed79].
︙ | ︙ | |||
8 9 10 11 12 13 14 | <option value="">— Choisir une action à effectuer —</option> <option value="move">Changer de catégorie</option> <option value="template">Générer des documents</option> {if !isset($export) || $export != false} <option value="csv">Exporter en tableau CSV</option> <option value="ods">Exporter en classeur Office</option> {/if} | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <option value="">— Choisir une action à effectuer —</option> <option value="move">Changer de catégorie</option> <option value="template">Générer des documents</option> {if !isset($export) || $export != false} <option value="csv">Exporter en tableau CSV</option> <option value="ods">Exporter en classeur Office</option> {/if} <option value="delete">Supprimer le membre</option> </select> <noscript> <input type="submit" value="OK" /> </noscript> </td> </tr> </tfoot> |
Modified src/templates/admin/membres/fiche.tpl from [858a55f227] to [56a79db109].
︙ | ︙ | |||
28 29 30 31 32 33 34 | </dd> {/foreach} <dd> {if count($services)} {linkbutton href="!services/user/?id=%d"|args:$membre.id label="Liste des inscriptions aux activités" shape="menu"} {/if} {if $session->canAccess($session::SECTION_USERS, $session::ACCESS_WRITE)} | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | </dd> {/foreach} <dd> {if count($services)} {linkbutton href="!services/user/?id=%d"|args:$membre.id label="Liste des inscriptions aux activités" shape="menu"} {/if} {if $session->canAccess($session::SECTION_USERS, $session::ACCESS_WRITE)} {linkbutton href="!services/user/subscribe.php?user=%d"|args:$membre.id label="Inscrire à une activité" shape="plus"} {/if} </dd> {if count($services)} <dd> {linkbutton shape="alert" label="Liste des rappels envoyés" href="!services/reminders/user.php?id=%d"|args:$membre.id} </dd> {/if} |
︙ | ︙ |
Modified src/templates/services/user/_service_user_form.tpl from [10a2edc910] to [75a8977fdd].
1 2 3 4 | <?php assert(isset($create) && is_bool($create)); assert(isset($has_past_services) && is_bool($has_past_services)); assert(isset($current_only) && is_bool($current_only)); | < | 1 2 3 4 5 6 7 8 9 10 11 | <?php assert(isset($create) && is_bool($create)); assert(isset($has_past_services) && is_bool($has_past_services)); assert(isset($current_only) && is_bool($current_only)); assert(isset($form_url) && is_string($form_url)); assert(isset($today) && $today instanceof \DateTimeInterface); assert($create === false || isset($account_targets)); assert(isset($grouped_services) && is_array($grouped_services)); ?> <form method="post" action="{$self_url}" data-focus="1" data-create="{$create|escape:json}"> |
︙ | ︙ | |||
20 21 22 23 24 25 26 | </nav> {/if} <fieldset> <legend>Inscrire un membre à une activité</legend> <dl> | > | > > | > > > > > > > > > | 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 | </nav> {/if} <fieldset> <legend>Inscrire un membre à une activité</legend> <dl> {if $create && $users} <dt>Membres inscrits</dt> {if count($users) <= 10} {foreach from=$users key="id" item="name"} <dd>{$name}<input type="hidden" name="users[{$id}]" value="{$name}" /></dd> {/foreach} {else} <dd>{$users|count} membres sélectionnés</dd> {/if} {elseif $create && $copy_service} <dt>Recopier depuis l'activité</dt> <dd><strong>{$copy_service.label}</strong><input type="hidden" name="copy_service" value="{$copy_service.id}" /></dd> <dd><em>{if $copy_service_only_paid}(seulement les inscriptions marquées comme payées){else}(toutes les inscriptions){/if}</em><input type="hidden" name="copy_service_only_paid" value="{$copy_service_only_paid}" /></dd> {/if} <dt><label for="f_service_ID">Activité</label> <b>(obligatoire)</b></dt> {foreach from=$grouped_services item="service"} <dd class="radio-btn"> {input type="radio" name="id_service" value=$service.id data-duration=$service.duration data-expiry=$service.expiry_date|date_short label=null source=$service_user} <label for="f_id_service_{$service.id}"> |
︙ | ︙ | |||
65 66 67 68 69 70 71 | {foreach from=$service.fees key="service_id" item="fee"} <dd class="radio-btn"> {input type="radio" name="id_fee" value=$fee.id data-user-amount=$fee.user_amount data-account=$fee.id_account data-year=$fee.id_year label=null source=$service_user } <label for="f_id_fee_{$fee.id}"> <div> <h3>{$fee.label}</h3> <p> | < < | > > > > | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | {foreach from=$service.fees key="service_id" item="fee"} <dd class="radio-btn"> {input type="radio" name="id_fee" value=$fee.id data-user-amount=$fee.user_amount data-account=$fee.id_account data-year=$fee.id_year label=null source=$service_user } <label for="f_id_fee_{$fee.id}"> <div> <h3>{$fee.label}</h3> <p> {if $fee.user_amount && $fee.formula} <strong>{$fee.user_amount|raw|money_currency}</strong> (montant calculé) {elseif $fee.formula} montant calculé, variable selon les membres {elseif $fee.user_amount} <strong>{$fee.user_amount|raw|money_currency}</strong> {else} prix libre ou gratuit {/if} </p> {if $fee.description} <p class="help"> {$fee.description|escape|nl2br} </p> {/if} |
︙ | ︙ | |||
118 119 120 121 122 123 124 | </fieldset> {/if} <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} | | | 131 132 133 134 135 136 137 138 139 140 141 142 143 | </fieldset> {/if} <p class="submit"> {csrf_field key=$csrf_key} {button type="submit" name="save" label="Enregistrer" shape="right" class="main"} {if $create && $users && count($users) == 1} {button type="submit" name="save_and_add_payment" class="accounting" label="Enregistrer et ajouter un autre règlement" shape="plus"} {/if} </p> </form> |
Modified src/templates/services/user/add.tpl from [e38a83f3e8] to [027f0b9b0f].
1 2 3 4 5 6 | {include file="admin/_head.tpl" title="Inscrire à une activité" current="membres/services"} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} | < | | > > > > | > > > > > > > > > > > > < | > > > > > > | < > > > | > | 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 | {include file="admin/_head.tpl" title="Inscrire à une activité" current="membres/services"} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} <form method="post" action="subscribe.php" data-focus="button"> <fieldset> <legend>Inscrire à une activité</legend> <dl> {input type="radio-btn" name="choice" value="1" label="Sélectionner des membres" default=1} {input type="radio-btn" name="choice" value="2" label="Recopier depuis une activité" help="Utile si vous avez une cotisation par année civile par exemple : copie les membres inscrits l'année précédente dans la nouvelle année."} </dl> </fieldset> <fieldset class="c1"> <legend>Inscrire des membres</legend> <dl> {input type="list" name="users" required=true label="Membres à inscrire" target="membres/selector.php" multiple=true} </dl> </fieldset> <fieldset class="c2"> <legend>Recopier depuis une activité</legend> <dl> {input type="select" name="copy_service" label="Activité à recopier" options=$services required=true} {input type="checkbox" name="copy_service_only_paid" value="1" label="Ne recopier que les membres dont l'inscription est payée"} </dl> </fieldset> <p class="submit"> {button type="submit" name="next" label="Continuer" shape="right" class="main"} </p> </form> <script type="text/javascript"> {literal} function selectChoice() { let choice = $('#f_choice_1').form.choice.value; g.toggle('.c1', choice == 1); g.toggle('.c2', choice == 2); } selectChoice(); $('#f_choice_1').onchange = selectChoice; $('#f_choice_2').onchange = selectChoice; {/literal} </script> {include file="admin/_foot.tpl"} |
Modified src/templates/services/user/index.tpl from [0bde5bd459] to [43943e4257].
1 2 3 4 | {include file="admin/_head.tpl" title="%s — Inscriptions aux activités et cotisations"|args:$user.identite current="membres/services"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$user.id label="Retour à la fiche membre" shape="user"} | | | 1 2 3 4 5 6 7 8 9 10 11 12 | {include file="admin/_head.tpl" title="%s — Inscriptions aux activités et cotisations"|args:$user.identite current="membres/services"} <p> {linkbutton href="!membres/fiche.php?id=%d"|args:$user.id label="Retour à la fiche membre" shape="user"} {linkbutton href="!services/user/subscribe.php?user=%d"|args:$user.id label="Inscrire à une activité" shape="plus"} </p> {form_errors} <dl class="cotisation"> <dt>Statut des inscriptions</dt> {foreach from=$services item="service"} |
︙ | ︙ |
Added src/templates/services/user/subscribe.tpl version [8f9805b504].
> > > > > > > > > | 1 2 3 4 5 6 7 8 9 | {include file="admin/_head.tpl" title="Inscrire à une activité" current="membres/services"} {include file="services/_nav.tpl" current="save" fee=null service=null} {form_errors} {include file="services/user/_service_user_form.tpl" create=true} {include file="admin/_foot.tpl"} |
Modified src/www/admin/acc/accounts/journal.php from [da00ba6416] to [af0fa51c71].
︙ | ︙ | |||
47 48 49 50 51 52 53 | $simple = qg('simple'); // Use simplified view for favourite accounts if (null === $simple) { $simple = (bool) $account->type; } | > > > > | > > > | > > | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | $simple = qg('simple'); // Use simplified view for favourite accounts if (null === $simple) { $simple = (bool) $account->type; } $filter = new \stdClass; $filter->start = Utils::get_datetime(qg('start')); $filter->end = Utils::get_datetime(qg('end')); $list = $account->listJournal($year_id, $simple, $filter->start, $filter->end); $list->setTitle(sprintf('Journal - %s - %s', $account->code, $account->label)); $list->loadFromQueryString(); $sum = null; if (!$filter->start && !$filter->end) { $sum = $account->getSum($year_id, $simple); } $tpl->assign(compact('simple', 'year', 'account', 'list', 'sum', 'can_edit', 'filter')); $tpl->display('acc/accounts/journal.tpl'); |
Modified src/www/admin/services/user/_form.php from [355c6ae19e] to [9911775664].
1 2 3 4 5 6 7 8 9 10 11 | <?php namespace Garradin; use Garradin\Services\Services; if (!defined('\Garradin\ROOT')) { die(); } | | > > > > > > | | > | 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 | <?php namespace Garradin; use Garradin\Services\Services; if (!defined('\Garradin\ROOT')) { die(); } assert(isset($tpl, $form_url, $create)); $current_only = !qg('past_services'); // If there is only one user selected we can calculate the amount $single_user_id = isset($users) && count($users) == 1 ? key($users) : null; $copy_service ??= null; $copy_service_only_paid ??= null; $users ??= null; $grouped_services = Services::listGroupedWithFees($single_user_id, $current_only); if (!count($grouped_services)) { Utils::redirect($form_url . 'past_services=' . (int) $current_only); } if (!isset($count_all)) { $count_all = Services::count(); } $has_past_services = count($grouped_services) != $count_all; $today = new \DateTime; $tpl->assign([ 'custom_js' => ['service_form.js'], ]); $tpl->assign(compact('form_url', 'today', 'grouped_services', 'current_only', 'has_past_services', 'create', 'copy_service', 'copy_service_only_paid', 'users')); |
Modified src/www/admin/services/user/add.php from [614b57c4f4] to [1b2cc90329].
1 2 3 4 | <?php namespace Garradin; use Garradin\Services\Services; | < < < < | < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <?php namespace Garradin; use Garradin\Services\Services; require_once __DIR__ . '/../_inc.php'; $session->requireAccess($session::SECTION_USERS, $session::ACCESS_WRITE); // This controller allows to either select a user if none has been provided in the query string // or subscribe a user to an activity (create a new Service_User entity) // If $user_id is null then the form is just a select to choose a user $count_all = Services::count(); if (!$count_all) { Utils::redirect(ADMIN_URL . 'services/?CREATE'); } $services = Services::listAssoc(); $tpl->assign(compact('services')); $tpl->display('services/user/add.tpl'); |
Modified src/www/admin/services/user/edit.php from [b0b3db3c77] to [f09c2d97e9].
︙ | ︙ | |||
10 11 12 13 14 15 16 | $su = Services_User::get((int) qg('id')); if (!$su) { throw new UserException("Cette inscription n'existe pas"); } $csrf_key = 'su_edit_' . $su->id(); | < | > | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | $su = Services_User::get((int) qg('id')); if (!$su) { throw new UserException("Cette inscription n'existe pas"); } $csrf_key = 'su_edit_' . $su->id(); $users = [$su->id_user => (new Membres)->getNom($su->id_user)]; $form_url = sprintf('edit.php?id=%d&', $su->id()); $create = false; require __DIR__ . '/_form.php'; $form->runIf('save', function () use ($su) { $su->importForm(); $su->save(); }, $csrf_key, ADMIN_URL . 'services/user/?id=' . $su->id_user); $service_user = $su; $tpl->assign(compact('csrf_key', 'service_user')); $tpl->display('services/user/edit.tpl'); |
Added src/www/admin/services/user/subscribe.php version [72bcfd51bb].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 72 73 74 75 76 | <?php namespace Garradin; use Garradin\Services\Services; use Garradin\Entities\Services\Service_User; use Garradin\Entities\Accounting\Account; use Garradin\Entities\Accounting\Transaction; require_once __DIR__ . '/../_inc.php'; $session->requireAccess($session::SECTION_USERS, $session::ACCESS_WRITE); // This controller allows to either select a user if none has been provided in the query string // or subscribe a user to an activity (create a new Service_User entity) // If $user_id is null then the form is just a select to choose a user $count_all = Services::count(); if (!$count_all) { Utils::redirect(ADMIN_URL . 'services/?CREATE'); } $users = null; $copy_service = null; $copy_service_only_paid = null; if (qg('user') && ($name = (new Membres)->getNom((int)qg('user')))) { $users = [(int)qg('user') => $name]; } elseif (f('users') && is_array(f('users'))) { $users = f('users'); $users = array_filter($users, 'intval', \ARRAY_FILTER_USE_KEY); } elseif (f('copy_service') && $copy_service = Services::get((int)f('copy_service'))) { $copy_service_only_paid = (bool) f('copy_service_only_paid'); } else { throw new UserException('Aucun membre n\'a été sélectionné'); } $form_url = '?'; $csrf_key = 'service_save'; $create = true; // Only load the form if a user has been selected require __DIR__ . '/_form.php'; $form->runIf(f('save') || f('save_and_add_payment'), function () use ($session, $users, $copy_service, $copy_service_only_paid) { if ($copy_service) { $users = $copy_service->getUsers($copy_service_only_paid); } $su = Service_User::createFromForm($users, $session->getUser()->id, $copy_service ? true : false); if (count($users) > 1) { $url = ADMIN_URL . 'services/details.php?id=' . $su->id_service; } elseif (f('save_and_add_payment')) { $url = ADMIN_URL . 'services/user/payment.php?id=' . $su->id; } else { $url = ADMIN_URL . 'services/user/?id=' . $su->id_user; } Utils::redirect($url); }, $csrf_key); $types_details = Transaction::getTypesDetails(); $account_targets = $types_details[Transaction::TYPE_REVENUE]->accounts[1]->targets_string; $service_user = null; $tpl->assign(compact('csrf_key', 'users', 'account_targets', 'service_user')); $tpl->display('services/user/subscribe.tpl'); |
Modified src/www/admin/static/styles/05-navigation.css from [d3ea311406] to [2228a1d3bc].
︙ | ︙ | |||
49 50 51 52 53 54 55 | text-decoration: underline; border-bottom: none; } nav.tabs aside { float: right; max-width: 50%; | | > | 49 50 51 52 53 54 55 56 57 58 | text-decoration: underline; border-bottom: none; } nav.tabs aside { float: right; max-width: 50%; text-align: right; clear: right; } |
Modified src/www/admin/web/page.php from [7684223213] to [fa91cc041f].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?php namespace Garradin; use Garradin\Web\Web; use Garradin\Entities\Web\Page; require_once __DIR__ . '/_inc.php'; $page = Web::get(qg('p')); if (!$page) { throw new UserException('Page inconnue'); } | > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?php namespace Garradin; use Garradin\Web\Web; use Garradin\Entities\Web\Page; require_once __DIR__ . '/_inc.php'; if (!qg('p')) { throw new UserException('Page inconnue'); } $page = Web::get(qg('p')); if (!$page) { throw new UserException('Page inconnue'); } |
︙ | ︙ |