Artifact fe9131dd28b6e74b486276d68b1cc264702521f6b53c9708024b4f6f13bcef69:


<?php

namespace Garradin\Entities\Accounting;

use Garradin\CSV;
use Garradin\DB;
use Garradin\Entity;
use Garradin\Utils;
use Garradin\ValidationException;
use Garradin\UserException;
use Garradin\Accounting\Accounts;

use KD2\DB\EntityManager;

class Chart extends Entity
{
	const TABLE = 'acc_charts';

	protected ?int $id;
	protected string $label;
	protected ?string $country = null;
	protected ?string $code;
	protected bool $archived = false;

	const COUNTRY_LIST = [
		'BE' => 'Belgique',
		'FR' => 'France',
		'CH' => 'Suisse',
	];

	const REQUIRED_COLUMNS = ['code', 'label', 'description', 'position', 'bookmark'];

	const COLUMNS = [
		'code' => 'Numéro',
		'label' => 'Libellé',
		'description' => 'Description',
		'position' => 'Position',
		'added' => 'Ajouté',
		'bookmark' => 'Favori',
	];

	public function selfCheck(): void
	{
		$this->assert(trim($this->label) !== '', 'Le libellé ne peut rester vide.');
		$this->assert(strlen($this->label) <= 200, 'Le libellé ne peut faire plus de 200 caractères.');
		$this->assert(null === $this->country || array_key_exists($this->country, self::COUNTRY_LIST), 'Pays inconnu');
		parent::selfCheck();
	}

	public function accounts()
	{
		return new Accounts($this->id());
	}

	public function importForm(array $source = null)
	{
		if (null === $source) {
			$source = $_POST;
		}

		// Don't allow to change country
		if (isset($this->code)) {
			unset($source['country']);
		}

		unset($source['code']);

		return Entity::importForm($source);
	}

	public function canDelete()
	{
		return !DB::getInstance()->firstColumn(sprintf('SELECT 1 FROM %s WHERE id_chart = ? LIMIT 1;', Year::TABLE), $this->id());
	}

	public function importCSV(string $file, bool $update = false): void
	{
		$db = DB::getInstance();
		$positions = array_flip(Account::POSITIONS_NAMES);
		$types = array_flip(Account::TYPES_NAMES);

		$db->begin();

		try {
			foreach (CSV::import($file, self::COLUMNS, self::REQUIRED_COLUMNS) as $line => $row) {
				$account = null;

				if ($update) {
					$account = EntityManager::findOne(Account::class, 'SELECT * FROM @TABLE WHERE code = ? AND id_chart = ?;', $row['code'], $this->id());
				}

				if (!$account) {
					$account = new Account;
					$account->id_chart = $this->id();
				}

				try {
					if (!isset($positions[$row['position']])) {
						throw new ValidationException('Position inconnue : ' . $row['position']);
					}
					// Don't update user-set values
					if ($account->exists()) {
						unset($row['bookmark'], $row['description']);
					}
					else {
						$row['user'] = !empty($row['added']);
						$row['bookmark'] = !empty($row['bookmark']);
					}

					$row['position'] = $positions[$row['position']];

					$account->importForm($row);
					$account->save();
				}
				catch (ValidationException $e) {
					throw new UserException(sprintf('Ligne %d : %s', $line, $e->getMessage()));
				}
			}

			$db->commit();
		}
		catch (\Exception $e) {
			$db->rollback();
			throw $e;
		}
	}


	/**
	 * Return all accounts from current chart
	 */
	public function export(): \Generator
	{
		$res = DB::getInstance()->iterate('SELECT
			code, label, description, position, user, bookmark
			FROM acc_accounts WHERE id_chart = ? ORDER BY code COLLATE NOCASE;',
			$this->id);

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

	public function country_code(): ?string
	{
		if (!$this->code) {
			return null;
		}

		return strtolower($this->country . '_' . $this->code);
	}
}