Comment: | Implement: add account to chart |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | dev |
Files: | files | file ages | folders |
SHA1: |
6d7d32626778abe1dbcb403a8d86cdfc |
User & Date: | bohwaz on 2020-10-14 18:14:31 |
Other Links: | branch diff | manifest | tags |
2020-10-14
| ||
18:54 | Implement: account delete, limiting account changes if it's used in closed years check-in: 38f005c1b7 user: bohwaz tags: dev | |
18:14 | Implement: add account to chart check-in: 6d7d326267 user: bohwaz tags: dev | |
17:09 | Implement: edition of accounts in charts check-in: 48540772ec user: bohwaz tags: dev | |
Modified src/include/lib/Garradin/Accounting/Accounts.php from [0e6b03fee6] to [da4f7ed4c6].
︙ | ︙ | |||
79 80 81 82 83 84 85 | } $out = []; $query = $this->em->iterate('SELECT * FROM @TABLE WHERE id_chart = ? AND type != 0 ' . $types . ' ORDER BY type, code COLLATE NOCASE;', $this->chart_id); foreach ($query as $row) { | > > | | | | | | > > > > > > > > > > > > > > > > > > > > > > | 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 | } $out = []; $query = $this->em->iterate('SELECT * FROM @TABLE WHERE id_chart = ? AND type != 0 ' . $types . ' ORDER BY type, code COLLATE NOCASE;', $this->chart_id); foreach ($query as $row) { if (!isset($out[$row->type])) { $out[$row->type] = (object) [ 'label' => Account::TYPES_NAMES[$row->type], 'type' => $row->type, 'accounts' => [], ]; } $out[$row->type]->accounts[] = $row; } return $out; } public function getNextCodesForTypes(): array { $db = DB::getInstance(); $codes = $db->getAssoc(sprintf('SELECT type, MAX(code) FROM %s WHERE id_chart = ? AND type > 0 GROUP BY type;', Account::TABLE), $this->chart_id); foreach ($codes as &$code) { if (($letter = substr($code, -1)) && !is_numeric($letter)) { $code = substr($code, 0, -1); $letter = strtoupper($letter); $letter = ($letter == 'Z') ? 'AA' : chr(ord($letter)+1); } else { $letter = 'A'; } $code = $code . $letter; } unset($code); return $codes; } } |
Modified src/include/lib/Garradin/Accounting/Reports.php from [d01896f10b] to [11a0817a06].
︙ | ︙ | |||
52 53 54 55 56 57 58 | Account::LIABILITY => [], 'sums' => [ Account::ASSET => 0, Account::LIABILITY => 0, ], ]; | | | | 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 | Account::LIABILITY => [], 'sums' => [ Account::ASSET => 0, Account::LIABILITY => 0, ], ]; $position_criteria = ['position' => [Account::ASSET, Account::LIABILITY, Account::ASSET_OR_LIABILITY]]; $list = self::getClosingSumsWithAccounts($criterias + $position_criteria); foreach ($list as $row) { if ($row->sum == 0) { // Ignore empty accounts continue; } $sum = $row->sum; $row->sum = abs($row->sum); if ($row->position == Account::ASSET_OR_LIABILITY) { if ($sum < 0) { $out[Account::ASSET][] = $row; } else { $out[Account::LIABILITY][] = $row; } } |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Accounting/Account.php from [035f1d0b3a] to [b8cd267cfd].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php namespace Garradin\Entities\Accounting; use DateTimeInterface; use Garradin\Entity; use Garradin\DB; use Garradin\Utils; use Garradin\UserException; class Account extends Entity { const TABLE = 'acc_accounts'; // Actif const ASSET = 1; // Passif const LIABILITY = 2; // Passif ou actif | > | | 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 | <?php namespace Garradin\Entities\Accounting; use DateTimeInterface; use Garradin\Entity; use Garradin\DB; use Garradin\Utils; use Garradin\UserException; use Garradin\ValidationException; class Account extends Entity { const TABLE = 'acc_accounts'; // Actif const ASSET = 1; // Passif const LIABILITY = 2; // Passif ou actif const ASSET_OR_LIABILITY = 3; // Produit const REVENUE = 4; // Charge const EXPENSE = 5; |
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 99 100 101 102 103 | protected $_form_rules = [ 'code' => 'required|string|alpha_num|max:10', 'label' => 'required|string|max:200', 'description' => 'string|max:2000', 'position' => 'required|numeric|min:0', 'type' => 'required|numeric|min:0', ]; public function getJournal(int $year_id) { $db = DB::getInstance(); $sql = 'SELECT l.debit, l.credit, t.id, t.date, t.reference, l.reference AS line_reference, t.label, l.label AS line_label, l.reconciled FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction | > > > > > > > > > > > > > > | 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 | protected $_form_rules = [ 'code' => 'required|string|alpha_num|max:10', 'label' => 'required|string|max:200', 'description' => 'string|max:2000', 'position' => 'required|numeric|min:0', 'type' => 'required|numeric|min:0', ]; public function selfCheck(): void { $db = DB::getInstance(); $where = 'code = ?'; $where .= $this->exists() ? sprintf(' AND id != %d', $this->id()) : ''; if ($db->test(self::TABLE, $where, $this->code)) { throw new ValidationException('Ce code est déjà utilisé par un autre compte.'); } parent::selfCheck(); } public function getJournal(int $year_id) { $db = DB::getInstance(); $sql = 'SELECT l.debit, l.credit, t.id, t.date, t.reference, l.reference AS line_reference, t.label, l.label AS line_label, l.reconciled FROM acc_transactions_lines l INNER JOIN acc_transactions t ON t.id = l.id_transaction |
︙ | ︙ | |||
154 155 156 157 158 159 160 | { return (int) DB::getInstance()->firstColumn('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 < ? ORDER BY t.date, t.id;', $this->id(), $year_id, $date->format('Y-m-d')); } | | > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | { return (int) DB::getInstance()->firstColumn('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 < ? ORDER BY t.date, t.id;', $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) { $source = $_POST; } if (empty($source['type'])) { throw new UserException('Le type est obligatoire dans ce formulaire'); } $type = (int) $source['type']; if (array_key_exists($type, $translate_type_position)) { $source['position'] = $translate_type_position[$type]; } else { $source['position'] = self::ASSET_OR_LIABILITY; } if (array_key_exists($type, $translate_type_codes)) { $source['code'] = $translate_type_codes[$type]; } $this->importForm($source); } } |
Modified src/include/lib/Garradin/Template.php from [ad5ed56bcb] to [338bc036fa].
︙ | ︙ | |||
190 191 192 193 194 195 196 | if (!isset($name, $type)) { throw new \InvalidArgumentException('Missing name or type'); } $current_value = null; $current_value_from_user = false; | < < < | | 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | if (!isset($name, $type)) { throw new \InvalidArgumentException('Missing name or type'); } $current_value = null; $current_value_from_user = false; if (isset($_POST[$name])) { $current_value = $_POST[$name]; $current_value_from_user = true; } elseif (isset($default)) { $current_value = $default; } elseif (isset($source) && is_object($source) && isset($source->$name)) { |
︙ | ︙ |
Added src/templates/acc/charts/accounts/_account_form.tpl version [042fa20c8d].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <dl> {input type="select" label="Type de compte favori" name="type" source=$account required=true options=$types} <dd class="help">Le statut de compte favori est utilisé pour les écritures <em>« simplifiées »</em> (recettes, dépenses, dettes, créances, virements), pour la liste des comptes, et également pour proposer certaines fonctionnalités (rapprochement pour les comptes bancaires, règlement rapide de dette et créance, dépôt de chèques).</dd> <dd class="help">Un compte qui n'a pas de type favori ne pourra être utilisé que dans une saisie avancée, et ne sera visible que dans les rapports de l'exercice.</dd> {if !$simple} <dt><label for="f_position_0">Position au bilan ou résultat</label> <b>(obligatoire)</b></dt> <dd class="help">La position permet d'indiquer dans quelle partie du bilan ou du résultat doit figurer le compte.</dd> <dd class="help">Les comptes inscrits en actif ou passif figureront dans le bilan, alors que ceux inscrits en produit ou charge figureront au compte de résultat.</dd> {input type="radio" label="Ne pas utiliser ce compte au bilan ni au résultat" name="position" value=0 source=$account} {input type="radio" label="Bilan : actif" name="position" value=1 source=$account help="ce que possède l'association : stocks, locaux, soldes bancaires, etc."} {input type="radio" label="Bilan : passif" name="position" value=2 source=$account help="ce que l'association doit : dettes, provisions, réserves, etc."} {input type="radio" label="Bilan : actif ou passif" name="position" value=3 source=$account help="le compte sera placé à l'actif si son solde est débiteur, ou au passif s'il est créditeur"} {input type="radio" label="Résultat : produit" name="position" value=4 source=$account help="recettes"} {input type="radio" label="Résultat : charge" name="position" value=5 source=$account help="dépenses"} {input type="text" label="Code" maxlength="10" name="code" source=$account required=true help="Le code du compte sert à trier le compte dans le plan comptable, attention à choisir un code qui correspond au plan comptable."} {/if} {input type="text" label="Libellé" name="label" source=$account required=true} {input type="textarea" label="Description" name="description" source=$account} </dl> {if !$simple && isset($translate_type_position, $translate_type_codes)} <script type="text/javascript"> var types_positions = {$translate_type_position|escape:json}; var types_codes = {$translate_type_codes|escape:json}; {literal} $('#f_type').onchange = () => { var v = $('#f_type').value; if (v in types_positions) { $('#f_position_' + types_positions[v]).checked = true; } else { $('#f_position_3').checked = true; } var code = $('#f_code'); if (types_codes[v]) { code.value = types_codes[v]; } else { code.value = ''; } }; {/literal} </script> {/if} |
Modified src/templates/acc/charts/accounts/_nav.tpl from [2dfbae9554] to [3da276707e].
1 2 3 4 5 6 7 8 9 10 | <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/charts/">Plans comptables</a></li> <li><a href="{$admin_url}acc/charts/import.php">Importer un plan comptable</a></li> </ul> <ul class="sub"> <li><strong>{$chart.label} :</strong></li> <li{if $current == 'favorites'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/?id={$chart.id}">Comptes favoris</a></li> <li{if $current == 'all'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/all.php?id={$chart.id}">Tous les comptes</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <nav class="tabs"> <ul> <li class="current"><a href="{$admin_url}acc/charts/">Plans comptables</a></li> <li><a href="{$admin_url}acc/charts/import.php">Importer un plan comptable</a></li> </ul> <ul class="sub"> <li><strong>{$chart.label} :</strong></li> <li{if $current == 'favorites'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/?id={$chart.id}">Comptes favoris</a></li> <li{if $current == 'all'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/all.php?id={$chart.id}">Tous les comptes</a></li> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} <li{if $current == 'add'} class="current"{/if}><a href="{$admin_url}acc/charts/accounts/new.php?id={$chart.id}"><strong>Ajouter un compte</strong></a></li> {/if} </ul> </nav> |
Modified src/templates/acc/charts/accounts/edit.tpl from [3c53ed4ef4] to [ce7d466486].
1 2 3 4 5 6 7 8 | {include file="admin/_head.tpl" title="Modifier un compte" current="acc/charts" js=1} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Modifier un compte</legend> | < < < < | < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | {include file="admin/_head.tpl" title="Modifier un compte" current="acc/charts" js=1} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Modifier un compte</legend> {include file="acc/charts/accounts/_account_form.tpl" simple=false} </fieldset> <p class="submit"> {csrf_field key="acc_accounts_edit_%s"|args:$account.id} <input type="submit" name="edit" value="Enregistrer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Modified src/templates/acc/charts/accounts/index.tpl from [472c3bf003] to [3bde12849f].
1 2 3 4 5 | {include file="admin/_head.tpl" title="Comptes favoris" current="acc/charts"} {include file="acc/charts/accounts/_nav.tpl" current="favorites"} <table class="list"> | | > | > > > > | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | {include file="admin/_head.tpl" title="Comptes favoris" current="acc/charts"} {include file="acc/charts/accounts/_nav.tpl" current="favorites"} <table class="list"> {foreach from=$accounts_grouped item="group"} <tbody> <tr> <td colspan="3"><h2 class="ruler">{$group.label}</h2></td> <td class="actions"> {linkbutton label="Ajouter un compte" shape="plus" href="acc/charts/accounts/new.php?id=%d&type=%d"|args:$chart.id,$group.type} </td> </tr> {foreach from=$group.accounts item="account"} <tr> <td class="num">{$account.code}</td> <th>{$account.label}</th> <td class="desc">{$account.description}</td> <td class="actions"> {if $session->canAccess('compta', Membres::DROIT_ADMIN)} {linkbutton shape="edit" label="Modifier" href="acc/charts/accounts/edit.php?id=%d"|args:$account.id} |
︙ | ︙ |
Added src/templates/acc/charts/accounts/new.tpl version [4f55ecb5c3].
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | {include file="admin/_head.tpl" title="Nouveau compte" current="acc/charts" js=1} {form_errors} <form method="post" action="{$self_url}"> <fieldset> <legend>Créer un nouveau compte</legend> {include file="acc/charts/accounts/_account_form.tpl" simple=$simple} </fieldset> <p class="submit"> {csrf_field key="acc_accounts_new"} <input type="submit" name="save" value="Créer →" /> </p> </form> {include file="admin/_foot.tpl"} |
Added src/www/admin/acc/charts/accounts/new.php version [a766140b57].
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | <?php namespace Garradin; use Garradin\Entities\Accounting\Account; use Garradin\Accounting\Accounts; use Garradin\Accounting\Charts; require_once __DIR__ . '/../../_inc.php'; $session->requireAccess('compta', Membres::DROIT_ADMIN); $chart = Charts::get((int)qg('id')); if (!$chart) { throw new UserException('Ce plan comptable n\'existe pas'); } $account = new Account; $account->position = Account::ASSET_OR_LIABILITY; $types = $account::TYPES_NAMES; $types[0] = '-- Pas un compte favori'; $translate_type_position = [ Account::TYPE_REVENUE => Account::REVENUE, Account::TYPE_EXPENSE => Account::EXPENSE, ]; $translate_type_codes = $chart->accounts()->getNextCodesForTypes(); $simple = false; // Simple creation with pre-determined account type if ($type = (int)qg('type')) { $account->type = $type; $simple = true; $types = array_slice($types, 1, null, true); } if (f('save') && $form->check('acc_accounts_new')) { try { if ($simple) { $account->importSimpleForm($translate_type_position, $translate_type_codes); } else { $account->importForm(); } $account->id_chart = $chart->id(); $account->user = 1; $account->save(); $page = ''; if (!$account->type) { $page = 'all.php'; } Utils::redirect(sprintf('%sacc/charts/accounts/%s?id=%d', ADMIN_URL, $page, $account->id_chart)); } catch (UserException $e) { $form->addError($e->getMessage()); } } $tpl->assign(compact('simple', 'types', 'account', 'translate_type_position', 'translate_type_codes')); $tpl->display('acc/charts/accounts/new.tpl'); |
Added src/www/admin/static/font/garradin.woff2 version [285f8b1099].
cannot compute difference between binary files