Overview
Comment:Improve accounting import: display what is being changed in each transaction, modify transaction if lines have been changed
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | stable
Files: files | file ages | folders
SHA3-256: eff3ee76f39d7d0f9746e6b72ea339413515726e90d525ebc97b35d9bdadce95
User & Date: bohwaz on 2022-12-22 01:58:43
Other Links: manifest | tags
Context
2022-12-22
02:05
Fix display of transaction diff check-in: eb9eaaca5a user: bohwaz tags: trunk, stable
01:58
Improve accounting import: display what is being changed in each transaction, modify transaction if lines have been changed check-in: eff3ee76f3 user: bohwaz tags: trunk, stable
01:54
Rename Garradin to Paheko install check-in: 20e5eebb8b user: bohwaz tags: trunk, stable
Changes

Modified src/include/lib/Garradin/Accounting/Export.php from [0e5101bc13] to [ba557923cc].

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

	static protected function iterateExport(int $year_id, string $type): \Generator
	{
		$id_field = Config::getInstance()->get('champ_identite');

		if (self::SIMPLE == $type) {
			$sql =  'SELECT t.id, t.type, t.status, t.label, t.date, t.notes, t.reference,
				l1.reference AS p_reference,
				a1.code AS debit_account,
				a2.code AS credit_account,
				l1.debit AS amount,
				IFNULL(p.code, p.label) AS project,
				GROUP_CONCAT(u.%s) AS linked_users
				FROM acc_transactions t
				INNER JOIN acc_transactions_lines l1 ON l1.id_transaction = t.id AND l1.debit != 0







|







152
153
154
155
156
157
158
159
160
161
162
163
164
165
166

	static protected function iterateExport(int $year_id, string $type): \Generator
	{
		$id_field = Config::getInstance()->get('champ_identite');

		if (self::SIMPLE == $type) {
			$sql =  'SELECT t.id, t.type, t.status, t.label, t.date, t.notes, t.reference,
				IFNULL(l1.reference, l2.reference) AS p_reference,
				a1.code AS debit_account,
				a2.code AS credit_account,
				l1.debit AS amount,
				IFNULL(p.code, p.label) AS project,
				GROUP_CONCAT(u.%s) AS linked_users
				FROM acc_transactions t
				INNER JOIN acc_transactions_lines l1 ON l1.id_transaction = t.id AND l1.debit != 0

Modified src/include/lib/Garradin/Accounting/Import.php from [3a1db78ec0] to [08dbeee140].

1
2
3
4
5
6
7
8
9
10
11
12


13
14
15
16
17
18
19
<?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\Config;
use Garradin\DB;
use Garradin\UserException;



class Import
{
	static protected function saveImportedTransaction(Transaction $transaction, ?array $linked_users, bool $dry_run = false, array &$report = null): void
	{
		static $users = [];
		$found_users = null;













>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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\Config;
use Garradin\DB;
use Garradin\UserException;

use KD2\SimpleDiff;

class Import
{
	static protected function saveImportedTransaction(Transaction $transaction, ?array $linked_users, bool $dry_run = false, array &$report = null): void
	{
		static $users = [];
		$found_users = null;

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
				$sql = sprintf('SELECT %s AS name, id FROM membres WHERE %s;', $db->quoteIdentifier($id_field), $db->where($id_field, $linked_users));

				foreach ($db->iterate($sql) as $row) {
					$found_users[$row->name] = $row->id;
					$users[$row->name] = $row->id;
				}


				$missing = array_diff_key($users, array_flip($linked_users));



				foreach ($missing as $key => $v) {
					$users[$key] = null;
				}
			}

			$found_users = array_filter($found_users);
		}
		elseif (is_array($linked_users) && count($linked_users) == 0) {
			$found_users = [];
		}


		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();
			}

			if (null !== $found_users) {
				$transaction->updateLinkedUsers($found_users);
			}
		}
		else {
			$transaction->selfCheck();
		}

		if (null !== $report) {


			if (!$transaction->isModified() && (null === $found_users || !$transaction->checkLinkedUsersChange($found_users))) {
				$target = 'unchanged';
			}
			elseif ($transaction->exists()) {





				$target = 'modified';
			}










			else {
				$target = 'created';
			}

			$report[$target][] = $transaction->asJournalArray()
				+ ['linked_users' => null !== $found_users ? implode(', ', array_keys($found_users)) : null];
		}
	}

	/**
	 * 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







>
|
>
>
|
<
<








>










|












>
>
|
|

|
>
>
>
>
>

|
>
>
>
>
>
>
>
>
>
>

|


|
<







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
				$sql = sprintf('SELECT %s AS name, id FROM membres WHERE %s;', $db->quoteIdentifier($id_field), $db->where($id_field, $linked_users));

				foreach ($db->iterate($sql) as $row) {
					$found_users[$row->name] = $row->id;
					$users[$row->name] = $row->id;
				}

				// Fill array with NULL for missing user names, so that we won't go fetch them again
				foreach ($linked_users as $name) {
					if (!array_key_exists($name, $users)) {
						$users[$name] = null;
					}


				}
			}

			$found_users = array_filter($found_users);
		}
		elseif (is_array($linked_users) && count($linked_users) == 0) {
			$found_users = [];
		}


		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->diff()) {
				$transaction->save();
			}

			if (null !== $found_users) {
				$transaction->updateLinkedUsers($found_users);
			}
		}
		else {
			$transaction->selfCheck();
		}

		if (null !== $report) {
			$diff = null;

			if (!$transaction->exists()) {
				$target = 'created';
			}
			elseif (($diff = $transaction->diff())
				|| ($linked_users = $transaction->listLinkedUsersAssoc()) && (array_values($linked_users) != array_keys($found_users))) {
				if (!$diff) {
					$diff = [];
				}

				$target = 'modified';

				if (array_values($linked_users) != array_keys($found_users)) {
					$diff['linked_users'] = [
						implode(', ', $linked_users),
						implode(', ', array_keys($found_users))
					];
				}

				$linked_users = implode(', ', $linked_users);
				$diff = compact('diff', 'transaction', 'linked_users');
			}
			else {
				$target = 'unchanged';
			}

			$report[$target][] = $diff ?? array_merge($transaction->asJournalArray(), ['linked_users' => implode(', ', array_keys($found_users))]);

		}
	}

	/**
	 * 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
224
225
226
227
228
229
230
231
232
233



234
235
236
237
238
239
240
								$status |= $k;
							}
						}

						$transaction->status = $status;
					}

					if (isset($row->linked_users)) {
						$linked_users = array_map('trim', explode(',', $row->linked_users));
					}



				}

				$data = [];

				if (!empty($row->project)) {
					$id_project = Projects::getIdFromCodeOrLabel($row->project);








|


>
>
>







244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
								$status |= $k;
							}
						}

						$transaction->status = $status;
					}

					if (isset($row->linked_users) && trim($row->linked_users) !== '') {
						$linked_users = array_map('trim', explode(',', $row->linked_users));
					}
					else {
						$linked_users = [];
					}
				}

				$data = [];

				if (!empty($row->project)) {
					$id_project = Projects::getIdFromCodeOrLabel($row->project);

327
328
329
330
331
332
333

334
335
336
337
		$db->commit();

		if ($report) {
			foreach ($report as $type => $entries) {
				$report[$type . '_count'] = count($entries);
			}
		}


		return $report;
	}
}







>




350
351
352
353
354
355
356
357
358
359
360
361
		$db->commit();

		if ($report) {
			foreach ($report as $type => $entries) {
				$report[$type . '_count'] = count($entries);
			}
		}


		return $report;
	}
}

Modified src/include/lib/Garradin/Accounting/Projects.php from [4cac127cae] to [e7a48e5114].

15
16
17
18
19
20
21


















22
23
24
25
26
27
28
		return EntityManager::findOneById(Project::class, $id);
	}

	static public function getIdFromCodeOrLabel(string $str): ?int
	{
		return DB::getInstance()->firstColumn('SELECT id FROM acc_projects WHERE code = ? OR label = ?;', $str, $str) ?: null;
	}



















	static public function count(): int
	{
		return DB::getInstance()->count(Project::TABLE);
	}

	static public function listAssoc(): array







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
		return EntityManager::findOneById(Project::class, $id);
	}

	static public function getIdFromCodeOrLabel(string $str): ?int
	{
		return DB::getInstance()->firstColumn('SELECT id FROM acc_projects WHERE code = ? OR label = ?;', $str, $str) ?: null;
	}

	static public function getName(?int $id): ?string
	{
		if (!$id) {
			return null;
		}

		static $projects = [];

		if (array_key_exists($id, $projects)) {
			return $projects[$id];
		}

		$p = DB::getInstance()->first('SELECT code, label FROM acc_projects WHERE id = ?;', $id);

		$projects[$id] = $p ? sprintf('%s — %s', $p->code, $p->label) : null;
		return $projects[$id];
	}

	static public function count(): int
	{
		return DB::getInstance()->count(Project::TABLE);
	}

	static public function listAssoc(): array

Modified src/include/lib/Garradin/Entities/Accounting/Transaction.php from [7a0d34d5c9] to [9ae4f0f7e7].

10
11
12
13
14
15
16

17
18
19
20
21
22
23
use Garradin\Utils;
use Garradin\UserException;

use Garradin\Files\Files;
use Garradin\Entities\Files\File;

use Garradin\Accounting\Accounts;

use Garradin\ValidationException;

class Transaction extends Entity
{
	const TABLE = 'acc_transactions';

	const TYPE_ADVANCED = 0;







>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use Garradin\Utils;
use Garradin\UserException;

use Garradin\Files\Files;
use Garradin\Entities\Files\File;

use Garradin\Accounting\Accounts;
use Garradin\Accounting\Projects;
use Garradin\ValidationException;

class Transaction extends Entity
{
	const TABLE = 'acc_transactions';

	const TYPE_ADVANCED = 0;
42
43
44
45
46
47
48









49
50
51
52
53
54
55
		'Avancé',
		'Recette',
		'Dépense',
		'Virement',
		'Dette',
		'Créance',
	];










	protected ?int $id;
	protected ?int $type = null;
	protected int $status = 0;
	protected string $label;
	protected ?string $notes = null;
	protected ?string $reference = null;







>
>
>
>
>
>
>
>
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
		'Avancé',
		'Recette',
		'Dépense',
		'Virement',
		'Dette',
		'Créance',
	];

	const FIELDS_NAMES = [
		'type'      => 'Type',
		'status'    => 'Statut',
		'label'     => 'Libellé',
		'notes'     => 'Notes',
		'reference' => 'Numéro pièce comptable',
		'date'      => 'Date',
	];

	protected ?int $id;
	protected ?int $type = null;
	protected int $status = 0;
	protected string $label;
	protected ?string $notes = null;
	protected ?string $reference = null;
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
		return true;
	}

	public function listLinkedUsers(): array
	{
		$db = EntityManager::getInstance(self::class)->DB();
		$identity_column = Config::getInstance()->get('champ_identite');
		$sql = sprintf('SELECT m.id, m.%s AS identity, l.id_service_user FROM membres m INNER JOIN acc_transactions_users l ON l.id_user = m.id WHERE l.id_transaction = ?;', $identity_column);
		return $db->get($sql, $this->id());
	}

	public function listLinkedUsersAssoc(): array
	{
		$db = EntityManager::getInstance(self::class)->DB();
		$identity_column = Config::getInstance()->get('champ_identite');







|







940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
		return true;
	}

	public function listLinkedUsers(): array
	{
		$db = EntityManager::getInstance(self::class)->DB();
		$identity_column = Config::getInstance()->get('champ_identite');
		$sql = sprintf('SELECT m.id, m.%s AS identity, l.id_service_user FROM membres m INNER JOIN acc_transactions_users l ON l.id_user = m.id WHERE l.id_transaction = ? ORDER BY id;', $identity_column);
		return $db->get($sql, $this->id());
	}

	public function listLinkedUsersAssoc(): array
	{
		$db = EntityManager::getInstance(self::class)->DB();
		$identity_column = Config::getInstance()->get('champ_identite');
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163


1164
1165
1166
1167


1168



1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197










































































































1198
1199
1200
1201
1202
	}

	public function getTypeName(): string
	{
		return self::TYPES_NAMES[$this->type];
	}

	public function asDetailsArray(): array
	{
		$lines = [];



		foreach ($this->getLines() as $i => $line) {
			$lines[$i+1] = $line->asDetailsArray();
		}






		return [
			'Numéro'          => $this->id ?? '--',
			'Type'            => self::TYPES_NAMES[$this->type ?? self::TYPE_ADVANCED],
			'Libellé'         => $this->label ?? null,
			'Date'            => $this->date ?? null,
			'Pièce comptable' => $this->reference ?? null,
			'Remarques'       => $this->notes ?? null,
			'Total crédit'    => Utils::money_format($this->getLinesCreditSum()),
			'Total débit'     => Utils::money_format($this->getLinesDebitSum()),
			'Lignes'          => $lines,
		];
	}

	public function asJournalArray(): array
	{
		$out = $this->asArray();

		if ($this->exists()) {
			$out['url'] = $this->url();
		}

		$out['lines'] = $this->getLinesWithAccounts();
		foreach ($out['lines'] as &$line) {
			unset($line->line);
		}
		unset($line);
		return $out;
	}











































































































	public function url(): string
	{
		return Utils::getLocalURL('!acc/transactions/details.php?id=' . $this->id());
	}
}







|


>
>

|

|
>
>
|
>
>
>

|
|
|
|
|
|
|
|




















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
	}

	public function getTypeName(): string
	{
		return self::TYPES_NAMES[$this->type];
	}

	public function asDetailsArray(bool $modified = false): array
	{
		$lines = [];
		$debit = 0;
		$credit = 0;

		foreach ($this->getLine() as $i => $line) {
			$lines[$i+1] = $line->asDetailsArray();

			$debit += $line->debit;
			$credit +=$line->credit;
		}

		$src = $this->asArray();

		return [
			'Numéro'          => $src['id'] ?? '--',
			'Type'            => self::TYPES_NAMES[$src['type'] ?? self::TYPE_ADVANCED],
			'Libellé'         => $src['label'] ?? null,
			'Date'            => isset($src['date']) ? $src['date']->format('d/m/Y') : null,
			'Pièce comptable' => $src['reference'] ?? null,
			'Remarques'       => $src['notes'] ?? null,
			'Total crédit'    => Utils::money_format($debit),
			'Total débit'     => Utils::money_format($credit),
			'Lignes'          => $lines,
		];
	}

	public function asJournalArray(): array
	{
		$out = $this->asArray();

		if ($this->exists()) {
			$out['url'] = $this->url();
		}

		$out['lines'] = $this->getLinesWithAccounts();
		foreach ($out['lines'] as &$line) {
			unset($line->line);
		}
		unset($line);
		return $out;
	}

	/**
	 * Compare transaction, to see if something has changed
	 */
	public function diff(): ?array
	{
		$out = [
			'transaction' => [],
			'lines' => [],
			'lines_new' => [],
			'lines_removed' => [],
		];

		foreach ($this->_modified as $key => $old) {
			$out['transaction'][self::FIELDS_NAMES[$key]] = [$old, $this->$key];
		}

		static $keys = [
			'id_account' => 'Numéro de compte',
			'label'      => 'Libellé ligne',
			'reference'  => 'Référence ligne',
			'credit'     => 'Crédit',
			'debit'      => 'Débit',
			'id_project' => 'Projet',
		];

		$new_lines = [];
		$old_line = [];

		foreach ($this->getLines() as $line) {
			$new_line = [];

			foreach ($keys as $key => $label) {
				$new_line[$key] = $line->$key;
			}

			$new_lines[] = $new_line;

			if ($line->exists() && $line->isModified()) {
				$old_line = [];

				foreach ($keys as $key => $label) {
					$old_line[$key] = $line->getModifiedProperty($key) ?? $line->$key;
				}

				$old_lines[] = $old_line;
			}
		}

		foreach ($this->_old_lines as $line) {
			$old_line = [];

			foreach ($keys as $key => $label) {
				$old_line[$key] = $line->$key;
			}

			$old_lines[] = $old_line;
		}

		// Append new lines and changed lines
		foreach ($new_lines as $i => $new_line) {
			$found = array_search($new_line, $old_lines);

			if (false === $found) {
				$new_line['account'] = Accounts::getCodeAndLabel($new_line['id_account']);
				$new_line['project'] = Projects::getName($new_line['id_project']);
				$out['lines_new'][] = $new_line;
			}
			/*
			// Currently unused, as we can't really compare lines unless it keeps the same ID
			// And in import we reset the lines
			else {
				$found = $old_lines[$found];
				$out['lines'][$i] = $new_line;
				$out['lines'][$i]['account'] = Accounts::getCodeAndLabel($new_line['id_account']);
				$out['lines'][$i]['diff'] = [];

				foreach ($keys as $key => $label) {
					$value = $new_line[$key];

					if ($found[$key] !== $value) {
						$out['lines'][$i]['diff'][$key] = [$found[$key], $value];
					}
				}

				if (isset($out['lines'][$i]['diff']['id_project'])) {
					$out['lines'][$i]['diff']['project'] = [Projects::getName($out['lines'][$i]['diff']['id_project'][0]), Projects::getName($out['lines'][$i]['diff']['id_project'][1])];
				}
			}*/
		}

		// Append removed lines
		foreach ($old_lines as $i => $old_line) {
			if (!in_array($old_line, $new_lines)) {
				$old_line['account'] = Accounts::getCodeAndLabel($old_line['id_account']);
				$old_line['project'] = Projects::getName($old_line['id_project']);
				$out['lines_removed'][] = $old_line;
			}
		}

		if (!count($out['transaction']) && !count($out['lines']) && !count($out['lines_new']) && !count($out['lines_removed'])) {
			return null;
		}

		return $out;
	}

	public function url(): string
	{
		return Utils::getLocalURL('!acc/transactions/details.php?id=' . $this->id());
	}
}

Modified src/include/lib/Garradin/Template.php from [d6200e98be] to [d965f6db15].

942
943
944
945
946
947
948
949
950



951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
		}

		return $out;
	}

	protected function diff(array $params)
	{
		if (!isset($params['old']) || !isset($params['new']))
		{



			throw new \BadFunctionCallException('Paramètres old et new requis.');
		}

		$old = $params['old'];
		$new = $params['new'];

		$diff = \KD2\SimpleDiff::diff_to_array(false, $old, $new, 3);

		$out = '<table class="diff">';
		$prev = key($diff);

		foreach ($diff as $i=>$line)
		{
			if ($i > $prev + 1)
			{







|
<
>
>
>



<
<
<
<
<







942
943
944
945
946
947
948
949

950
951
952
953
954
955





956
957
958
959
960
961
962
		}

		return $out;
	}

	protected function diff(array $params)
	{
		if (isset($params['old'], $params['new'])) {

			$diff = \KD2\SimpleDiff::diff_to_array(false, $params['old'], $params['new'], $params['context'] ?? 3);
		}
		else {
			throw new \BadFunctionCallException('Paramètres old et new requis.');
		}






		$out = '<table class="diff">';
		$prev = key($diff);

		foreach ($diff as $i=>$line)
		{
			if ($i > $prev + 1)
			{

Modified src/templates/acc/reports/_journal.tpl from [997c31a255] to [174e1e10d7].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<table class="list multi">
	<thead>
		<tr>
			<td class="num">N°</td>
			<td>Pièce comptable</td>
			<td>Date</td>
			<th>Libellé</th>
			{if !empty($with_linked_users)}<td>Membres liés</td>{/if}
			<td>Comptes</td>
			<td class="money">Débit</td>
			<td class="money">Crédit</td>
			<td>Libellé ligne</td>
			<td>Réf. ligne</td>
			{if !empty($action)}<td></td>{/if}
		</tr>







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<table class="list multi">
	<thead>
		<tr>
			<td class="num">N°</td>
			<td>Pièce comptable</td>
			<td>Date</td>
			<th>Libellé</th>
			{if !empty($with_linked_users)}<td>Membres associés</td>{/if}
			<td>Comptes</td>
			<td class="money">Débit</td>
			<td class="money">Crédit</td>
			<td>Libellé ligne</td>
			<td>Réf. ligne</td>
			{if !empty($action)}<td></td>{/if}
		</tr>

Added src/templates/acc/reports/_journal_diff.tpl version [b32218ea5c].







































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<table class="list multi diff">
	<thead>
		<tr>
			<td class="num">N°</td>
			<td>Pièce comptable</td>
			<td>Date</td>
			<th>Libellé</th>
			{if !empty($with_linked_users)}<td>Membres associés</td>{/if}
			<td>Comptes</td>
			<td class="money">Débit</td>
			<td class="money">Crédit</td>
			<td>Libellé ligne</td>
			<td>Réf. ligne</td>
			<td>Projet</td>
		</tr>
	</thead>
	{foreach from=$journal item="t"}
	<?php
	$transaction = $t['transaction'];
	$diff = $t['diff'];
	$lines_count = isset($diff['transaction']) ? count($diff['lines']) + count($diff['lines_removed']) + count($diff['lines_new']) :  count($transaction->getLines());
	?>
	<tbody>
		<tr>
			<td rowspan="{$lines_count}" class="num">{if $transaction.id}<a href="{$admin_url}acc/transactions/details.php?id={$transaction.id}">#{$transaction.id}</a>{/if}</td>
			<td rowspan="{$lines_count}">
				{if $diff.transaction.reference}
					<del>{$diff.transaction.reference[0]}</del>
					<ins>{$diff.transaction.reference[1]}</ins>
				{else}
					{$transaction.reference}
				{/if}
			</td>
			<td rowspan="{$lines_count}">
				{if $diff.transaction.date}
					<del>{$diff.transaction.date[0]|date_short}</del>
					<ins>{$diff.transaction.date[1]|date_short}</ins>
				{else}
					{$transaction.date|date_short}
				{/if}
			</td>
			<th rowspan="{$lines_count}">
				{if $diff.transaction.label}
					<del>{$diff.transaction.label[0]}</del>
					<ins>{$diff.transaction.label[1]}</ins>
				{else}
					{$transaction.label}
				{/if}
			</th>
			<td rowspan="{$lines_count}">
				{if $diff.linked_users}
					<del>{$diff.linked_users[0]}</del>
					<ins>{$diff.linked_users[1]}</ins>
				{else}
					{$t.linked_users}
				{/if}
			</td>
	{if isset($diff['transaction'])}
		{foreach from=$diff.lines_removed item="line"}
			<td><del>{$line.account}</del></td>
			<td class="money"><del>{$line.debit|raw|money}</del></td>
			<td class="money"><del>{$line.credit|raw|money}</del></td>
			<td><del>{$line.label}</del></td>
			<td><del>{$line.reference}</del></td>
			<td><del>{$line.project}</del></td>
		</tr>
		<tr>
		{/foreach}
		{foreach from=$diff.lines_new item="line"}
			<td><ins>{$line.account}</ins></td>
			<td class="money"><ins>{$line.debit|raw|money}</ins></td>
			<td class="money"><ins>{$line.credit|raw|money}</ins></td>
			<td><ins>{$line.label}</ins></td>
			<td><ins>{$line.reference}</ins></td>
			<td><ins>{$line.project}</ins></td>
		</tr>
		<tr>
		{/foreach}
		{* Currently unused as we cannot really compare values of lines *}
		{foreach from=$diff.lines item="line"}
			<td>
				{if $line.diff.account}
					<del>{$line.diff.account[0]}</del>
					<ins>{$line.diff.account[1]}</ins>
				{else}
					{$line.account}
				{/if}
			</td>
			<td class="money">
				{if $line.diff.debit}
					<del>{$line.diff.debit[0]|raw|money:false}</del>
					<ins>{$line.diff.debit[1]|raw|money:false}</ins>
				{else}
					{$line.debit|raw|money}
				{/if}
			</td>
			<td class="money">
				{if $line.diff.credit}
					<del>{$line.diff.credit[0]|raw|money:false}</del>
					<ins>{$line.diff.credit[1]|raw|money:false}</ins>
				{else}
					{$line.credit|raw|money}
				{/if}
			</td>
			<td>
				{if $line.diff.label}
					<del>{$line.diff.label[0]}</del>
					<ins>{$line.diff.label[1]}</ins>
				{else}
					{$line.label}
				{/if}
			</td>
			<td>
				{if $line.diff.reference}
					<del>{$line.diff.reference[0]}</del>
					<ins>{$line.diff.reference[1]}</ins>
				{else}
					{$line.reference}
				{/if}
			</td>
			<td>
				{if $line.diff.project}
					<del>{$line.diff.project[0]}</del>
					<ins>{$line.diff.project[1]}</ins>
				{else}
					{$line.project}
				{/if}
			</td>
		</tr>
		<tr>
		{/foreach}
	{else}
		{foreach from=$transaction->getLinesWithAccounts() item="line"}
			<td>{$line.account_code} - {$line.account_label}</td>
			<td class="money">{$line.debit|raw|money}</td>
			<td class="money">{$line.credit|raw|money}</td>
			<td>{$line.label}</td>
			<td>{$line.reference}</td>
			<td>{$line.project}</td>
		</tr>
		<tr>
		{/foreach}
	{/if}
		</tr>
	</tbody>
	{/foreach}
</table>

Modified src/templates/acc/years/import.tpl from [e143c934c5] to [cfa507cc57].

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

	{if $report.created_count}
	<details>
		<summary>
			<h2>{{%n écriture sera créée}{%n écritures seront créées} n=$report.created_count}</h2>
		</summary>
		<p class="help">Les écritures suivantes mentionnées dans le fichier seront ajoutées.</p>
		{include file="acc/reports/_journal.tpl" journal=$report.created}
	</details>
	{/if}

	{if $report.modified_count}
	<details>
		<summary>
			<h2>{{%n écriture sera modifiée}{%n écritures seront modifiées} n=$report.modified_count}</h2>
		</summary>
		<p class="help">Les écritures suivantes mentionnées dans le fichier seront modifiées.</p>
		{include file="acc/reports/_journal.tpl" journal=$report.modified}
	</details>
	{/if}

	{if $report.unchanged_count}
	<p class="help">

		<strong>{{%n écriture ne sera pas affectée.}{%n écritures ne seront pas affectées.} n=$report.unchanged_count}</strong>



	</div>
	{/if}

	{if !$report.modified_count && !$report.created_count}
	<p class="error block">
		Aucune modification ne serait apportée par ce fichier à importer. Il n'est donc pas possible de terminer l'import.
	</p>
	{else}







|








|
|




|
>
|
>
>
>
|







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

	{if $report.created_count}
	<details>
		<summary>
			<h2>{{%n écriture sera créée}{%n écritures seront créées} n=$report.created_count}</h2>
		</summary>
		<p class="help">Les écritures suivantes mentionnées dans le fichier seront ajoutées.</p>
		{include file="acc/reports/_journal.tpl" journal=$report.created with_linked_users=true}
	</details>
	{/if}

	{if $report.modified_count}
	<details>
		<summary>
			<h2>{{%n écriture sera modifiée}{%n écritures seront modifiées} n=$report.modified_count}</h2>
		</summary>
		<p class="help">Les écritures suivantes mentionnées dans le fichier seront modifiées.<br />En rouge ce qui sera supprimé, en vert ce qui sera ajouté.</p>
		{include file="acc/reports/_journal_diff.tpl" journal=$report.modified}
	</details>
	{/if}

	{if $report.unchanged_count}
	<details>
		<summary>
			<h3>{{%n écriture ne sera pas affectée.}{%n écritures ne seront pas affectées.} n=$report.unchanged_count}</h3>
		</summary>
		<p class="help">Les écritures suivantes mentionnées dans le fichier <strong>ne seront pas modifiées</strong>.</p>
		{include file="acc/reports/_journal.tpl" journal=$report.unchanged with_linked_users=true}
	</details>
	{/if}

	{if !$report.modified_count && !$report.created_count}
	<p class="error block">
		Aucune modification ne serait apportée par ce fichier à importer. Il n'est donc pas possible de terminer l'import.
	</p>
	{else}

Modified src/www/admin/static/styles/02-common.css from [f91819bb0d] to [ad55fd3c96].

545
546
547
548
549
550
551



}

.search-results .breadcrumbs {
    margin: 0;
    font-size: .9em;
    margin-bottom: .8em;
}










>
>
>
545
546
547
548
549
550
551
552
553
554
}

.search-results .breadcrumbs {
    margin: 0;
    font-size: .9em;
    margin-bottom: .8em;
}

.diff ins { background: #cfc; color: #000; text-decoration: none; }
.diff del { background: #fcc; color: #000; }

Modified src/www/admin/static/styles/wiki.css from [8d582848fc] to [36110b4a17].

55
56
57
58
59
60
61

62
63
64
65
66
67
68
    border-top: 0.1em solid var(--gLightBorderColor);
    clear: both;
}

form#f_upload fieldset {
    position: relative;
}


.diff {
    margin: 1em;
}

.diff .ins {diff
    background: #cfc;







>







55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    border-top: 0.1em solid var(--gLightBorderColor);
    clear: both;
}

form#f_upload fieldset {
    position: relative;
}


.diff {
    margin: 1em;
}

.diff .ins {diff
    background: #cfc;
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
}

.diff .leftChange, .diff .rightChange {
    text-align: center;
    vertical-align: middle;
}

.diff ins { background: #9f9; }
.diff del { background: #f99; }

.diff hr {
    background: none;
    border: none;
    border-top: 5px dotted #fff;
    color: #fff;
    margin: .2em .4em;







<
<







85
86
87
88
89
90
91


92
93
94
95
96
97
98
}

.diff .leftChange, .diff .rightChange {
    text-align: center;
    vertical-align: middle;
}




.diff hr {
    background: none;
    border: none;
    border-top: 5px dotted #fff;
    color: #fff;
    margin: .2em .4em;