Overview
Comment:Reset charts accounts rules for BE/CH/FR when upgrading
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | next2
Files: files | file ages | folders
SHA3-256: 700e447d2a80357f6e7176e77a0b4bb1611b6fa7b666087c21df1919e3e155db
User & Date: bohwaz on 2022-11-06 21:21:07
Other Links: branch diff | manifest | tags
Context
2022-11-06
22:13
Fix old reference to a2.code in saved searches, merge with trunk check-in: b09ff7318a user: bohwaz tags: next2
21:21
Reset charts accounts rules for BE/CH/FR when upgrading check-in: 700e447d2a user: bohwaz tags: next2
20:03
Do not allow all countries in charts, only allow supported countries, other countries won't have categorization of accounts check-in: f8c8398d30 user: bohwaz tags: next2
Changes

Modified src/include/lib/Garradin/Accounting/Charts.php from [8036c917de] to [49d79e0fab].

35
36
37
38
39
40
41









42
43
44
45
46
47
48
		if (!$chart) {
			return null;
		}

		$chart->importCSV($file, true);
		return $chart;
	}










	static public function install(string $chart_code): Chart
	{
		if (!array_key_exists($chart_code, self::BUNDLED_CHARTS)) {
			throw new \InvalidArgumentException('Le plan comptable demandé n\'existe pas.');
		}








>
>
>
>
>
>
>
>
>







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
		if (!$chart) {
			return null;
		}

		$chart->importCSV($file, true);
		return $chart;
	}

	static public function resetRules(array $country_list): void
	{
		foreach (self::list() as $c) {
			if (in_array($c->country, $country_list)) {
				$c->resetAccountsRules();
			}
		}
	}

	static public function install(string $chart_code): Chart
	{
		if (!array_key_exists($chart_code, self::BUNDLED_CHARTS)) {
			throw new \InvalidArgumentException('Le plan comptable demandé n\'existe pas.');
		}

Modified src/include/lib/Garradin/Entities/Accounting/Account.php from [e8a30d4e85] to [41601687e7].

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318

		$this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide: ' . $this->type);
		$this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide');

		parent::selfCheck();
	}

	static public function clearCache(): void
	{
		self::$_charts = null;
	}

	protected function getCountry(): ?string
	{
		if (!isset(self::$_charts)) {
			self::$_charts = DB::getInstance()->getGrouped('SELECT id, country, code FROM acc_charts;');
		}

		return self::$_charts[$this->id_chart]->country ?? null;







<
<
<
<
<







300
301
302
303
304
305
306





307
308
309
310
311
312
313

		$this->assert(array_key_exists($this->type, self::TYPES_NAMES), 'Type invalide: ' . $this->type);
		$this->assert(array_key_exists($this->position, self::POSITIONS_NAMES), 'Position invalide');

		parent::selfCheck();
	}






	protected function getCountry(): ?string
	{
		if (!isset(self::$_charts)) {
			self::$_charts = DB::getInstance()->getGrouped('SELECT id, country, code FROM acc_charts;');
		}

		return self::$_charts[$this->id_chart]->country ?? null;
327
328
329
330
331
332
333

334


335
336
337
338
339
340
341
	/**
	 * This sets the account position according to local rules
	 * if the chart is linked to a country, but only
	 * if the account is user-created, or if the chart is non-official
	 */
	protected function getLocalPosition(string $country = null): ?int
	{

		$country ??= $this->getCountry();


		$is_official = $this->isChartOfficial();

		if (!$country) {
			return null;
		}

		// Do not change position of official chart accounts







>
|
>
>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
	/**
	 * This sets the account position according to local rules
	 * if the chart is linked to a country, but only
	 * if the account is user-created, or if the chart is non-official
	 */
	protected function getLocalPosition(string $country = null): ?int
	{
		if (!func_num_args()) {
			$country = $this->getCountry();
		}

		$is_official = $this->isChartOfficial();

		if (!$country) {
			return null;
		}

		// Do not change position of official chart accounts
357
358
359
360
361
362
363

364

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380

381


382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399

400

401
402
403
404
405
406
407
		}

		return null;
	}

	protected function getLocalType(string $country = null): int
	{

		$country ??= $this->getCountry();


		if (!$country) {
			return self::TYPE_NONE;
		}

		foreach (self::LOCAL_TYPES[$country] as $type => $number) {
			if ($this->matchType($type, $country)) {
				return $type;
			}
		}

		return self::TYPE_NONE;
	}

	protected function matchType(int $type, string $country = null): bool
	{

		$country ??= $this->getCountry();


		$pattern = self::LOCAL_TYPES[$country][$type] ?? null;

		if (!$pattern) {
			return false;
		}

		if (in_array($type, self::COMMON_TYPES)) {
			$pattern = sprintf('/^%s.+/', $pattern);
		}
		else {
			$pattern = sprintf('/^%s$/', $pattern);
		}

		return (bool) preg_match($pattern, $this->code);
	}

	public function setLocalRules(string $country = null): void
	{

		$country ??= $this->getCountry();


		if (!$country) {
			$this->set('type', 0);
			return;
		}

		$this->set('type', $this->getLocalType($country));







>
|
>
















>
|
>
>


















>
|
>







355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
		}

		return null;
	}

	protected function getLocalType(string $country = null): int
	{
		if (!func_num_args()) {
			$country = $this->getCountry();
		}

		if (!$country) {
			return self::TYPE_NONE;
		}

		foreach (self::LOCAL_TYPES[$country] as $type => $number) {
			if ($this->matchType($type, $country)) {
				return $type;
			}
		}

		return self::TYPE_NONE;
	}

	protected function matchType(int $type, string $country = null): bool
	{
		if (func_num_args() < 2) {
			$country = $this->getCountry();
		}

		$pattern = self::LOCAL_TYPES[$country][$type] ?? null;

		if (!$pattern) {
			return false;
		}

		if (in_array($type, self::COMMON_TYPES)) {
			$pattern = sprintf('/^%s.+/', $pattern);
		}
		else {
			$pattern = sprintf('/^%s$/', $pattern);
		}

		return (bool) preg_match($pattern, $this->code);
	}

	public function setLocalRules(string $country = null): void
	{
		if (!func_num_args()) {
			$country = $this->getCountry();
		}

		if (!$country) {
			$this->set('type', 0);
			return;
		}

		$this->set('type', $this->getLocalType($country));
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
			return;
		}

		if (!isset(self::LOCAL_TYPES[$country][$this->type])) {
			return;
		}

		$this->assert($this->matchType($this->type), sprintf('Le numéro des comptes de type "%s" doit commencer par "%s" (%s).', self::TYPES_NAMES[$this->type], self::LOCAL_TYPES[$country][$this->type], $this->code));
	}

	public function getNewNumberAvailable(?string $base = null): ?string
	{
		$base ??= $this->getNumberBase();

		if (!$base) {







|







428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
			return;
		}

		if (!isset(self::LOCAL_TYPES[$country][$this->type])) {
			return;
		}

		$this->assert($this->matchType($this->type), sprintf('Compte "%s - %s" : le numéro des comptes de type "%s" doit commencer par "%s" (%s).', $this->code, $this->label, self::TYPES_NAMES[$this->type], self::LOCAL_TYPES[$country][$this->type], $this->code));
	}

	public function getNewNumberAvailable(?string $base = null): ?string
	{
		$base ??= $this->getNumberBase();

		if (!$base) {

Modified src/include/lib/Garradin/Entities/Accounting/Chart.php from [7222c3cdf2] to [de81e6181b].

139
140
141
142
143
144
145



















146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
		foreach ($res as $row) {
			$row->position = Account::POSITIONS_NAMES[$row->position];
			$row->user = $row->user ? 'Ajouté' : '';
			$row->bookmark = $row->bookmark ? 'Favori' : '';
			yield $row;
		}
	}




















	public function save(bool $selfcheck = true): bool
	{
		$country_modified = $this->isModified('country');
		$exists = $this->exists();

		$ok = parent::save($selfcheck);

		// Change account types
		if ($ok && $exists && $country_modified) {
			$db = DB::getInstance();
			$db->begin();

			foreach ($this->accounts()->listAll() as $account) {
				$account->setLocalRules($this->country);
				$account->save();
			}

			$db->commit();
		}

		return $ok;
	}

}







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










<
<
|
<
<
<
<
<
<






139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174


175






176
177
178
179
180
181
		foreach ($res as $row) {
			$row->position = Account::POSITIONS_NAMES[$row->position];
			$row->user = $row->user ? 'Ajouté' : '';
			$row->bookmark = $row->bookmark ? 'Favori' : '';
			yield $row;
		}
	}

	public function resetAccountsRules(): void
	{
		$db = DB::getInstance();
		$db->begin();

		try {
			foreach ($this->accounts()->listAll() as $account) {
				$account->setLocalRules($this->country);
				$account->save();
			}
		}
		catch (UserException $e) {
			$db->rollback();
			throw $e;
		}

		$db->commit();
	}

	public function save(bool $selfcheck = true): bool
	{
		$country_modified = $this->isModified('country');
		$exists = $this->exists();

		$ok = parent::save($selfcheck);

		// Change account types
		if ($ok && $exists && $country_modified) {


			$this->resetAccountsRules();






		}

		return $ok;
	}

}

Modified src/include/lib/Garradin/Upgrade.php from [eb254539b9] to [3a8a3894c5].

481
482
483
484
485
486
487

488
489
490
491
492
493
494
				Charts::updateInstalled('be_pcmn_2019');
				$db->commitSchemaUpdate();
			}

			if (version_compare($v, '1.2.1', '<')) {
				$db->beginSchemaUpdate();
				$db->import(ROOT . '/include/migrations/1.2/1.2.1.sql');

				$db->commitSchemaUpdate();
			}

			// Vérification de la cohérence des clés étrangères
			$db->foreignKeyCheck();

			// Delete local cached files







>







481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
				Charts::updateInstalled('be_pcmn_2019');
				$db->commitSchemaUpdate();
			}

			if (version_compare($v, '1.2.1', '<')) {
				$db->beginSchemaUpdate();
				$db->import(ROOT . '/include/migrations/1.2/1.2.1.sql');
				Charts::resetRules(['FR', 'CH', 'BE']);
				$db->commitSchemaUpdate();
			}

			// Vérification de la cohérence des clés étrangères
			$db->foreignKeyCheck();

			// Delete local cached files

Modified src/include/migrations/1.2/1.2.1.sql from [1654148dee] to [c785ad23ee].

1
2
3
4
5


6






7
8

9
10


11
ALTER TABLE acc_charts RENAME TO acc_charts_old;

.read schema.sql

INSERT INTO acc_charts SELECT * FROM acc_charts_old;


UPDATE acc_charts SET country = 'FR' WHERE code IN ('PCA_2018', 'PCA_1999');






UPDATE acc_charts SET country = NULL WHERE country NOT IN ('FR', 'BE');


UPDATE acc_accounts SET type = 0 WHERE id_chart IN (SELECT id FROM acc_charts WHERE country IS NULL);



DROP TABLE acc_charts_old;





>
>
|
>
>
>
>
>
>
|

>


>
>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ALTER TABLE acc_charts RENAME TO acc_charts_old;

.read schema.sql

INSERT INTO acc_charts SELECT * FROM acc_charts_old;

-- Reset country if code was official, changing the country should not have been possible
UPDATE acc_charts SET country = 'FR' WHERE code IS NOT NULL AND code != 'PCMN_2019';
UPDATE acc_charts SET country = 'BE' WHERE code IS NOT NULL AND code = 'PCMN_2019';

-- Reset country to FR for countries using something similar
UPDATE acc_charts SET country = 'FR' WHERE country IN ('GN', 'TN', 'RE', 'CN', 'PF', 'MW', 'CI', 'GP', 'GA', 'DE', 'NC');

-- Set country to NULL if outside of supported countries
UPDATE acc_charts SET country = NULL WHERE country NOT IN ('FR', 'BE', 'CH');

-- Reset type to zero if not supported
UPDATE acc_accounts SET type = 0 WHERE id_chart IN (SELECT id FROM acc_charts WHERE country IS NULL);

-- Reset other charts in PHP code

DROP TABLE acc_charts_old;

Modified src/www/admin/acc/charts/accounts/index.php from [9349ac07de] to [61b1caaf37].

14
15
16
17
18
19
20




21
22
23
24
25
26
	$year = $current_year;
	$chart = $year->chart();
}

if (!$chart) {
	throw new UserException('Aucun plan comptable spécifié');
}





$accounts = $chart->accounts();

$tpl->assign(compact('chart'));
$tpl->assign('accounts_grouped', $accounts->listCommonGrouped($types, true));
$tpl->display('acc/charts/accounts/index.tpl');







>
>
>
>






14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
	$year = $current_year;
	$chart = $year->chart();
}

if (!$chart) {
	throw new UserException('Aucun plan comptable spécifié');
}

if (!$chart->country) {
	Utils::redirect('!acc/charts/accounts/all.php?id=' . $chart->id);
}

$accounts = $chart->accounts();

$tpl->assign(compact('chart'));
$tpl->assign('accounts_grouped', $accounts->listCommonGrouped($types, true));
$tpl->display('acc/charts/accounts/index.tpl');

Modified src/www/admin/acc/charts/accounts/new.php from [37b5fca96c] to [3ed04e0b88].

33
34
35
36
37
38
39



40
41
42
43
44
45
46
// Simple creation with pre-determined account type
if ($type !== null) {
	$account->type = (int)$type;
}
elseif (isset($types) && is_array($types) && count($types) == 1) {
	$account->type = (int)current($types);
}




$csrf_key = 'account_new';

$form->runIf('toggle_bookmark', function () use ($accounts, $chart) {
	$a = $accounts->get(f('toggle_bookmark'));
	$a->bookmark = true;
	$a->save();







>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Simple creation with pre-determined account type
if ($type !== null) {
	$account->type = (int)$type;
}
elseif (isset($types) && is_array($types) && count($types) == 1) {
	$account->type = (int)current($types);
}
elseif (!$chart->country) {
	$account->type = $account::TYPE_NONE;
}

$csrf_key = 'account_new';

$form->runIf('toggle_bookmark', function () use ($accounts, $chart) {
	$a = $accounts->get(f('toggle_bookmark'));
	$a->bookmark = true;
	$a->save();