Overview
Comment:Import / export de plan comptable au format JSON, à partir du patch envoyé par @adresse
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | stable
Files: files | file ages | folders
SHA1: 9f18af1dbe2e1db17b2fd6ea9880a7ba87358290
User & Date: bohwaz on 2019-05-26 13:40:57
Other Links: manifest | tags
Context
2019-05-26
13:46
Rétablir sous-menu caisse / chèque à encaisser etc. dans la liste de compte, signalé par @zou check-in: 3e77f40dd7 user: bohwaz tags: trunk, stable
13:40
Import / export de plan comptable au format JSON, à partir du patch envoyé par @adresse check-in: 9f18af1dbe user: bohwaz tags: trunk, stable
2019-05-24
09:32
Correction : affichage du champ membre de type date au format français check-in: 1694c75ab2 user: bohwaz tags: trunk, stable
Changes

Modified src/include/lib/Garradin/Compta/Comptes.php from [8786b38bca] to [9bf36bdeef].

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
    const CARTE_A_ENCAISSER = '5115';

    const PASSIF = 0x01;
    const ACTIF = 0x02;
    const PRODUIT = 0x04;
    const CHARGE = 0x08;











    public function importPlan()
    {








        $plan = json_decode(file_get_contents(\Garradin\ROOT . '/include/data/plan_comptable.json'));






        $db = DB::getInstance();
        $db->begin();
        $ids = [];

        foreach ($plan as $id=>$compte)
        {
            $ids[] = $id;

            if ($db->test('compta_comptes', $db->where('id', $id)))
            {
                $db->update('compta_comptes', [
                    'parent'    =>  $compte->parent,
                    'libelle'   =>  $compte->nom,
                    'position'  =>  $compte->position,
                    'plan_comptable' => 1,

                ], $db->where('id', $id));
            }
            else
            {
                $db->insert('compta_comptes', [
                    'id'        =>  $id,
                    'parent'    =>  $compte->parent,
                    'libelle'   =>  $compte->nom,
                    'position'  =>  $compte->position,
                    'plan_comptable' => 1,

                ]);
            }
        }

        // Supprime les comptes qui étaient dans l'ancien plan comptable
        // mais pas dans le nouveau










        $db->delete('compta_comptes', $db->where('id', 'NOT IN', $ids) . ' AND ' . $db->where('plan_comptable', 1));


        $db->commit();





























        return true;
    }

    public function add($data)
    {
        $this->_checkFields($data, true);








>
>
>
>
>
>
>
>
>
>
|

>
>
>
>
>
>
>
>
|
>
>
>
>
>















|
>









|
>




|
|
>
>
>
>
>
>
>
>
>
>
|
|
>


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







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
    const CARTE_A_ENCAISSER = '5115';

    const PASSIF = 0x01;
    const ACTIF = 0x02;
    const PRODUIT = 0x04;
    const CHARGE = 0x08;

    /**
     * Importe un plan comptable
     * @param  string $source_file Chemin du fichier à importer.
     * @param  boolean $delete_all True active la suppression des tous les anciens comptes (peu importe plan_comptable)
     * @return boolean/array Retourne un array des comptes non-supprimés avec leur raison, s'il y en a. Sinon true.
     *
     * Accepte 0 ou 1 argument : soit un chemin, soit true.
     * Sans arguments : importe le plan par défaut et ne supprime que les comptes
     * plus présent appartenants au plan d'origine (WHERE plan_comptable = 1)
     */
    public function importPlan($source_file = null, $delete_all = false)
    {
        $reset = false;

        if(null == $source_file)
        {
            $reset = true;
            $source_file = \Garradin\ROOT . '/include/data/plan_comptable.json';
        }

        $plan = json_decode(file_get_contents($source_file));

        if(is_null($plan))
        {
            throw new UserException('Le fichier n\'est pas du JSON ou n\'a pas pu être décodé.');
        }

        $db = DB::getInstance();
        $db->begin();
        $ids = [];

        foreach ($plan as $id=>$compte)
        {
            $ids[] = $id;

            if ($db->test('compta_comptes', $db->where('id', $id)))
            {
                $db->update('compta_comptes', [
                    'parent'    =>  $compte->parent,
                    'libelle'   =>  $compte->nom,
                    'position'  =>  $compte->position,
                    'plan_comptable' => $reset || !empty($compte->plan_comptable) ? 1 : 0,
                    'desactive' => !empty($compte->desactive) ? 1 : 0,
                ], $db->where('id', $id));
            }
            else
            {
                $db->insert('compta_comptes', [
                    'id'        =>  $id,
                    'parent'    =>  $compte->parent,
                    'libelle'   =>  $compte->nom,
                    'position'  =>  $compte->position,
                    'plan_comptable' => $reset || !empty($compte->plan_comptable) ? 1 : 0,
                    'desactive' => !empty($compte->desactive) ? 1 : 0,
                ]);
            }
        }

        // Effacer les comptes du plan comptable s'ils ne sont pas utilisés ailleurs
        // et qu'ils ne sont pas dans le nouveau plan comptable qu'on vient d'importer
        $sql = 'DELETE FROM compta_comptes WHERE id NOT IN (
            SELECT id FROM compta_comptes_bancaires
            UNION SELECT compte_credit FROM compta_journal
            UNION SELECT compte_debit FROM compta_journal
            UNION SELECT id FROM compta_categories)
            AND '. $db->where('id', 'NOT IN', $ids);

        // Si on ne fait qu'importer une mise à jour du plan comptable,
        // ne supprimer que les comptes qui n'ont pas été créés par l'usager
        if (!$delete_all) {
            $sql .= ' AND ' . $db->where('plan_comptable', 1);
        }

        $db->commit();

        return true;
    }

    public function exportPlan()
    {
        $name = 'plan_comptable';

        header('Content-type: application/json');
        header(sprintf('Content-Disposition: attachment; filename="%s.json"', $name));

        $liste = $this->listTree(0, true);

        $export = [];

        foreach ($liste as $k => $v)
        {
            $export[$v->id] = [
                'code'           => $v->id,
                'nom'            => $v->libelle,
                'parent'         => $v->parent,
                'position'       => $v->position,
                'plan_comptable' => $v->plan_comptable,
                'desactive'      => $v->desactive,
            ];
        }

        file_put_contents('php://output', json_encode($export, JSON_PRETTY_PRINT));

        return true;
    }

    public function add($data)
    {
        $this->_checkFields($data, true);

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
            $parent = false;
            $id = $new_id;

            // Vérification que c'est bien le bon parent !
            // Sinon risque par exemple d'avoir parent = 5 et id = 512A !
            while (!$parent && strlen($id))
            {
            	// On enlève un caractère à la fin jusqu'à trouver un compte parent
            	$id = substr($id, 0, -1);
            	$parent = $db->firstColumn('SELECT id FROM compta_comptes WHERE id = ?;', $id);
            }

            if (!$parent || $parent != $data['parent'])
            {
            	throw new UserException('Le compte parent sélectionné est incorrect, par exemple pour créer un compte 512A il faut sélectionner 512 comme compte parent.');
            }
        }

        // Vérification que le compte n'existe pas déjà
        if ($db->test('compta_comptes', 'id = ?', $new_id))
        {
        	throw new UserException('Ce numéro de compte existe déjà dans le plan comptable : ' . $new_id);
        }

        if (isset($data['position']))
        {
            $position = (int) $data['position'];
        }
        else







|
|
|




|






|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
            $parent = false;
            $id = $new_id;

            // Vérification que c'est bien le bon parent !
            // Sinon risque par exemple d'avoir parent = 5 et id = 512A !
            while (!$parent && strlen($id))
            {
                // On enlève un caractère à la fin jusqu'à trouver un compte parent
                $id = substr($id, 0, -1);
                $parent = $db->firstColumn('SELECT id FROM compta_comptes WHERE id = ?;', $id);
            }

            if (!$parent || $parent != $data['parent'])
            {
                throw new UserException('Le compte parent sélectionné est incorrect, par exemple pour créer un compte 512A il faut sélectionner 512 comme compte parent.');
            }
        }

        // Vérification que le compte n'existe pas déjà
        if ($db->test('compta_comptes', 'id = ?', $new_id))
        {
            throw new UserException('Ce numéro de compte existe déjà dans le plan comptable : ' . $new_id);
        }

        if (isset($data['position']))
        {
            $position = (int) $data['position'];
        }
        else

Added src/templates/admin/compta/comptes/classe.tpl version [45939485c2].































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
{include file="admin/_head.tpl" title=$classe_compte.libelle current="compta/categories"}

<ul class="actions">
    <li><a href="{$admin_url}compta/comptes/">Liste des classes</a></li>
    <li><a href="{$admin_url}compta/comptes/ajouter.php?classe={$classe}">Ajouter un compte dans cette classe</a></li>
</ul>

<p class="help">
    Les comptes avec la mention <em>*</em> font partie du plan comptable standard
    et ne peuvent être modifiés ou supprimés.
</p>

{if !empty($liste)}
    <table class="list accountList">
    {foreach from=$liste item="compte"}
        <tr class="niveau_{$compte.id|strlen}">
            <th>{$compte.id}</th>
            <td class="libelle">{$compte.libelle}</td>
            <td>
                {if !empty($compte.desactive)}
                    <em>Désactivé</em>
                {else}
                    {$compte.position|get_position}
                {/if}
            </td>
            <td class="actions">
                {if empty($compte.desactive)}
                    {if !$compte.plan_comptable}
                        <a class="icn" href="{$admin_url}compta/comptes/modifier.php?id={$compte.id}" title="Modifier">✎</a>
                        <a class="icn" href="{$admin_url}compta/comptes/supprimer.php?id={$compte.id}" title="Supprimer">✘</a>
                    {else}
                        <em>*</em>
                    {/if}
                {/if}
            </td>
        </tr>
    {/foreach}
    </table>

{else}
    <p class="alert">
        Aucun compte trouvé.
    </p>
{/if}


{include file="admin/_foot.tpl"}

Added src/templates/admin/compta/comptes/import.tpl version [99c4dfd495].

























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
{include file="admin/_head.tpl" title="Plan comptable" current="compta/categories"}

<ul class="actions">
	<li><a href="{$admin_url}compta/comptes/">Plan comptable</a></li>
	<li class="current"><a href="?import">Import / remise à zéro</a></li>
	<li><a href="?export=plan">Exporter le plan en format JSON</a></li>
</ul>

{form_errors}

{if $confirm}
<p class="confirm">
	{if $confirm == 'import'}L'import s'est correctement déroulé.
	{elseif $confirm == 'reset'}Le plan comptable a bien été remis à zéro.{/if}
</p>
{/if}

<form method="post" action="{$self_url}" enctype="multipart/form-data">

	<fieldset>
		<legend>Importer un plan comptable</legend>
		<p class="help">
			Toute modification actuelle du plan comptable sera perdue.<br />
			Les comptes associés à des écritures ou des comptes bancaires ne seront pas supprimés.
		</p>
		<dl>
			<dt><label for="f_file">Fichier à importer</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
			<dd><input type="file" name="upload" id="f_file" required="required" /></dd>
			<dt><label for="f_type">Format de fichier</label> <b title="(Champ obligatoire)">obligatoire</b></dt>
			<dd>
				<input type="radio" name="format" id="f_format_json" value="json" {*form_field name="format" checked="json"*} checked="checked" />
				<label for="f_format_json">Plan comptable au format JSON de plan comptable Garradin</label>
			</dd>
		</dl>

		<p class="submit">
			{csrf_field key="plan_import"}
			<input type="submit" name="import" value="Importer &rarr;" />
		</p>
	</fieldset>

</form>

<form method="post" action="{$self_url}">

	<fieldset>
		<legend>Remise à zéro du plan comptable</legend>
		<p class="help">
			Permet de rétablir le plan comptable par défaut de Garradin.<br />
			Vos modifications personnelles seront perdues, assurez-vous d'en avoir une copie avant en cas de problèmes (bouton «&nbsp;Exporter le plan&nbsp;»).
		</p>

		<p class="submit">
			{csrf_field key="plan_reset"}
			<input type="submit" name="reset" value="Rétablir le plan comptable &rarr;" />
		</p>

	</fieldset>

</form>

Modified src/templates/admin/compta/comptes/index.tpl from [452d349397] to [4936874101].

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
{if empty($classe)}
    {include file="admin/_head.tpl" title="Comptes" current="compta/categories"}
    <ul class="accountList">
    {foreach from=$classes item="_classe"}
        <li><h4><a href="{$admin_url}compta/comptes/?classe={$_classe.id}">{$_classe.libelle}</a></h4></li>
    {/foreach}
    </ul>
{else}
    {include file="admin/_head.tpl" title=$classe_compte.libelle current="compta/categories"}

    <ul class="actions">
        <li><a href="{$admin_url}compta/comptes/">Liste des classes</a></li>
        <li><a href="{$admin_url}compta/comptes/ajouter.php?classe={$classe}">Ajouter un compte dans cette classe</a></li>

    </ul>

    <p class="help">
        Les comptes avec la mention <em>*</em> font partie du plan comptable standard
        et ne peuvent être modifiés ou supprimés.
    </p>

    {if !empty($liste)}
        <table class="list accountList">
        {foreach from=$liste item="compte"}
            <tr class="niveau_{$compte.id|strlen}">
                <th>{$compte.id}</th>
                <td class="libelle">{$compte.libelle}</td>
                <td>
                    {if !empty($compte.desactive)}
                        <em>Désactivé</em>
                    {else}
                        {$compte.position|get_position}
                    {/if}
                </td>
                <td class="actions">
                    {if empty($compte.desactive)}
                        {if !$compte.plan_comptable}
                            <a class="icn" href="{$admin_url}compta/comptes/modifier.php?id={$compte.id}" title="Modifier">✎</a>
                            <a class="icn" href="{$admin_url}compta/comptes/supprimer.php?id={$compte.id}" title="Supprimer">✘</a>
                        {else}
                            <em>*</em>
                        {/if}
                    {/if}
                </td>
            </tr>
        {/foreach}
        </table>

    {else}
        <p class="alert">
            Aucun compte trouvé.
        </p>
    {/if}
{/if}

{include file="admin/_foot.tpl"}
<
|
<
<
<
<
<
<
<

|
|
|
>
|

|
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
|
<
<
<
<
<
|
<
<



1







2
3
4
5
6
7
8
9






10













11







12





13


14
15

{include file="admin/_head.tpl" title="Plan comptable" current="compta/categories"}








<ul class="actions">
	<li class="current"><a href="{$admin_url}compta/comptes/">Plan comptable</a></li>
	<li><a href="?import">Import / remise à zéro</a></li>
	<li><a href="?export=plan">Exporter le plan en format JSON</a></li>
</ul>

<ul class="accountList">






{foreach from=$classes item="_classe"}













	<li><h4><a href="{$admin_url}compta/comptes/?classe={$_classe.id}">{$_classe.libelle}</a></h4></li>







{/foreach}





</ul>



{include file="admin/_foot.tpl"}

Modified src/www/admin/compta/comptes/index.php from [8422c33bbc] to [7140f6c1ad].

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
<?php
namespace Garradin;

require_once __DIR__ . '/../_inc.php';

$session->requireAccess('compta', Membres::DROIT_ADMIN);






























$classe = (int) qg('classe');

$tpl->assign('classe', $classe);

if (!$classe)
{
    $tpl->assign('classes', $comptes->listTree(0, false));
}
else
{
    $positions = $comptes->getPositions();

    $tpl->assign('classe_compte', $comptes->get($classe));
    $tpl->assign('liste', $comptes->listTree($classe));
}

function tpl_get_position($pos)
{
    global $positions;
    return $positions[$pos];
}

$tpl->register_modifier('get_position', 'Garradin\tpl_get_position');











$tpl->display('admin/compta/comptes/index.tpl');






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







|



|

|
|




|
|




>
>
>
>
>
>
>
>
>
>
|
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
<?php
namespace Garradin;

require_once __DIR__ . '/../_inc.php';

$session->requireAccess('compta', Membres::DROIT_ADMIN);

if (qg('export') == 'plan')
{
	$comptes->exportPlan();
	exit;
}

$tpl->assign('confirm', qg('confirm'));

if (f('import') && $form->check('plan_import', ['upload' => 'file|required', 'format' => 'required|in:json']))
{
	try {
		$comptes->importPlan($_FILES['upload']['tmp_name'], true);
		Utils::redirect(ADMIN_URL . 'compta/comptes/?import&confirm=import');
	}
	catch (UserException $e) {
		$form->addError($e->getMessage());
	}
}
elseif (f('reset') && $form->check('plan_reset'))
{
	try {
		$comptes->importPlan(null, true);
		Utils::redirect(ADMIN_URL . 'compta/comptes/?import&confirm=reset');
	}
	catch (UserException $e) {
		$form->addError($e->getMessage());
	}
}

$classe = (int) qg('classe');

$tpl->assign('classe', $classe);

if (!$classe)
{
	$tpl->assign('classes', $comptes->listTree(0, false));
}
else
{
	$positions = $comptes->getPositions();

	$tpl->assign('classe_compte', $comptes->get($classe));
	$tpl->assign('liste', $comptes->listTree($classe));
}

function tpl_get_position($pos)
{
	global $positions;
	return $positions[$pos];
}

$tpl->register_modifier('get_position', 'Garradin\tpl_get_position');

$template = 'index';

if ($classe) {
	$template = 'classe';
}
elseif (qg('import') !== null) {
	$template = 'import';
	$tpl->assign('confirm', qg('confirm'));
}

$tpl->display(sprintf('admin/compta/comptes/%s.tpl', $template));