Overview
Comment: | Assign automatically a type to a transaction if it was not specified in the CSV file |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk | stable |
Files: | files | file ages | folders |
SHA3-256: |
5f33bded63dbe6a959ac707594eff37b |
User & Date: | bohwaz on 2022-09-02 01:17:19 |
Other Links: | manifest | tags |
Context
2022-09-02
| ||
01:29 | Fix default date when paying a debt was not formatted properly, fix [cc92d787154af38440ecfcc93a8b68815f406699] check-in: b1e7b09974 user: bohwaz tags: trunk, stable | |
01:17 | Assign automatically a type to a transaction if it was not specified in the CSV file check-in: 5f33bded63 user: bohwaz tags: trunk, stable | |
2022-08-28
| ||
14:24 | Fix: don't mark as invalid links to the homepage check-in: f25e3a6716 user: bohwaz tags: trunk, stable | |
Changes
Modified src/include/lib/Garradin/Accounting/Import.php from [119c7ad9c6] to [f47afbfa9c].
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 | <?php namespace Garradin\Accounting; use Garradin\Entities\Accounting\Line; use Garradin\Entities\Accounting\Transaction; use Garradin\Entities\Accounting\Year; use Garradin\CSV_Custom; use Garradin\DB; use Garradin\UserException; class Import { /** * Imports a CSV file of transactions in a year * @param string $type Type of CSV format * @param Year $year Target year where transactions should be updated or created * @param CSV_Custom $csv CSV object * @param int $user_id Current user ID, the one running the import * @param array $options array of options * @return ?array */ static public function import(string $type, Year $year, CSV_Custom $csv, int $user_id, array $options = []): ?array { $options_default = [ 'ignore_ids' => false, 'dry_run' => false, 'return_report' => false, ]; $o = (object) array_merge($options_default, $options); if ($type != Export::GROUPED && $type != Export::SIMPLE && $type != Export::FEC) { throw new \InvalidArgumentException('Invalid type value'); } if ($year->closed) { throw new \InvalidArgumentException('Closed year'); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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\Accounting; use Garradin\Entities\Accounting\Line; use Garradin\Entities\Accounting\Transaction; use Garradin\Entities\Accounting\Year; use Garradin\CSV_Custom; use Garradin\DB; use Garradin\UserException; class Import { static protected function saveImportedTransaction(Transaction $transaction, bool $dry_run = false, array &$report = null): void { if ($transaction->countLines() > 2) { $transaction->type = Transaction::TYPE_ADVANCED; } // Try to magically find out what kind of transaction this is elseif (!isset($transaction->type)) { $transaction->type = $transaction->findTypeFromAccounts(); } if (!$dry_run) { if ($transaction->isModified()) { $transaction->save(); } } else { $transaction->selfCheck(); } if (null !== $report) { if (!$transaction->isModified()) { $target = 'unchanged'; } elseif ($transaction->exists()) { $target = 'modified'; } else { $target = 'created'; } $report[$target][] = $transaction->asJournalArray(); } } /** * Imports a CSV file of transactions in a year * @param string $type Type of CSV format * @param Year $year Target year where transactions should be updated or created * @param CSV_Custom $csv CSV object * @param int $user_id Current user ID, the one running the import * @param array $options array of options * @return ?array */ static public function import(string $type, Year $year, CSV_Custom $csv, int $user_id, array $options = []): ?array { $options_default = [ 'ignore_ids' => false, 'dry_run' => false, 'return_report' => false, ]; $o = (object) array_merge($options_default, $options); $dry_run = $o->dry_run; if ($type != Export::GROUPED && $type != Export::SIMPLE && $type != Export::FEC) { throw new \InvalidArgumentException('Invalid type value'); } if ($year->closed) { throw new \InvalidArgumentException('Closed year'); |
︙ | ︙ | |||
48 49 50 51 52 53 54 | if ($o->return_report) { $report = ['created' => [], 'modified' => [], 'unchanged' => []]; } else { $report = null; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | if ($o->return_report) { $report = ['created' => [], 'modified' => [], 'unchanged' => []]; } else { $report = null; } $l = 1; try { $current_id = null; foreach ($csv->iterate() as $l => $row) { $row = (object) $row; |
︙ | ︙ | |||
101 102 103 104 105 106 107 | && empty($row->date) && empty($row->notes) && empty($row->reference) ); // New transaction, save previous one if (null !== $transaction && $has_transaction) { | > | > | < < < < | 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 132 133 134 135 136 | && empty($row->date) && empty($row->notes) && empty($row->reference) ); // New transaction, save previous one if (null !== $transaction && $has_transaction) { self::saveImportedTransaction($transaction, $dry_run, $report); $transaction = null; } if (!$has_transaction && null === $transaction) { throw new UserException('cette ligne n\'est reliée à aucune écriture'); } } else { if (!empty($row->id) && $row->id != $current_id) { if (null !== $transaction) { self::saveImportedTransaction($transaction, $dry_run, $report); $transaction = null; } $current_id = (int) $row->id; } } // Find or create transaction if (null === $transaction) { if (!empty($row->id) && !$o->ignore_ids) { $transaction = Transactions::get((int)$row->id); |
︙ | ︙ | |||
147 148 149 150 151 152 153 | } else { $transaction = new Transaction; $transaction->id_creator = $user_id; $transaction->id_year = $year->id(); } | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | } else { $transaction = new Transaction; $transaction->id_creator = $user_id; $transaction->id_year = $year->id(); } if (isset($row->type) && !isset($types[$row->type])) { throw new UserException(sprintf('le type "%s" est inconnu', $row->type)); } // FEC does not define type, so don't change it if (isset($row->type)) { $transaction->type = $types[$row->type]; } |
︙ | ︙ | |||
223 224 225 226 227 228 229 | 'debit' => $row->amount, 'id_account' => $debit_account, ]); $transaction->addLine($l1); $transaction->addLine($l2); | | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | 'debit' => $row->amount, 'id_account' => $debit_account, ]); $transaction->addLine($l1); $transaction->addLine($l2); self::saveImportedTransaction($transaction, $dry_run, $report); $transaction = null; } else { $id_account = $accounts->getIdFromCode($row->account); if (!$id_account) { throw new UserException(sprintf('le compte "%s" n\'existe pas dans le plan comptable', $row->account)); |
︙ | ︙ | |||
249 250 251 252 253 254 255 | $line = new Line; $line->importForm($data); $transaction->addLine($line); } } if (null !== $transaction) { | > | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | $line = new Line; $line->importForm($data); $transaction->addLine($line); } } if (null !== $transaction) { self::saveImportedTransaction($transaction, $dry_run, $report); $transaction = null; } } catch (UserException $e) { $db->rollback(); $e->setMessage(sprintf('Erreur sur la ligne %d : %s', $l - 1, $e->getMessage())); if (null !== $transaction) { |
︙ | ︙ |
Modified src/include/lib/Garradin/Entities/Accounting/Transaction.php from [2ec4d6f85e] to [f348b1e49b].
︙ | ︙ | |||
104 105 106 107 108 109 110 111 112 113 114 115 116 117 | case Account::TYPE_CASH: case Account::TYPE_OUTSTANDING: return self::TYPE_TRANSFER; default: return self::TYPE_ADVANCED; } } public function getLinesWithAccounts(): array { $db = EntityManager::getInstance(Line::class)->DB(); // Merge data from accounts with lines $accounts = []; | > > > > > > > > > > > > > > > > > > > | 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 131 132 133 134 135 136 | case Account::TYPE_CASH: case Account::TYPE_OUTSTANDING: return self::TYPE_TRANSFER; default: return self::TYPE_ADVANCED; } } public function findTypeFromAccounts(): int { if (count($this->getLines()) != 2) { return self::TYPE_ADVANCED; } foreach ($this->getLinesWithAccounts() as $line) { if ($line->account_position == Account::REVENUE && $line->credit) { return self::TYPE_REVENUE; } elseif ($line->account_position == Account::EXPENSE && $line->debit) { return self::TYPE_EXPENSE; } } // Did not find a expense/revenue account: fall back to advanced return self::TYPE_ADVANCED; } public function getLinesWithAccounts(): array { $db = EntityManager::getInstance(Line::class)->DB(); // Merge data from accounts with lines $accounts = []; |
︙ | ︙ |
Modified src/www/admin/acc/years/export.php from [ff77b91d6e] to [f39aed5a9b].
︙ | ︙ | |||
34 35 36 37 38 39 40 | $types = [ Export::FULL => [ 'label' => 'Complet (comptabilité d\'engagement)', 'help' => '(Conseillé pour transfert vers un autre logiciel) Chaque ligne reprend toutes les informations de la ligne et de l\'écriture.', ], Export::GROUPED => [ 'label' => 'Complet groupé', | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | $types = [ Export::FULL => [ 'label' => 'Complet (comptabilité d\'engagement)', 'help' => '(Conseillé pour transfert vers un autre logiciel) Chaque ligne reprend toutes les informations de la ligne et de l\'écriture.', ], Export::GROUPED => [ 'label' => 'Complet groupé', 'help' => 'Les colonnes de l\'écriture ne sont pas répétées pour chaque ligne.', ], Export::SIMPLE => [ 'label' => 'Simplifié (comptabilité de trésorerie)', 'help' => 'Les écritures avancées ne sont pas inclues dans cet export.', ], Export::FEC => [ 'label' => 'FEC (Fichier des Écritures Comptables)', |
︙ | ︙ |