Overview
Comment:Make sure either both id_year and id_account are null, or both of them are filled
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA1: 5ffcc013353aff22b0b2facf36eda0e99ae9131f
User & Date: bohwaz on 2020-11-07 16:48:46
Other Links: branch diff | manifest | tags
Context
2020-11-07
17:01
Saving a service for a user is working \o/ check-in: c4ed8acc1d user: bohwaz tags: dev
16:48
Make sure either both id_year and id_account are null, or both of them are filled check-in: 5ffcc01335 user: bohwaz tags: dev
16:39
Set 'Escape' key to close any iframe dialog check-in: 232c3fc135 user: bohwaz tags: dev
Changes

Modified src/include/data/1.0.0_schema.sql from [22b57213e7] to [d082661890].

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    label TEXT NOT NULL,
    description TEXT NULL,

    amount INTEGER NULL,
    formula TEXT NULL, -- Formule de calcul du montant de la cotisation, si cotisation dynamique (exemple : membres.revenu_imposable * 0.01)

    id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
    id_account INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL, -- NULL si le type n'est pas associé automatiquement à la compta
    id_year INTEGER NULL REFERENCES acc_years (id) ON DELETE SET NULL -- NULL si le type n'est pas associé automatiquement à la compta
);

CREATE TABLE IF NOT EXISTS services_users
-- Enregistrement des cotisations et activités
(
    id INTEGER NOT NULL PRIMARY KEY,







|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    label TEXT NOT NULL,
    description TEXT NULL,

    amount INTEGER NULL,
    formula TEXT NULL, -- Formule de calcul du montant de la cotisation, si cotisation dynamique (exemple : membres.revenu_imposable * 0.01)

    id_service INTEGER NOT NULL REFERENCES services (id) ON DELETE CASCADE,
    id_account INTEGER NULL REFERENCES acc_accounts (id) ON DELETE SET NULL CHECK (id_account IS NULL OR id_year IS NOT NULL), -- NULL si le type n'est pas associé automatiquement à la compta
    id_year INTEGER NULL REFERENCES acc_years (id) ON DELETE SET NULL -- NULL si le type n'est pas associé automatiquement à la compta
);

CREATE TABLE IF NOT EXISTS services_users
-- Enregistrement des cotisations et activités
(
    id INTEGER NOT NULL PRIMARY KEY,

Modified src/include/lib/Garradin/Entities/Services/Fee.php from [fbf5342292] to [5e1f69acfa].

5
6
7
8
9
10
11

12
13
14
15
16
17
18
..
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
use Garradin\Config;
use Garradin\DB;
use Garradin\DynamicList;
use Garradin\Entity;
use Garradin\ValidationException;
use Garradin\Utils;
use Garradin\Entities\Accounting\Account;

use KD2\DB\EntityManager;

class Fee extends Entity
{
	const TABLE = 'services_fees';

	protected $id;
................................................................................
			elseif ($source['amount_type'] == 1) {
				$source['formula'] = null;
			}
			else {
				$source['amount'] = $source['formula'] = null;
			}
		}





		return parent::importForm($source);
	}

	public function selfCheck(): void
	{
		$db = DB::getInstance();
................................................................................
		parent::selfCheck();

		$this->assert(trim($this->label) !== '', 'Le libellé doit être renseigné');
		$this->assert(strlen($this->label) <= 200, 'Le libellé doit faire moins de 200 caractères');
		$this->assert(strlen($this->description) <= 2000, 'La description doit faire moins de 2000 caractères');
		$this->assert(null === $this->amount || $this->amount > 0, 'Le montant est invalide');
		$this->assert($this->id_service, 'Aucun service n\'a été indiqué pour ce tarif.');


		$this->assert(null === $this->id_account || $db->test(Account::TABLE, 'id = ?', $this->id_account), 'Le compte du plan comptable indiqué n\'existe pas');

		$this->assert(null === $this->formula || $this->checkFormula(), 'Formule de calcul invalide');
		$this->assert(null === $this->amount || null === $this->formula, 'Il n\'est pas possible de spécifier à la fois une formule et un montant');
	}

	public function getAmountForUser(int $user_id): ?int
	{
		if ($this->amount) {







>







 







>
>
>
>







 







>
>
|
>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
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
use Garradin\Config;
use Garradin\DB;
use Garradin\DynamicList;
use Garradin\Entity;
use Garradin\ValidationException;
use Garradin\Utils;
use Garradin\Entities\Accounting\Account;
use Garradin\Entities\Accounting\Year;
use KD2\DB\EntityManager;

class Fee extends Entity
{
	const TABLE = 'services_fees';

	protected $id;
................................................................................
			elseif ($source['amount_type'] == 1) {
				$source['formula'] = null;
			}
			else {
				$source['amount'] = $source['formula'] = null;
			}
		}

		if (empty($source['accounting'])) {
			$source['id_account'] = $source['id_year'] = null;
		}

		return parent::importForm($source);
	}

	public function selfCheck(): void
	{
		$db = DB::getInstance();
................................................................................
		parent::selfCheck();

		$this->assert(trim($this->label) !== '', 'Le libellé doit être renseigné');
		$this->assert(strlen($this->label) <= 200, 'Le libellé doit faire moins de 200 caractères');
		$this->assert(strlen($this->description) <= 2000, 'La description doit faire moins de 2000 caractères');
		$this->assert(null === $this->amount || $this->amount > 0, 'Le montant est invalide');
		$this->assert($this->id_service, 'Aucun service n\'a été indiqué pour ce tarif.');
		$this->assert((null === $this->id_account && null === $this->id_year)
			|| (null !== $this->id_account && null !== $this->id_year), 'Le compte doit être indiqué avec l\'exercice');
		$this->assert(null === $this->id_account || $db->test(Account::TABLE, 'id = ?', $this->id_account), 'Le compte indiqué n\'existe pas');
		$this->assert(null === $this->id_year || $db->test(Year::TABLE, 'id = ?', $this->id_year), 'L\'exercice indiqué n\'existe pas');
		$this->assert(null === $this->formula || $this->checkFormula(), 'Formule de calcul invalide');
		$this->assert(null === $this->amount || null === $this->formula, 'Il n\'est pas possible de spécifier à la fois une formule et un montant');
	}

	public function getAmountForUser(int $user_id): ?int
	{
		if ($this->amount) {

Modified src/include/lib/Garradin/Entities/Services/Service_User.php from [72624605bd] to [acc90e2331].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42
..
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
..
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

<?php

namespace Garradin\Entities\Services;

use Garradin\Config;
use Garradin\DynamicList;
use Garradin\Entity;
use Garradin\ValidationException;
use Garradin\Utils;
use Garradin\Services\Services;
use Garradin\Entities\Accounting\Transaction;

class Service_User extends Entity
{
	const TABLE = 'services_users';

................................................................................
		'id_fee'      => 'int',
		'id_service'  => 'int',
		'paid'        => 'bool',
		'date'        => 'date',
		'expiry_date' => '?date',
	];

	protected $_service;






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

................................................................................
			if (!$service) {
				throw new \LogicException('The requested service is not found');
			}

			if ($service->duration) {
				$dt = new \DateTime;
				$dt->modify(sprintf('+%d days', $service->duration));
				$this->expiry_date = $dt->format('Y-m-d');
			}
			elseif ($service->end_date) {
				$this->expiry_date = $service->end_date;
			}
			else {
				$this->expiry_date = null;
			}
................................................................................
	{
		if (null === $this->_service) {
			$this->_service = Services::get($this->id_service);
		}

		return $this->_service;
	}










	static public function saveFromForm(int $user_id, ?array $source = null)
	{
		if (null === $source) {
			$source = $_POST;
		}




		$su = new self;

		$su->importForm($source);
		$su->save();

		if ($su->service()->id_account && !empty($source['paid_amount'])) {
			$transaction = new Transaction;
			$transaction->id_user = $user_id;


			$source['type'] = Transaction::TYPE_REVENUE;
			$key = sprintf('account_%d_', $source['type']);
			$source[$key . '0'] = [$su->service()->id_account() => ''];
			$source[$key . '1'] = $source['account'];




			$transaction->importFromNewForm($source);
			$transaction->save();
			$transaction->updateLinkedUsers([$su->id_user]);
		}
	}

}





|
<


|







 







|
>
>
>
>
>







 







|







 







>
>
>
>
>
>
>
>
>







>
>
>

>



|

|
>



|
|
>
>
>



|

|
>
|
>
1
2
3
4
5

6
7
8
9
10
11
12
13
14
15
..
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
..
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
..
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
<?php

namespace Garradin\Entities\Services;

use Garradin\DB;

use Garradin\Entity;
use Garradin\ValidationException;
use Garradin\Services\Fees;
use Garradin\Services\Services;
use Garradin\Entities\Accounting\Transaction;

class Service_User extends Entity
{
	const TABLE = 'services_users';

................................................................................
		'id_fee'      => 'int',
		'id_service'  => 'int',
		'paid'        => 'bool',
		'date'        => 'date',
		'expiry_date' => '?date',
	];

	protected $_service, $_fee;

	public function selfCheck(): void
	{
		$this->assert(!DB::getInstance()->test(self::TABLE, 'id_user = ? AND id_service = ? AND date = ?', $this->id_user, $this->id_service, $this->date->format('Y-m-d')), 'Cette activité a déjà été enregistrée pour ce membre et ce jour');
	}

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

................................................................................
			if (!$service) {
				throw new \LogicException('The requested service is not found');
			}

			if ($service->duration) {
				$dt = new \DateTime;
				$dt->modify(sprintf('+%d days', $service->duration));
				$this->expiry_date = $dt;
			}
			elseif ($service->end_date) {
				$this->expiry_date = $service->end_date;
			}
			else {
				$this->expiry_date = null;
			}
................................................................................
	{
		if (null === $this->_service) {
			$this->_service = Services::get($this->id_service);
		}

		return $this->_service;
	}

	public function fee()
	{
		if (null === $this->_fee) {
			$this->_fee = Fees::get($this->id_fee);
		}

		return $this->_fee;
	}

	static public function saveFromForm(int $user_id, ?array $source = null)
	{
		if (null === $source) {
			$source = $_POST;
		}

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

		$su = new self;
		$su->date = new \DateTime;
		$su->importForm($source);
		$su->save();

		if ($su->fee()->id_account && !empty($source['amount'])) {
			$transaction = new Transaction;
			$transaction->id_creator = $user_id;
			$transaction->id_year = $su->fee()->id_year;

			$source['type'] = Transaction::TYPE_REVENUE;
			$key = sprintf('account_%d_', $source['type']);
			$source[$key . '0'] = [$su->fee()->id_account => ''];
			$source[$key . '1'] = isset($source['account']) ? $source['account'] : null;

			$source['label'] = 'Règlement activité - ' . $su->service()->label . ' - ' . $su->fee()->label;
			$source['date'] = $su->date->format('d/m/Y');

			$transaction->importFromNewForm($source);
			$transaction->save();
			$transaction->linkToUser($su->id_user, $su->id());
		}

		$db->commit();
	}
}

Modified src/include/lib/Garradin/Entity.php from [a75474c4ab] to [32e7c887ca].

44
45
46
47
48
49
50
51











52
53
54
55
		else {
			return parent::filterUserValue($type, $value, $key);
		}
	}

	protected function assert(bool $test, string $message = null): void
	{
		if (null !== $message && !$test) {











			throw new ValidationException($message);
		}
	}
}







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




44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
		else {
			return parent::filterUserValue($type, $value, $key);
		}
	}

	protected function assert(bool $test, string $message = null): void
	{
		if ($test) {
			return;
		}

		if (null === $message) {
			$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
			$caller_class = array_pop($backtrace);
			$caller = array_pop($backtrace);
			$message = sprintf('Entity assertion fail from class %s on line %d', $caller_class['class'], $caller['line']);
			throw new \UnexpectedValueException($message);
		}
		else {
			throw new ValidationException($message);
		}
	}
}

Modified src/include/lib/Garradin/Services/Services.php from [d83ba1ba18] to [89f45ea0ac].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
	static public function listAssoc()
	{
		return DB::getInstance()->getAssoc('SELECT id, label FROM services ORDER BY label COLLATE NOCASE;');
	}

	static public function listGroupedWithFees(?int $user_id = null)
	{
		$services = DB::getInstance()->getGrouped('SELECT id, label, duration, start_date, end_date FROM services;');
		$fees = Fees::listAllByService($user_id);
		$out = [];

		foreach ($fees as $fee) {
			$id = $fee->id_service;

			if (!array_key_exists($id, $out)) {







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
	static public function listAssoc()
	{
		return DB::getInstance()->getAssoc('SELECT id, label FROM services ORDER BY label COLLATE NOCASE;');
	}

	static public function listGroupedWithFees(?int $user_id = null)
	{
		$services = DB::getInstance()->getGrouped('SELECT id, label, duration, start_date, end_date, description FROM services;');
		$fees = Fees::listAllByService($user_id);
		$out = [];

		foreach ($fees as $fee) {
			$id = $fee->id_service;

			if (!array_key_exists($id, $out)) {

Modified src/include/lib/Garradin/Template.php from [99b8464397] to [0dc1ec7995].

260
261
262
263
264
265
266











267
268
269
270
271
272
273
...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
			$attributes['disabled'] = 'disabled';
			unset($attributes['required']);
		}
		else {
			unset($attributes['disabled']);
		}












		$attributes_string = $attributes;

		array_walk($attributes_string, function (&$v, $k) {
			$v = sprintf('%s="%s"', $k, $v);
		});

		$attributes_string = implode(' ', $attributes_string);
................................................................................
			if (isset($help)) {
				$out .= sprintf(' <em class="help">(%s)</em>', $this->escape($help));
			}

			$out .= '</dd>';
		}
		else {
			if (array_key_exists('required', $attributes)) {
				$required_label =  ' <b title="Champ obligatoire">(obligatoire)</b>';
			}
			else {
				$required_label =  ' <i>(facultatif)</i>';
			}

			$out = sprintf('<dt>%s%s</dt><dd>%s</dd>', $label, $required_label, $input);

			if (isset($help)) {
				$out .= sprintf('<dd class="help">%s</dd>', $this->escape($help));
			}
		}








>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<







260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
...
361
362
363
364
365
366
367







368
369
370
371
372
373
374
			$attributes['disabled'] = 'disabled';
			unset($attributes['required']);
		}
		else {
			unset($attributes['disabled']);
		}

		if (array_key_exists('required', $attributes) || array_key_exists('fake_required', $attributes)) {
			$required_label =  ' <b title="Champ obligatoire">(obligatoire)</b>';
		}
		else {
			$required_label =  ' <i>(facultatif)</i>';
		}

		// Fake required: doesn't set the required attribute, just the label
		// (useful for form elements that are hidden by JS)
		unset($attributes['fake_required']);

		$attributes_string = $attributes;

		array_walk($attributes_string, function (&$v, $k) {
			$v = sprintf('%s="%s"', $k, $v);
		});

		$attributes_string = implode(' ', $attributes_string);
................................................................................
			if (isset($help)) {
				$out .= sprintf(' <em class="help">(%s)</em>', $this->escape($help));
			}

			$out .= '</dd>';
		}
		else {







			$out = sprintf('<dt>%s%s</dt><dd>%s</dd>', $label, $required_label, $input);

			if (isset($help)) {
				$out .= sprintf('<dd class="help">%s</dd>', $this->escape($help));
			}
		}

Modified src/include/lib/Garradin/Utils.php from [86a1d2932c] to [e1571e929f].

129
130
131
132
133
134
135


136
137
138
139
140
141
142
        return $value;
    }

    static public function money_format($number, string $dec_point = ',', string $thousands_sep = ' ', $zero_if_empty = true): string {
        if ($number == 0) {
            return $zero_if_empty ? '0' : '0,00';
        }



        $decimals = substr($number, -2);
        $number = (int) substr($number, 0, -2);

        return sprintf('%s%s%s', number_format($number, 0, $dec_point, $thousands_sep), $dec_point, $decimals);
    }








>
>







129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
        return $value;
    }

    static public function money_format($number, string $dec_point = ',', string $thousands_sep = ' ', $zero_if_empty = true): string {
        if ($number == 0) {
            return $zero_if_empty ? '0' : '0,00';
        }

        $number = (int) $number;

        $decimals = substr($number, -2);
        $number = (int) substr($number, 0, -2);

        return sprintf('%s%s%s', number_format($number, 0, $dec_point, $thousands_sep), $dec_point, $decimals);
    }

Modified src/templates/acc/charts/accounts/delete.tpl from [9400f6a9aa] to [245366acb6].

1
2
3
4
5
6
7
8
9
10
{include file="admin/_head.tpl" title="Supprimer un compte" current="acc/charts"}

{include file="common/delete_form.tpl"
	legend="Supprimer ce plan comptable ?"
	warning="Êtes-vous sûr de vouloir supprimer le compte « %s — %s » ?"|args:$account.code,$account.label
	alert="Attention, le compte ne pourra pas être supprimé si des opérations y sont affectées."
	csrf_key="acc_accounts_delete_%s"|args:$account.id
}

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





|




1
2
3
4
5
6
7
8
9
10
{include file="admin/_head.tpl" title="Supprimer un compte" current="acc/charts"}

{include file="common/delete_form.tpl"
	legend="Supprimer ce plan comptable ?"
	warning="Êtes-vous sûr de vouloir supprimer le compte « %s — %s » ?"|args:$account.code,$account.label
	alert="Attention, le compte ne pourra pas être supprimé si des écritures y sont affectées."
	csrf_key="acc_accounts_delete_%s"|args:$account.id
}

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

Modified src/templates/acc/charts/accounts/selector.tpl from [82b9c1ab55] to [9e12e5285e].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
110
111
112
113
114
115
116
117
118
119
120
121
122
{include file="admin/_head.tpl" title="Sélectionner un compte" body_id="popup" is_popup=true}

{if $charts}
	<form method="get" action="{$self_url_no_qs}">
		<nav class="acc-year">
			<h4>Plan comptable à utiliser&nbsp;:</h4>
			<dl>{input type="select" name="chart" options=$charts default=$chart.id onchange="this.form.submit();"}</dl>
			<p>
				<input type="hidden" name="targets" value="{$targets}" />
				<input type="hidden" name="chart_choice" value="1" />
				<noscript><input type="submit" value="OK" /></noscript>
			</p>
		</nav>
	</form>
{/if}

{if empty($grouped_accounts) && empty($accounts)}
	<p class="block alert">Le plan comptable ne comporte aucun compte de ce type. Pour afficher des comptes ici, les <a href="{$www_url}admin/acc/charts/accounts/all.php?id={$chart.id}" target="_blank">modifier dans le plan comptable</a> en sélectionnant le type de compte favori voulu.</td>

{elseif isset($grouped_accounts)}

	{foreach from=$grouped_accounts item="group"}
		<h2 class="ruler">{$group.label}</h2>
................................................................................
			}
		});

	};

	q.focus();
}

window.onkeyup = (e) => { if (e.key == 'Escape') window.parent.g.closeDialog(); };
</script>
{/literal}

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


<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







<
<




1
2














3
4
5
6
7
8
9
..
96
97
98
99
100
101
102


103
104
105
106
{include file="admin/_head.tpl" title="Sélectionner un compte" body_id="popup" is_popup=true}















{if empty($grouped_accounts) && empty($accounts)}
	<p class="block alert">Le plan comptable ne comporte aucun compte de ce type. Pour afficher des comptes ici, les <a href="{$www_url}admin/acc/charts/accounts/all.php?id={$chart.id}" target="_blank">modifier dans le plan comptable</a> en sélectionnant le type de compte favori voulu.</td>

{elseif isset($grouped_accounts)}

	{foreach from=$grouped_accounts item="group"}
		<h2 class="ruler">{$group.label}</h2>
................................................................................
			}
		});

	};

	q.focus();
}


</script>
{/literal}

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

Modified src/templates/acc/transactions/details.tpl from [cbf588a6d3] to [0529903ae9].

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
	{if $transaction.id_projet}
		<dt>Projet</dt>
		<dd>
			<a href="{$admin_url}compta/projets/">{$projet.libelle}</a>
		</dd>
	{/if}

	<dt>Opération créée par</dt>
	<dd>
		{if $transaction.id_creator}
			{if $session->canAccess('compta', Membres::DROIT_ACCES)}
				<a href="{$admin_url}membres/fiche.php?id={$transaction.id_creator}">{$creator_name}</a>
			{else}
				{$creator_name}
			{/if}
		{else}
			<em>membre supprimé</em>
		{/if}
	</dd>

	<dt>Opération liée à</dt>
	{if empty($related_users)}
		<dd><em>Aucun membre n'est lié à cette opération.</em></dd>
	{else}
		{foreach from=$related_users item="u"}

			<dd><a href="{$admin_url}membres/fiche.php?id={$u.id}">{$u.identity}</a></dd>


		{/foreach}
	{/if}

	<dt>Remarques</dt>
	<dd>{if trim($transaction.notes)}{$transaction.notes|escape|nl2br}{else}-{/if}</dd>

	<dt>Fichiers joints</dt>







|












|

|


>
|
>
>







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
	{if $transaction.id_projet}
		<dt>Projet</dt>
		<dd>
			<a href="{$admin_url}compta/projets/">{$projet.libelle}</a>
		</dd>
	{/if}

	<dt>Écriture créée par</dt>
	<dd>
		{if $transaction.id_creator}
			{if $session->canAccess('compta', Membres::DROIT_ACCES)}
				<a href="{$admin_url}membres/fiche.php?id={$transaction.id_creator}">{$creator_name}</a>
			{else}
				{$creator_name}
			{/if}
		{else}
			<em>membre supprimé</em>
		{/if}
	</dd>

	<dt>Écriture liée à</dt>
	{if empty($related_users)}
		<dd><em>Aucun membre n'est lié à cette écriture.</em></dd>
	{else}
		{foreach from=$related_users item="u"}
			<dd>
				<a href="{$admin_url}membres/fiche.php?id={$u.id}">{$u.identity}</a>
				{if $u.id_service_user}— en règlement d'une <a href="{$admin_url}services/user.php?id={$u.id}&amp;only={$u.id_service_user}">activité</a>{/if}
			</dd>
		{/foreach}
	{/if}

	<dt>Remarques</dt>
	<dd>{if trim($transaction.notes)}{$transaction.notes|escape|nl2br}{else}-{/if}</dd>

	<dt>Fichiers joints</dt>

Modified src/templates/acc/years/delete.tpl from [bec58a78c5] to [2dd3f2267d].

1
2
3
4
5
6
7
8
9
10
{include file="admin/_head.tpl" title="Supprimer un exercice" current="acc/years"}

{include file="common/delete_form.tpl"
	legend="Supprimer cet exercice ?"
	warning="Êtes-vous sûr de vouloir supprimer l'exercice « %s » ?"|args:$year.label
	alert="Attention, l'exercice ne pourra pas être supprimé si des opérations y sont toujours affectées."
	csrf_key="acc_years_delete_%s"|args:$year.id
}

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





|




1
2
3
4
5
6
7
8
9
10
{include file="admin/_head.tpl" title="Supprimer un exercice" current="acc/years"}

{include file="common/delete_form.tpl"
	legend="Supprimer cet exercice ?"
	warning="Êtes-vous sûr de vouloir supprimer l'exercice « %s » ?"|args:$year.label
	alert="Attention, l'exercice ne pourra pas être supprimé si des écritures y sont toujours affectées."
	csrf_key="acc_years_delete_%s"|args:$year.id
}

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

Modified src/templates/admin/config/donnees/reset.tpl from [19ac60768c] to [c696026876].

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{/if}

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

<fieldset>
    <legend>Remise à zéro</legend>
	<p class="block error">
		Attention : toutes les données seront effacées&nbsp;! Ceci inclut les membres, les opérations comptables, les pages du wiki, etc.
        Seul votre compte membre sera re-créé avec le même email et mot de passe.
	</p>
    <p class="help">
        Une sauvegarde sera automatiquement créée avant de procéder à la remise à zéro.
    </p>
    <dl>
        <dt><label for="f_passe_verif">Votre mot de passe</label> (pour vérification)</dt>







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{/if}

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

<fieldset>
    <legend>Remise à zéro</legend>
	<p class="block error">
		Attention : toutes les données seront effacées&nbsp;! Ceci inclut les membres, les écritures comptables, les pages du wiki, etc.
        Seul votre compte membre sera re-créé avec le même email et mot de passe.
	</p>
    <p class="help">
        Une sauvegarde sera automatiquement créée avant de procéder à la remise à zéro.
    </p>
    <dl>
        <dt><label for="f_passe_verif">Votre mot de passe</label> (pour vérification)</dt>

Modified src/templates/services/fees/_fee_form.tpl from [9dbe61f3f4] to [72c2e336d6].

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
..
51
52
53
54
55
56
57

58
59
60
61
62
63
64
..
65
66
67
68
69
70
71












72
73
74
			{input name="description" type="textarea" label="Description" source=$fee}

			<dt><label for="f_amount_type">Montant de la cotisation</label></dt>
			{input name="amount_type" type="radio" value="0" label="Gratuite ou prix libre" default=$amount_type}
			{input name="amount_type" type="radio" value="1" label="Montant fixe ou prix libre conseillé" default=$amount_type}
			<dd class="amount_type_1">
				<dl>
					{input name="amount" type="money" label="Montant" source=$fee}
				</dl>
			</dd>
			{input name="amount_type" type="radio" value="2" label="Montant variable" default=$amount_type}
			<dd class="amount_type_2">
				<dl>
					{input name="formula" type="textarea" label="Formule de calcul" source=$fee}
					<dd class="help">
						<a href="https://fossil.kd2.org/garradin/wiki?name=Formule_calcul_activit%C3%A9">Aide sur les formules de calcul</a>
					</dd>
				</dl>
			</dd>






			{input type="list" target="acc/charts/accounts/selector.php?targets=%s&chart_choice=1"|args:$targets name="account" label="Enregistrer les règlements dans ce compte du plan comptable" help="Si aucun compte n'est sélectionné, les règlements ne seront pas enregistrés en comptabilité" default=$account}















		</dl>

	</fieldset>

	<p class="submit">
		{csrf_field key=$csrf_key}
		<input type="submit" name="save" value="{$submit_label} &rarr;" />
	</p>

................................................................................
	if (!$('#f_amount_type_1').checked)
		hide.push('.amount_type_1');

	if (!$('#f_amount_type_2').checked)
		hide.push('.amount_type_2');

	g.toggle(hide, false);


	function togglePeriod()
	{
		g.toggle(['.amount_type_1', '.amount_type_2'], false);

		if (this.checked && this.value == 1)
			g.toggle('.amount_type_1', true);
................................................................................
		else if (this.checked && this.value == 2)
			g.toggle('.amount_type_2', true);
	}

	$('#f_amount_type_0').onchange = togglePeriod;
	$('#f_amount_type_1').onchange = togglePeriod;
	$('#f_amount_type_2').onchange = togglePeriod;












})();
{/literal}
</script>







|





|





>
>
>
>
>

<
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>







 







>







 







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



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
..
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
			{input name="description" type="textarea" label="Description" source=$fee}

			<dt><label for="f_amount_type">Montant de la cotisation</label></dt>
			{input name="amount_type" type="radio" value="0" label="Gratuite ou prix libre" default=$amount_type}
			{input name="amount_type" type="radio" value="1" label="Montant fixe ou prix libre conseillé" default=$amount_type}
			<dd class="amount_type_1">
				<dl>
					{input name="amount" type="money" label="Montant" source=$fee fake_required=1}
				</dl>
			</dd>
			{input name="amount_type" type="radio" value="2" label="Montant variable" default=$amount_type}
			<dd class="amount_type_2">
				<dl>
					{input name="formula" type="textarea" label="Formule de calcul" source=$fee fake_required=1}
					<dd class="help">
						<a href="https://fossil.kd2.org/garradin/wiki?name=Formule_calcul_activit%C3%A9">Aide sur les formules de calcul</a>
					</dd>
				</dl>
			</dd>
			<dt><strong>Enregistrement en comptabilité</strong></dt>
			{input name="accounting" type="checkbox" value="1" label="Enregistrer en comptabilité" default=$accounting_enabled}
			<dd class="help">Chaque nouvelle inscription de membre dans ce tarif sera enregistrée dans la comptabilité.</dd>
		</dl>
	</fieldset>


	<fieldset class="accounting">
		<legend>Enregistrer en comptabilité</legend>
		{if !count($years)}
			<p class="error block">Il n'y a aucun exercice ouvert dans la comptabilité, il n'est donc pas possible d'enregistrer les activités dans la comptabilité. Merci de commencer par <a href="{$admin_url}acc/years/new.php">créer un exercice</a>.</p>
		{else}
		<dl>
			<dt><label for="f_id_year">Exercice</label> <b>(obligatoire)</b></dt>
			<dd>
				<select id="f_id_year" name="id_year">
					{foreach from=$years item="year"}
					<option value="{$year.id}">{$year.label} — {$year.start_date|date_fr:'d/m/Y'} au {$year.end_date|date_fr:'d/m/Y'}</option>
					{/foreach}
				</select>
			</dd>
			{input type="list" target="acc/charts/accounts/selector.php?targets=%s&year=%d"|args:$targets,$fee.id_year name="account" label="Compte à utiliser" default=$account required=1}
		</dl>
		{/if}
	</fieldset>

	<p class="submit">
		{csrf_field key=$csrf_key}
		<input type="submit" name="save" value="{$submit_label} &rarr;" />
	</p>

................................................................................
	if (!$('#f_amount_type_1').checked)
		hide.push('.amount_type_1');

	if (!$('#f_amount_type_2').checked)
		hide.push('.amount_type_2');

	g.toggle(hide, false);
	g.toggle('.accounting', $('#f_accounting_1').checked);

	function togglePeriod()
	{
		g.toggle(['.amount_type_1', '.amount_type_2'], false);

		if (this.checked && this.value == 1)
			g.toggle('.amount_type_1', true);
................................................................................
		else if (this.checked && this.value == 2)
			g.toggle('.amount_type_2', true);
	}

	$('#f_amount_type_0').onchange = togglePeriod;
	$('#f_amount_type_1').onchange = togglePeriod;
	$('#f_amount_type_2').onchange = togglePeriod;
	$('#f_accounting_1').onchange = () => { g.toggle('.accounting', $('#f_accounting_1').checked); };

	function toggleYearForSelector()
	{
		var btn = document.querySelector('#f_account_container button');
		btn.value = btn.value.replace(/year=\d+/, 'year=' + y.value);
	}

	var y = $('#f_id_year')

	y.onchange = toggleYearForSelector;
	toggleYearForSelector();
})();
{/literal}
</script>

Modified src/templates/services/save.tpl from [0546db8209] to [bf6b80053a].

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
..
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

{form_errors}

<form method="post" action="{$self_url}" data-focus="1">

	<fieldset>
		<legend>Enregistrer une activité</legend>


		<dl>
			{input type="list" name="user" required=1 label="Membre concerné" default=$selected_user target="membres/selector.php"}






			<dt><label for="f_service_ID">Activité</label> <b>(obligatoire)</b></dt>

			{foreach from=$grouped_services item="service"}
				<dd><label>
					<input type="radio" name="id_service" id="f_id_service_{$service.id}" value="{$service.id}" {if f('id_service') == $service->id}checked="checked"{/if} />



					{$service.label}

					{if $service.duration}
						{$service.duration} jours
					{elseif $service.start_date}
						du {$service.start_date|date_short} au {$service.end_date|date_short}
					{else}
						ponctuelle
					{/if}
					</label>
				</dd>
				{if $service.description}
				<dd class="help">
					{$service.description|escape|nl2br}
				</dd>
				{/if}







				<dd data-service="s{$service.id}">
					<dl>
						<dt><label for="f_fee">Tarif</label> <b>(obligatoire)</b></dt>
					{foreach from=$service.fees key="service_id" item="fee"}


						{input type="radio" name="id_fee" value=$fee.id label=$fee.label help=$fee.description data-amount=$fee.amount data-user-amount=$fee.user_amount data-account=$fee.id_account}



















					{/foreach}
					</dl>
				</dd>
			{/foreach}

			<dt><strong>Montant de l'activité à payer</strong></dt>
			<dd><h3 class="money warning" id="target_amount" data-currency="{$config.monnaie}">--</h3></dd>
		</dl>
		<dl class="accounting">
			{input type="money" name="amount" label="Montant réglé par le membre"}
			{input type="list" target="acc/charts/accounts/selector.php?targets=%s"|args:$account_targets name="account" label="Compte de règlement" required=1}
		</dl>
		<dl>
			{input type="checkbox" name="paid" value="1" label="Marquer cette activité comme payée"}
			<dd class="help">En cas de règlement en plusieurs fois, il sera possible de cocher cette case lorsque le solde aura été réglé.</dd>
		</dl>
	</fieldset>












	<p class="submit">
		{csrf_field key=$csrf_key}
		<input type="submit" name="save" value="Enregistrer &rarr;" />
	</p>

</form>
................................................................................

	var first = document.querySelector('[data-service="s' + elm.value + '"] input[name=id_fee]');
	first.checked = true;
	selectFee(first);
}

function selectFee(elm) {
	var userAmount = parseInt(elm.getAttribute('data-user-amount'), 10);
	var amount = parseInt(elm.getAttribute('data-amount'), 10);

	if (userAmount) {
		amount = userAmount;
	}


	if (elm.getAttribute('data-account')) {
		g.toggle('.accounting', true);

	}
	else {
		g.toggle('.accounting', false);

	}

	console.log(elm.getAttribute('data-account'));

	var a = $('#target_amount');


	if (amount) {
		a.innerHTML = g.formatMoney(amount) + ' ' + a.getAttribute('data-currency');
		a.setAttribute('data-amount', amount);
		$('#f_paid_amount').value = g.formatMoney(amount);
		$('#f_paid_1').checked = true;
	}
	else {
		a.innerHTML = 'prix libre';
		a.setAttribute('data-amount', 0);
		$('#f_paid_1').checked = true;
	}
}

$('input[name=id_service]').forEach((e) => {
	e.onchange = () => { selectService(e); };
});

$('input[name=id_fee]').forEach((e) => {
	e.onchange = () => { selectFee(e); };
});

$('#f_paid_amount').onkeyup = () => {
	var v = g.getMoneyAsInt($('#f_paid_amount').value);
	var expected = parseInt($('#target_amount').getAttribute('data-amount'), 10);

	if (v >= expected) {
		$('#f_paid_1').checked = true;
	}
	else {
		$('#f_paid_1').checked = false;
	}
}

var selected = document.querySelector('input[name="id_service"]:checked, input[name="id_service"]');
selected.checked = true;

selectService(selected);
</script>
{/literal}

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







>
>

|
<
>
>
>
>
>

>
|
|
<
>
>
>
|
>
|
|
|
|
|
|
|
<
|
|
|
|
|
|
>
>
>
>
>
>
>
|
<
|
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
<
|

<
<
<
<
<
<
<





>
>
>
>
>
>
>
>
>
>
>







 







|
<

<
<
<
<
>
|
|
>
|
<
<
>
|
<
<
<
<
<
>

<
<
|
<
<
<
<
<
<











<
<
<
<
<
<
<
<
<
<
<
<








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
...
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

{form_errors}

<form method="post" action="{$self_url}" data-focus="1">

	<fieldset>
		<legend>Enregistrer une activité</legend>

{if !$selected_user}
		<dl>
			{input type="list" name="user" required=1 label="Sélectionner un membre" default=$selected_user target="membres/selector.php"}

		</dl>
{else}
		<dl>
			<dt>Membre sélectionné</dt>
			<dd><h3>{$user_name}</h3><input type="hidden" name="id_user" value="{$user_id}" /></dd>
			<dt><label for="f_service_ID">Activité</label> <b>(obligatoire)</b></dt>

		{foreach from=$grouped_services item="service"}
			<dd>

				<label class="radio-btn">
					{input type="radio" name="id_service" value=$service.id}
					<div>
						<h3>{$service.label}</h3>
						<p>
							{if $service.duration}
								{$service.duration} jours
							{elseif $service.start_date}
								du {$service.start_date|date_short} au {$service.end_date|date_short}
							{else}
								ponctuelle
							{/if}

						</p>
						{if $service.description}
						<p class="help">
							{$service.description|escape|nl2br}
						</p>
						{/if}
					</div>
				</label>
			</dd>
		{/foreach}
		</dl>

		{foreach from=$grouped_services item="service"}
		<dl data-service="s{$service.id}">

			<dt><label for="f_fee">Tarif</label> <b>(obligatoire)</b></dt>
			{foreach from=$service.fees key="service_id" item="fee"}
			<dd>
				<label class="radio-btn">
					{input type="radio" name="id_fee" value=$fee.id data-user-amount=$fee.user_amount data-account=$fee.id_account}
					<div>
						<h3>{$fee.label}</h3>
						<p>
							{if !$fee.user_amount}
								prix libre ou gratuit
							{elseif $fee.user_amount && $fee.formula}
								<strong>{$fee.user_amount|raw|money_currency}</strong> (montant calculé)
							{elseif $fee.user_amount}
								<strong>{$fee.user_amount|raw|money_currency}</strong>
							{/if}
						</p>
						{if $fee.description}
						<p class="help">
							{$fee.description|escape|nl2br}
						</p>
						{/if}
					</div>
				</label>
			</dd>
			{/foreach}
		</dl>

		{/foreach}








		<dl>
			{input type="checkbox" name="paid" value="1" label="Marquer cette activité comme payée"}
			<dd class="help">En cas de règlement en plusieurs fois, il sera possible de cocher cette case lorsque le solde aura été réglé.</dd>
		</dl>
	</fieldset>

	<fieldset class="accounting">
		<legend>Enregistrement en comptabilité</legend>

		<dl>
			{input type="money" name="amount" label="Montant réglé par le membre" required=1}
			{input type="list" target="acc/charts/accounts/selector.php?targets=%s"|args:$account_targets name="account" label="Compte de règlement" required=1}
			{input type="text" name="payment_reference" label="Référence de paiement" help="Numéro de chèque, numéro de transaction CB, etc."}
		</dl>
{/if}
	</fieldset>

	<p class="submit">
		{csrf_field key=$csrf_key}
		<input type="submit" name="save" value="Enregistrer &rarr;" />
	</p>

</form>
................................................................................

	var first = document.querySelector('[data-service="s' + elm.value + '"] input[name=id_fee]');
	first.checked = true;
	selectFee(first);
}

function selectFee(elm) {
	var amount = parseInt(elm.getAttribute('data-user-amount'), 10);






	// Toggle accounting part of the form
	var accounting = elm.getAttribute('data-account') ? true : false;
	g.toggle('.accounting', accounting);
	$('#f_amount').required = accounting;



	$('#f_paid_1').checked = true;






	// Fill the amount paid by the user
	if (amount) {


		$('#f_amount').value = g.formatMoney(amount);






	}
}

$('input[name=id_service]').forEach((e) => {
	e.onchange = () => { selectService(e); };
});

$('input[name=id_fee]').forEach((e) => {
	e.onchange = () => { selectFee(e); };
});













var selected = document.querySelector('input[name="id_service"]:checked, input[name="id_service"]');
selected.checked = true;

selectService(selected);
</script>
{/literal}

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

Modified src/www/admin/acc/charts/accounts/selector.php from [5fc652cda6] to [232649b9e9].

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
<?php

namespace Garradin;

use Garradin\Entities\Accounting\Account;
use Garradin\Accounting\Charts;


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

header('X-Frame-Options: SAMEORIGIN', true);

$charts = $chart = null;
$targets = qg('targets');



if (qg('chart')) {
	$chart = Charts::get((int)qg('chart'));







}
elseif ($current_year) {
	$chart = $current_year->chart();
}

if (qg('chart_choice')) {
	$charts = Charts::listAssoc();
}

if (!$chart) {
	throw new UserException('Aucun plan comptable ouvert actuellement');
}

$accounts = $chart->accounts();

$tpl->assign(compact('chart', 'charts', 'targets'));

if (!$targets) {
	$tpl->assign('accounts', $accounts->listAll());
}
else {
	$tpl->assign('grouped_accounts', $accounts->listCommonGrouped(explode(':', $targets)));
}


$tpl->display('acc/charts/accounts/selector.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
<?php

namespace Garradin;

use Garradin\Entities\Accounting\Account;
use Garradin\Accounting\Charts;
use Garradin\Accounting\Years;

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

header('X-Frame-Options: SAMEORIGIN', true);


$targets = qg('targets');

$chart = null;

if (qg('chart')) {
	$chart = Charts::get((int)qg('chart'));
}
elseif (qg('year')) {
	$year = Years::get((int)qg('year'));

	if ($year) {
		$chart = $year->chart();
	}
}
elseif ($current_year) {
	$chart = $current_year->chart();
}





if (!$chart) {
	throw new UserException('Aucun exercice ouvert disponible');
}

$accounts = $chart->accounts();

$tpl->assign(compact('chart', 'targets'));

if (!$targets) {
	$tpl->assign('accounts', $accounts->listAll());
}
else {
	$tpl->assign('grouped_accounts', $accounts->listCommonGrouped(explode(':', $targets)));
}


$tpl->display('acc/charts/accounts/selector.tpl');

Modified src/www/admin/services/fees/edit.php from [17d557417f] to [30c90681af].

1
2
3
4
5

6
7
8
9
10
11
12
..
27
28
29
30
31
32
33




34
35
36
37
38
39
<?php
namespace Garradin;

use Garradin\Services\Fees;
use Garradin\Accounting\Accounts;


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

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

$fee = Fees::get((int) qg('id'));

................................................................................
}
elseif ($fee->formula) {
	$amount_type = 2;
}
else {
	$amount_type = 0;
}





$account = $fee->id_account ? [$fee->id_account => Accounts::getSelectorLabel($fee->id_account)] : null;

$tpl->assign(compact('service', 'amount_type', 'fee', 'csrf_key', 'account'));

$tpl->display('services/fees/edit.tpl');





>







 







>
>
>
>



|


1
2
3
4
5
6
7
8
9
10
11
12
13
..
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
namespace Garradin;

use Garradin\Services\Fees;
use Garradin\Accounting\Accounts;
use Garradin\Accounting\Years;

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

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

$fee = Fees::get((int) qg('id'));

................................................................................
}
elseif ($fee->formula) {
	$amount_type = 2;
}
else {
	$amount_type = 0;
}

$accounting_enabled = (bool) $fee->id_account;

$years = Years::listOpen();

$account = $fee->id_account ? [$fee->id_account => Accounts::getSelectorLabel($fee->id_account)] : null;

$tpl->assign(compact('service', 'amount_type', 'fee', 'csrf_key', 'account', 'accounting_enabled', 'years'));

$tpl->display('services/fees/edit.tpl');

Modified src/www/admin/services/fees/index.php from [cc7d1085bb] to [85376d6574].

1
2
3
4

5
6
7
8
9
10
11
..
20
21
22
23
24
25
26



27
28
29
30
<?php
namespace Garradin;

use Garradin\Entities\Accounting\Account;

use Garradin\Entities\Services\Fee;
use Garradin\Services\Services;

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

$service = Services::get((int)qg('id'));

................................................................................
	$fee->id_service = $service->id();
	$fee->importForm();
	$fee->save();
}, 'fee_add', ADMIN_URL . 'services/fees/?id=' . $service->id());

$targets = Account::TYPE_REVENUE;




$tpl->assign(compact('service', 'targets'));
$tpl->assign('list', $fees->listWithStats());

$tpl->display('services/fees/index.tpl');




>







 







>
>
>
|



1
2
3
4
5
6
7
8
9
10
11
12
..
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
namespace Garradin;

use Garradin\Entities\Accounting\Account;
use Garradin\Accounting\Years;
use Garradin\Entities\Services\Fee;
use Garradin\Services\Services;

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

$service = Services::get((int)qg('id'));

................................................................................
	$fee->id_service = $service->id();
	$fee->importForm();
	$fee->save();
}, 'fee_add', ADMIN_URL . 'services/fees/?id=' . $service->id());

$targets = Account::TYPE_REVENUE;

$accounting_enabled = false;
$years = Years::listOpen();

$tpl->assign(compact('service', 'targets', 'accounting_enabled', 'years'));
$tpl->assign('list', $fees->listWithStats());

$tpl->display('services/fees/index.tpl');

Modified src/www/admin/services/save.php from [ad4b16d048] to [58f5e92f69].

1
2
3
4
5
6

7
8
9
10
11
12
13
..
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

33
34
35
36
<?php
namespace Garradin;

use Garradin\Services\Services;
use Garradin\Entities\Services\Service_User;
use Garradin\Entities\Accounting\Account;


require_once __DIR__ . '/_inc.php';

$session->requireAccess('membres', Membres::DROIT_ECRITURE);

$user_id = (int) qg('user') ?: null;
$user_name = $user_id ? (new Membres)->getNom($user_id) : null;
................................................................................

if (!count($grouped_services)) {
	Utils::redirect(ADMIN_URL . 'services/?CREATE');
}

$csrf_key = 'service_save';

$form->runIf('save', function () {
	$su = new Service_User;
	$su->saveFromForm($user->id);

	Utils::redirect(ADMIN_URL . 'services/user.php?id=' . $su->id_user);
}, $csrf_key);

$selected_user = $user_id ? [$user_id => $user_name] : null;

$account_targets = implode(',', [Account::TYPE_BANK, Account::TYPE_CASH, Account::TYPE_OUTSTANDING]);


$tpl->assign(compact('grouped_services', 'csrf_key', 'selected_user', 'account_targets'));

$tpl->display('services/save.tpl');






>







 







|

|






|
>

|


1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
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;

use Garradin\Services\Services;
use Garradin\Entities\Services\Service_User;
use Garradin\Entities\Accounting\Account;
use Garradin\Entities\Accounting\Transaction;

require_once __DIR__ . '/_inc.php';

$session->requireAccess('membres', Membres::DROIT_ECRITURE);

$user_id = (int) qg('user') ?: null;
$user_name = $user_id ? (new Membres)->getNom($user_id) : null;
................................................................................

if (!count($grouped_services)) {
	Utils::redirect(ADMIN_URL . 'services/?CREATE');
}

$csrf_key = 'service_save';

$form->runIf('save', function () use ($session) {
	$su = new Service_User;
	$su->saveFromForm($session->getUser()->id);

	Utils::redirect(ADMIN_URL . 'services/user.php?id=' . $su->id_user);
}, $csrf_key);

$selected_user = $user_id ? [$user_id => $user_name] : null;

$types_details = Transaction::getTypesDetails();
$account_targets = $types_details[Transaction::TYPE_REVENUE]->accounts[1]->targets_string;

$tpl->assign(compact('grouped_services', 'csrf_key', 'selected_user', 'account_targets', 'user_name', 'user_id'));

$tpl->display('services/save.tpl');