Garradin Plugins

Check-in [12f779efb8]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Mise à jour
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 12f779efb83637f7946979d1692bd69070542449
User & Date: bohwaz 2020-05-22 00:42:02
Context
2020-05-22
00:56
Fixes check-in: 83819e8692 user: bohwaz tags: trunk
00:42
Mise à jour check-in: 12f779efb8 user: bohwaz tags: trunk
2020-05-20
00:39
Ajout plugin caisse en alpha check-in: c3c4a1252a user: bohwaz tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to caisse/data.sql.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
...
145
146
147
148
149
150
151




152
153
154
155
	(3, "Sonnette basique (à languette, plastique noir)", 200),
	(3, "Tendeur", 300),
	(3, "Autre pièce neuve", 1000);

INSERT INTO @PREFIX_categories VALUES (4, "Pièces d'occasion");
INSERT INTO @PREFIX_products (category, name, price) VALUES
	(4, "Adaptateur (tige de selle, potence)", 100),
	(4, "Ampoule", 50),
	(4, "Attache (rapide, selle, roue, panier, siège)", 100),
	(4, "Axe (pédalier, roue)", 100),
	(4, "Béquille", 500),
	(4, "Boîtier de pédalier (ou cartouche)", 400),
	(4, "Butée réglable de gaine (frein, dérailleur)", 50),
	(4, "Câble (frein, dérailleur)", 50),
	(4, "Cadre nu", 1500),
................................................................................
	OR (name LIKE 'Clavette%')
	OR (name LIKE 'Écrou%')
	OR (name LIKE 'Dérailleur%')
	OR (name LIKE 'Rayon%')
	OR (name LIKE 'Pignon%')
	OR (name LIKE 'Plateau%')
	OR (name LIKE 'Fond de jante%')




	OR (name IN ('Potence', 'Poignée de guidon', 'Tige de selle'))
);

INSERT INTO @PREFIX_products_methods SELECT id, 3 FROM @PREFIX_products WHERE category IN (1, 2);







|







 







>
>
>
>
|



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
	(3, "Sonnette basique (à languette, plastique noir)", 200),
	(3, "Tendeur", 300),
	(3, "Autre pièce neuve", 1000);

INSERT INTO @PREFIX_categories VALUES (4, "Pièces d'occasion");
INSERT INTO @PREFIX_products (category, name, price) VALUES
	(4, "Adaptateur (tige de selle, potence)", 100),
	(4, "Ampoule pour phare dynamo", 50),
	(4, "Attache (rapide, selle, roue, panier, siège)", 100),
	(4, "Axe (pédalier, roue)", 100),
	(4, "Béquille", 500),
	(4, "Boîtier de pédalier (ou cartouche)", 400),
	(4, "Butée réglable de gaine (frein, dérailleur)", 50),
	(4, "Câble (frein, dérailleur)", 50),
	(4, "Cadre nu", 1500),
................................................................................
	OR (name LIKE 'Clavette%')
	OR (name LIKE 'Écrou%')
	OR (name LIKE 'Dérailleur%')
	OR (name LIKE 'Rayon%')
	OR (name LIKE 'Pignon%')
	OR (name LIKE 'Plateau%')
	OR (name LIKE 'Fond de jante%')
	OR (name LIKE 'Sonnette%')
	OR (name LIKE 'Dynamo%')
	OR (name LIKE 'Ampoule%')
	OR (name LIKE '%reelight%')
	OR (name IN ('Potence', 'Poignée de guidon', 'Tige de selle', 'Phare (sans ampoule)'))
);

INSERT INTO @PREFIX_products_methods SELECT id, 3 FROM @PREFIX_products WHERE category IN (1, 2);

Changes to caisse/lib/Session.php.

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














<?php

namespace Garradin\Plugin\Caisse;

use Garradin\DB;



class Session
{










	public function open(int $user_id, int $amount): int
	{
		$db = DB::getInstance();
		$db->insert(POS::tbl('sessions'), [
			'open_user'   => $user_id,
			'open_amount' => $amount,
		]);

		return $db->lastInsertId();
	}

	public function getCurrent()
	{
		$db = DB::getInstance();
		return $db->first(POS::sql('SELECT * FROM @PREFIX_sessions WHERE closed IS NULL LIMIT 1;'));
	}












	public function close(int $id, int $amount)
	{
		$db = DB::getInstance();

		if ($db->test(POS::tbl('tabs'), 'session = ? AND closed IS NULL', $id)) {
			throw new UserException('Il y a des notes qui ne sont pas clôturées.');
		}
	}












	public function listPayments(int $id)
	{
		return DB::getInstance()->get(POS::sql('SELECT tp.*, m.name
			FROM @PREFIX_tabs_payments tp
			INNER JOIN @PREFIX_tabs t ON tp.tab = t.id AND t.session = ?
			INNER JOIN @PREFIX_methods m ON m.id = tp.method
			ORDER BY m.name, tp.date;', $id));
	}

	public function listPaymentTotals(int $id)
	{
		return DB::getInstance()->get(POS::sql('SELECT SUM(tp.amount), m.name FROM @PREFIX_tabs_payments tp
			INNER JOIN @PREFIX_tabs t ON tp.tab = t.id AND t.session = ?
			INNER JOIN @PREFIX_methods m ON m.id = tp.method
			GROUP BY tp.method
			ORDER BY m.name;', $id));
	}

	public function listTabsTotals(int $id)
	{
		return DB::getInstance()->get(POS::sql('SELECT *,
			(SELECT SUM(qty * price) FROM @PREFIX_tabs_items WHERE tab = t.id) AS total
			FROM @PREFIX_tabs t WHERE session = ? AND closed IS NULL ORDER BY opened;', $id));
	}
}



















>
>



>
>
>
>
>
>
>
>
>
>
|










|


|


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



|


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





|


|

|



|


|



|

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

namespace Garradin\Plugin\Caisse;

use Garradin\DB;
use Garradin\Config;
use Garradin\UserException;

class Session
{
	public $id;

	public function __construct(int $id) {
		$this->id = $id;

		foreach (DB::getInstance()->first(POS::sql('SELECT * FROM @PREFIX_sessions WHERE id = ?;'), $id) as $key => $value) {
			$this->$key = $value;
		}
	}

	static public function open(int $user_id, int $amount): int
	{
		$db = DB::getInstance();
		$db->insert(POS::tbl('sessions'), [
			'open_user'   => $user_id,
			'open_amount' => $amount,
		]);

		return $db->lastInsertId();
	}

	static public function getCurrentId()
	{
		$db = DB::getInstance();
		return $db->firstColumn(POS::sql('SELECT id FROM @PREFIX_sessions WHERE closed IS NULL LIMIT 1;'));
	}

	static public function list()
	{
		$db = DB::getInstance();
		$name_field = Config::getInstance()->get('champ_identite');
		$sql = sprintf('SELECT s.*, m.%s AS open_user_name
			FROM @PREFIX_sessions s
			INNER JOIN membres m ON s.open_user = m.id
			ORDER BY s.opened DESC;', $db->quoteIdentifier($name_field));
		return $db->get(POS::sql($sql));
	}

	public function close(int $amount)
	{
		$db = DB::getInstance();

		if ($db->test(POS::tbl('tabs'), 'session = ? AND closed IS NULL', $this->id)) {
			throw new UserException('Il y a des notes qui ne sont pas clôturées.');
		}

		return $db->preparedQuery(POS::sql('UPDATE @PREFIX_sessions SET
			closed = datetime(\'now\', \'localtime\'),
			close_amount = ?
			WHERE id = ?'), [$amount, $this->id]);
	}

	public function getTotal()
	{
		return DB::getInstance()->firstColumn(POS::sql('SELECT SUM(tp.amount) FROM @PREFIX_tabs_payments tp
			INNER JOIN @PREFIX_tabs t ON tp.tab = t.id AND t.session = ?'), $this->id);
	}

	public function listPayments()
	{
		return DB::getInstance()->get(POS::sql('SELECT tp.*, m.name
			FROM @PREFIX_tabs_payments tp
			INNER JOIN @PREFIX_tabs t ON tp.tab = t.id AND t.session = ?
			INNER JOIN @PREFIX_methods m ON m.id = tp.method
			ORDER BY m.name, tp.date;'), $this->id);
	}

	public function listPaymentTotals()
	{
		return DB::getInstance()->get(POS::sql('SELECT SUM(tp.amount) AS total, m.name FROM @PREFIX_tabs_payments tp
			INNER JOIN @PREFIX_tabs t ON tp.tab = t.id AND t.session = ?
			INNER JOIN @PREFIX_methods m ON m.id = tp.method
			GROUP BY tp.method
			ORDER BY m.name;'), $this->id);
	}

	public function listTabsTotals()
	{
		return DB::getInstance()->get(POS::sql('SELECT *,
			(SELECT SUM(qty * price) FROM @PREFIX_tabs_items WHERE tab = t.id) AS total
			FROM @PREFIX_tabs t WHERE session = ? ORDER BY opened;'), $this->id);
	}

	public function listTotalsByCategory()
	{
		return DB::getInstance()->get(POS::sql('SELECT
			SUM(ti.qty * ti.price) AS total,
			c.name
			FROM @PREFIX_tabs_items ti
			INNER JOIN @PREFIX_products p ON ti.product = p.id
			INNER JOIN @PREFIX_categories c ON c.id = p.category
			WHERE ti.tab IN (SELECT id FROM @PREFIX_tabs WHERE session = ?)
			GROUP BY c.id
			ORDER BY c.name;'), $this->id);

	}
}

Changes to caisse/lib/Tab.php.

3
4
5
6
7
8
9
10
11
12
13
14




15
16
17
18
19
20
21
...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
namespace Garradin\Plugin\Caisse;

use Garradin\DB;
use Garradin\UserException;

class Tab
{
	protected $id;

	public function __construct(int $id)
	{
		$this->id = $id;




	}

	public function getRemainder(): int
	{
		return (int) DB::getInstance()->firstColumn(POS::sql('SELECT
			(SELECT SUM(price * qty) FROM @PREFIX_tabs_items WHERE tab = ?)
			- COALESCE((SELECT SUM(amount) FROM @PREFIX_tabs_payments WHERE tab = ?), 0);'), $this->id, $this->id);
................................................................................
		}

		return DB::getInstance()->preparedQuery(POS::sql('UPDATE @PREFIX_tabs SET closed = datetime(\'now\',\'localtime\') WHERE id = ?;'), [$this->id]);
	}

	public function delete() {
		$db = DB::getInstance();
		if ($db->test(POS::tbl('tabs'), 'closed IS NULL AND id = ?', $this->id)) {
			throw new UserException('Impossible de supprimer une note qui n\'est pas close');
		}

		$db->delete(POS::tbl('tabs'), 'id = ?', $this->id);
	}

	static public function listForSession(int $session_id) {
		return DB::getInstance()->getGrouped(POS::sql('SELECT id, *, COALESCE((SELECT SUM(qty*price) FROM @PREFIX_tabs_items WHERE tab = @PREFIX_tabs.id), 0) AS total FROM @PREFIX_tabs WHERE session = ? ORDER BY closed IS NOT NULL, opened DESC;'), $session_id);
	}
}







|




>
>
>
>







 







|










3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
namespace Garradin\Plugin\Caisse;

use Garradin\DB;
use Garradin\UserException;

class Tab
{
	public $id;

	public function __construct(int $id)
	{
		$this->id = $id;

		foreach (DB::getInstance()->first(POS::sql('SELECT * FROM @PREFIX_tabs WHERE id = ?;'), $id) as $key => $value) {
			$this->$key = $value;
		}
	}

	public function getRemainder(): int
	{
		return (int) DB::getInstance()->firstColumn(POS::sql('SELECT
			(SELECT SUM(price * qty) FROM @PREFIX_tabs_items WHERE tab = ?)
			- COALESCE((SELECT SUM(amount) FROM @PREFIX_tabs_payments WHERE tab = ?), 0);'), $this->id, $this->id);
................................................................................
		}

		return DB::getInstance()->preparedQuery(POS::sql('UPDATE @PREFIX_tabs SET closed = datetime(\'now\',\'localtime\') WHERE id = ?;'), [$this->id]);
	}

	public function delete() {
		$db = DB::getInstance();
		if ($db->count(POS::tbl('tabs_items'), 'tab = ?', $this->id) && $db->test(POS::tbl('tabs'), 'closed IS NULL AND id = ?', $this->id)) {
			throw new UserException('Impossible de supprimer une note qui n\'est pas close');
		}

		$db->delete(POS::tbl('tabs'), 'id = ?', $this->id);
	}

	static public function listForSession(int $session_id) {
		return DB::getInstance()->getGrouped(POS::sql('SELECT id, *, COALESCE((SELECT SUM(qty*price) FROM @PREFIX_tabs_items WHERE tab = @PREFIX_tabs.id), 0) AS total FROM @PREFIX_tabs WHERE session = ? ORDER BY closed IS NOT NULL, opened DESC;'), $session_id);
	}
}

Added caisse/templates/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
{include file="admin/_head.tpl" title="Sessions de caisse" current="plugin_%s"|args:$plugin.id}

{if !$current_pos_session}
<ul class="actions">
	<li><a href="session.php">Ouvrir la caisse</a></li>
</ul>
{/if}

<table class="list">
	<thead>
		<tr>
			<th>Caisse ouverte par</th>
			<td colspan="2">Ouverture</td>
			<td colspan="2">Clôture</td>
			<td></td>
		</tr>
	</thead>
	<tbody>
		{foreach from=$pos_sessions item="pos_session"}
		<tr>
			<th>{$pos_session.open_user_name}</th>
			<td>{$pos_session.opened|format_sqlite_date_to_french}</td>
			<td>{$pos_session.open_amount|raw|pos_money}</td>
			<td>{$pos_session.closed|format_sqlite_date_to_french}</td>
			<td>{$pos_session.close_amount|raw|pos_money}</td>
			<td class="actions">
				<a href="session.php?id={$pos_session.id}">Détails</a>
				{if !$pos_session.closed}
				| <a href="session.php?id={$pos_session.id}">Clôturer</a>
				| <a href="tab.php">Reprendre</a>
				{/if}
			</td>
		</tr>
		{/foreach}
	</tbody>
</table>

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

Changes to caisse/templates/invoice.tpl.

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
		</thead>
		<tbody>
		{foreach from=$items item="item"}
			<tr>
				<th>{$item.name}</th>
				<td>{$item.methods|raw|show_methods}</td>
				<td>{$item.qty}</td>
				<td>{$item.price|escape|pos_money}</td>
				<td>{$item.total|escape|pos_money}</td>
			</tr>
			{if $item.description}
			<tr>
				<td colspan="5">
					{$item.description|escape|nl2br}
				</td>
			</tr>
................................................................................
		{/foreach}
			<tr class="foot">
				<th>TVA</th>
				<td colspan="4"><em>Association exonérée des impôts commerciaux</em></td>
			</tr>
			<tr class="foot">
				<th colspan="4">Total</th>
				<td>{$tab.total|escape|pos_money}</td>
			</tr>
			{foreach from=$existing_payments item="payment"}
			<tr class="foot">
				<th>{$payment.name}</th>
				<td colspan="3"><em>Réf. {$payment.reference}</em></td>
				<td>{$payment.amount|escape|pos_money}</td>
			</tr>
			{/foreach}
			{foreach from=$payment_options item="option"}
			<tr class="foot">
				<th colspan="4">Déduction « Coup de pouce vélo - réparation »</th>
				<td>{$option.amount|escape|pos_money}</td>
			</tr>
			{/foreach}
			{if $remainder_after}
			<tr class="foot">
				<th colspan="4">Reste à payer</th>
				<td>{$remainder_after|escape|pos_money}</td>
			</tr>
			{/if}
		</tbody>
	</table>
</section>

</body>
</html>







|
|







 







|





|





|





|








109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
		</thead>
		<tbody>
		{foreach from=$items item="item"}
			<tr>
				<th>{$item.name}</th>
				<td>{$item.methods|raw|show_methods}</td>
				<td>{$item.qty}</td>
				<td>{$item.price|raw|pos_money}</td>
				<td>{$item.total|raw|pos_money}</td>
			</tr>
			{if $item.description}
			<tr>
				<td colspan="5">
					{$item.description|escape|nl2br}
				</td>
			</tr>
................................................................................
		{/foreach}
			<tr class="foot">
				<th>TVA</th>
				<td colspan="4"><em>Association exonérée des impôts commerciaux</em></td>
			</tr>
			<tr class="foot">
				<th colspan="4">Total</th>
				<td>{$tab.total|raw|pos_money}</td>
			</tr>
			{foreach from=$existing_payments item="payment"}
			<tr class="foot">
				<th>{$payment.name}</th>
				<td colspan="3"><em>Réf. {$payment.reference}</em></td>
				<td>{$payment.amount|raw|pos_money}</td>
			</tr>
			{/foreach}
			{foreach from=$payment_options item="option"}
			<tr class="foot">
				<th colspan="4">Déduction « Coup de pouce vélo - réparation »</th>
				<td>{$option.amount|raw|pos_money}</td>
			</tr>
			{/foreach}
			{if $remainder_after}
			<tr class="foot">
				<th colspan="4">Reste à payer</th>
				<td>{$remainder_after|raw|pos_money}</td>
			</tr>
			{/if}
		</tbody>
	</table>
</section>

</body>
</html>

Added caisse/templates/session.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
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
{include file="admin/_head.tpl" current="plugin_%s"|args:$plugin.id}

<h3>{$title}</h3>

<h2 class="ruler">Notes</h2>

<table class="list">
	<thead>
		<tr>
			<td>N°</td>
			<th>Note</th>
			<td>Total</td>
			<td></td>
		</tr>
	</thead>
	<tbody>
		{foreach from=$tabs item="tab"}
		<tr>
			<td>{$tab.id}</td>
			<th>
				{$tab.opened|date_format:"%H:%M"}
				{if $tab.closed}
				&rarr; {$tab.closed|date_format:"%H:%M"}
				{/if}
				— {$tab.name}
			</th>
			<td>
				{$tab.total|raw|pos_money}
			</td>
			<td class="actions"><span class="noprint"><a href="tab.php?id={$tab.id}" class="icn" title="Détails">𝍢</a></span></td>
		</tr>
		{/foreach}
	</tbody>
	<tfoot>
		<tr>
			<td></td>
			<th>Total</th>
			<td>{$total|raw|pos_money}</td>
			<td></td>
		</tr>
	</tfoot>
</table>

<h2 class="ruler">Règlements</h2>

<table class="list">
	<thead>
		<tr>
			<td>Note n°</td>
			<th>Date</th>
			<td>Moyen</td>
			<td>Montant</td>
			<td>Référence</td>
			<td></td>
		</tr>
	</thead>
	<tbody>
		{foreach from=$payments item="payment"}
		<tr>
			<td>{$payment.tab}</td>
			<th>
				{$payment.date|date_format:"%H:%M"}
			</th>
			<td>{$payment.name}</td>
			<td>
				{$payment.amount|raw|pos_money}
			</td>
			<td>{$payment.reference}</td>
			<td></td>
		</tr>
		{/foreach}
	</tbody>
</table>

<h2 class="ruler">Totaux, par moyen de paiement</h2>

<table class="list">
	<thead>
		<tr>
			<td>Moyen</td>
			<td>Montant</td>
			<td></td>
		</tr>
	</thead>
	<tbody>
		{foreach from=$payments_totals item="payment"}
		<tr>
			<th>{$payment.name}</th>
			<td>
				{$payment.total|raw|pos_money}
			</td>
			<td></td>
		</tr>
		{/foreach}
	</tbody>
</table>


<h2 class="ruler">Totaux, par catégorie</h2>

<table class="list">
	<thead>
		<tr>
			<td>Catégorie</td>
			<td>Montant</td>
			<td></td>
		</tr>
	</thead>
	<tbody>
		{foreach from=$totals_categories item="cat"}
		<tr>
			<th>{$cat.name}</th>
			<td>
				{$cat.total|raw|pos_money}
			</td>
			<td></td>
		</tr>
		{/foreach}
	</tbody>
</table>

{if $pos_session.opened && !$pos_session.closed}
<form method="post" action="">
<fieldset>
	<legend>Clôturer la caisse</legend>
	<dl>
		<dt>Ouverture</dt>
		<dd>{$pos_session.opened|date_format:"%d/%m/%Y à %H:%M"}</dd>
		<dt>Solde à l'ouverture</dt>
		<dd>{$pos_session.open_amount|raw|pos_money}</dd>
		<dt>Solde de la caisse à la clôture</dt>
		<dd><input type="text" pattern="\d+(,\d+)?" name="amount" id="f_amount" size="5" placeholder="42,32" />&nbsp;€</dd>
	</dl>
	<p class="submit">
		<input type="submit" name="close" value="Clôturer la caisse" />
	</p>
</fieldset>
</form>
{/if}

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

Changes to caisse/templates/session_open.tpl.

4
5
6
7
8
9
10
11
12
13
14
15
16
<fieldset>
	<legend>Ouvrir la caisse</legend>
	<dl>
		<dt><label for="f_amount">Solde de la caisse à l'ouverture</label></dt>
		<dd><input type="text" pattern="\d+(,\d+)?" name="amount" id="f_amount" size="5" placeholder="42,32" />&nbsp;€</dd>
	</dl>
	<p class="submit">
		<input type="submit" name="open" value="Enregistrer le paiement" />
	</p>
</fieldset>
</form>

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







|





4
5
6
7
8
9
10
11
12
13
14
15
16
<fieldset>
	<legend>Ouvrir la caisse</legend>
	<dl>
		<dt><label for="f_amount">Solde de la caisse à l'ouverture</label></dt>
		<dd><input type="text" pattern="\d+(,\d+)?" name="amount" id="f_amount" size="5" placeholder="42,32" />&nbsp;€</dd>
	</dl>
	<p class="submit">
		<input type="submit" name="open" value="Ouvrir la caisse" />
	</p>
</fieldset>
</form>

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

Changes to caisse/templates/tab.tpl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
64
65
66
67
68
69
70











71
72

73
74
75
76
77
78
79
{include file="admin/_head.tpl" title="Caisse" current="plugin_%s"|args:$plugin.id}

<ul class="actions">
	<li><a href="{$self_url_no_qs}?new"><strong>Nouvelle note</strong></a></li>
{foreach from=$tabs item="tab"}
	<li class="{if $tab.id == $tab_id}current{/if} {if $tab.closed}closed{/if}">
		<a href="{$self_url_no_qs}?change={$tab.id}">
			{$iteration}. {$tab.opened|date_format:"%H:%M"}
			{if $tab.total} — {$tab.total|escape|pos_money}{/if}
			{if $tab.name} — {$tab.name}{/if}
		</a>
	</li>
{/foreach}
</ul>
................................................................................
				&rarr; {$current_tab.closed|date_format:"%H:%M"}
				{/if}
				— {$current_tab.name}
			</h2>
			<div>
				<form method="post">
				<input type="submit" name="rename" value="Renommer" />
				{if !$remainder && !$current_tab.closed}
					<input type="submit" name="close" value="Clore la note" />
				{/if}
				{if !count($existing_payments)}
					<input type="submit" name="delete" value="Supprimer la note" />
				{/if}
				</form>
				<form method="post" action="./pdf.php?id={$current_tab.id}">
................................................................................
				<tfoot>
					<tr>
						<th>Total</th>
						<td></td>
						<td></td>
						<td colspan="2">{$current_tab.total|escape|pos_money}</td>
					</tr>











				</tfoot>
			</table>

		</section>

		<section class="payments">
			{if $existing_payments}
			<h2>Paiements effectués</h2>
			<table class="list">
				<tbody>
|





|







 







|







 







>
>
>
>
>
>
>
>
>
>
>


>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
{include file="admin/_head.tpl" current="plugin_%s"|args:$plugin.id}

<ul class="actions">
	<li><a href="{$self_url_no_qs}?new"><strong>Nouvelle note</strong></a></li>
{foreach from=$tabs item="tab"}
	<li class="{if $tab.id == $tab_id}current{/if} {if $tab.closed}closed{/if}">
		<a href="{$self_url_no_qs}?id={$tab.id}">
			{$iteration}. {$tab.opened|date_format:"%H:%M"}
			{if $tab.total} — {$tab.total|escape|pos_money}{/if}
			{if $tab.name} — {$tab.name}{/if}
		</a>
	</li>
{/foreach}
</ul>
................................................................................
				&rarr; {$current_tab.closed|date_format:"%H:%M"}
				{/if}
				— {$current_tab.name}
			</h2>
			<div>
				<form method="post">
				<input type="submit" name="rename" value="Renommer" />
				{if !$remainder && $items && !$current_tab.closed}
					<input type="submit" name="close" value="Clore la note" />
				{/if}
				{if !count($existing_payments)}
					<input type="submit" name="delete" value="Supprimer la note" />
				{/if}
				</form>
				<form method="post" action="./pdf.php?id={$current_tab.id}">
................................................................................
				<tfoot>
					<tr>
						<th>Total</th>
						<td></td>
						<td></td>
						<td colspan="2">{$current_tab.total|escape|pos_money}</td>
					</tr>
					<tr>
						<th>Reste à payer</th>
						<td></td>
						<td></td>
						<td colspan="2">{$remainder|raw|pos_money}</td>
					</tr>
					<tr>
						<th colspan="3">dont éligible Coup de pouce vélo
						<em>(min: 15 €, max: 50 €)</em></th>
						<td colspan="2">{$eligible_alveole|escape|pos_money}</td>
					</tr>
				</tfoot>
			</table>
		</form>
		</section>

		<section class="payments">
			{if $existing_payments}
			<h2>Paiements effectués</h2>
			<table class="list">
				<tbody>

Changes to caisse/www/admin/_inc.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

namespace Garradin\Plugin\Caisse;

use Garradin\Utils;

function reload() {
	Utils::redirect(Utils::getSelfURL(false));
}

function get_amount(string $amount): int {
	$a = preg_replace('/[^\d,]/', '', $amount);
	$a = explode('.', $a);
	$a = sprintf('%d%02d', $a[0], @$a[1]);
	return $a;
................................................................................
	return sprintf("%d,%02d", (int) ($a/100), (int) ($a%100));
}

function pos_money(?int $a): string {
	return $a === null ? '' : pos_amount($a) . '&nbsp;€';
}

$s = new Session;
$pos_session = $s->getCurrent();

if (!$pos_session && !defined('SESSION_CREATE')) {
	Utils::redirect(Utils::plugin_url(['file' => 'session.php']));
}

$tpl->register_modifier('pos_money', __NAMESPACE__ . '\\pos_money');
$tpl->register_modifier('pos_amount', __NAMESPACE__ . '\\pos_amount');
$tpl->register_modifier('image_base64', function (string $blob) {
	return 'data:image/png;base64,' . base64_encode($blob);
});

$tpl->assign('plugin_css', ['style.css']);







|







 







<
<
<
<
<
<
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
19
20
21
22
23
24
25







26
27
28
29
30
31
32
<?php

namespace Garradin\Plugin\Caisse;

use Garradin\Utils;

function reload() {
	Utils::redirect(Utils::getSelfURL(true));
}

function get_amount(string $amount): int {
	$a = preg_replace('/[^\d,]/', '', $amount);
	$a = explode('.', $a);
	$a = sprintf('%d%02d', $a[0], @$a[1]);
	return $a;
................................................................................
	return sprintf("%d,%02d", (int) ($a/100), (int) ($a%100));
}

function pos_money(?int $a): string {
	return $a === null ? '' : pos_amount($a) . '&nbsp;€';
}








$tpl->register_modifier('pos_money', __NAMESPACE__ . '\\pos_money');
$tpl->register_modifier('pos_amount', __NAMESPACE__ . '\\pos_amount');
$tpl->register_modifier('image_base64', function (string $blob) {
	return 'data:image/png;base64,' . base64_encode($blob);
});

$tpl->assign('plugin_css', ['style.css']);

Changes to caisse/www/admin/index.php.

1
2



3
4



<?php




require __DIR__ . '/_inc.php';






>
>
>


>
>
>
1
2
3
4
5
6
7
8
9
10
<?php

namespace Garradin;
use Garradin\Plugin\Caisse\Session;

require __DIR__ . '/_inc.php';

$tpl->assign('current_pos_session', Session::getCurrentId());
$tpl->assign('pos_sessions', Session::list());
$tpl->display(PLUGIN_ROOT . '/templates/index.tpl');

Changes to caisse/www/admin/pdf.php.

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
..
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

use Garradin\Plugin\Caisse\Tab;

require __DIR__ . '/_inc.php';

$tab = new Tab(qg('id'));

$tabs = Tab::listForSession($pos_session->id);
$current_tab = $tabs[qg('id')];

if ('' === trim($current_tab->name)) {
	throw new UserException('La note n\'a pas de nom associé : impossible de produire la facture');
}

if (!shell_exec('which chromium')) {
	die('Impossible de trouver Chromium');
}

$tpl->assign('tab', $current_tab);
$tpl->assign('items', $tab->listItems());
$tpl->assign('existing_payments', $tab->listPayments());
$remainder = $tab->getRemainder();
$options = $tab->listPaymentOptions();

foreach ($options as $k => &$option) {
	if ($option->id != 3) {
................................................................................
		unset($options[$k]);
		continue;
	}

	$eligible = $option->amount;
}

if (empty($eligible)) {
	throw new UserException('Rien n\'est éligible à Coup de pouce vélo');
}

$remainder_after = $remainder - $eligible;

$tpl->assign('remainder', $remainder);
$tpl->assign('remainder_after', $remainder_after);
$tpl->assign('payment_options', $options);

$tpl->register_modifier('show_methods', function ($m) {
................................................................................
	if (in_array(3, $m)) {
		return '<i>Oui</i>';
	}
});

$result = $tpl->fetch(PLUGIN_ROOT . '/templates/invoice.tpl');

//echo $result; exit;

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array('pipe', 'w'),
);

$cmd = 'prince -o - -';







<
<
<
|



|
|


|







 







<
<
<
<







 







<
<







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
..
42
43
44
45
46
47
48


49
50
51
52
53
54
55

use Garradin\Plugin\Caisse\Tab;

require __DIR__ . '/_inc.php';

$tab = new Tab(qg('id'));




if ('' === trim($tab->name)) {
	throw new UserException('La note n\'a pas de nom associé : impossible de produire la facture');
}

if (!shell_exec('which prince')) {
	die('Impossible de trouver Prince XML');
}

$tpl->assign('tab', $tab);
$tpl->assign('items', $tab->listItems());
$tpl->assign('existing_payments', $tab->listPayments());
$remainder = $tab->getRemainder();
$options = $tab->listPaymentOptions();

foreach ($options as $k => &$option) {
	if ($option->id != 3) {
................................................................................
		unset($options[$k]);
		continue;
	}

	$eligible = $option->amount;
}





$remainder_after = $remainder - $eligible;

$tpl->assign('remainder', $remainder);
$tpl->assign('remainder_after', $remainder_after);
$tpl->assign('payment_options', $options);

$tpl->register_modifier('show_methods', function ($m) {
................................................................................
	if (in_array(3, $m)) {
		return '<i>Oui</i>';
	}
});

$result = $tpl->fetch(PLUGIN_ROOT . '/templates/invoice.tpl');



$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array('pipe', 'w'),
);

$cmd = 'prince -o - -';

Changes to caisse/www/admin/session.php.

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

namespace Garradin;


use function Garradin\Plugin\Caisse\get_amount;

define('SESSION_CREATE', true);
require __DIR__ . '/_inc.php';

$s = new Plugin\Caisse\Session;








if (!empty($_POST['open'])) {
	$s->open($session->getUser()->id, get_amount(f('amount')));
	Utils::redirect(Utils::plugin_url(['file' => 'tab.php']));
}
elseif (!empty($_POST['close'])) {
	$s->close($pos_session->id);
}

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

if ($pos_session) {
	$tpl->assign('payments', $s->listPayments($pos_session->id));
	$tpl->assign('payments_totals', $s->listPaymentTotals($pos_session->id));
	$tpl->assign('tabs', $s->listTabsTotals($pos_session->id));




	$tpl->display(PLUGIN_ROOT . '/templates/session.tpl');
}
else {
	$tpl->display(PLUGIN_ROOT . '/templates/session_open.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
<?php

namespace Garradin;

use Garradin\Plugin\Caisse\Session;
use function Garradin\Plugin\Caisse\get_amount;

define('SESSION_CREATE', true);
require __DIR__ . '/_inc.php';

$pos_session = null;

if (null !== qg('id')) {
	$pos_session = new Session((int)qg('id'));
}
elseif ($current_pos_session = Session::getCurrentId()) {
	$pos_session = new Session($current_pos_session);
}

if (!empty($_POST['open'])) {
	Session::open($session->getUser()->id, get_amount(f('amount')));
	Utils::redirect(Utils::plugin_url(['file' => 'tab.php']));
}
elseif (!empty($_POST['close'])) {
	$pos_session->close(get_amount(f('amount')));
}

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

if ($pos_session) {
	$tpl->assign('payments', $pos_session->listPayments());
	$tpl->assign('payments_totals', $pos_session->listPaymentTotals());
	$tpl->assign('tabs', $pos_session->listTabsTotals());
	$tpl->assign('totals_categories', $pos_session->listTotalsByCategory());
	$tpl->assign('total', $pos_session->getTotal());

	$tpl->assign('title', 'Session de caisse du ' . Utils::sqliteDateToFrench($pos_session->opened));
	$tpl->display(PLUGIN_ROOT . '/templates/session.tpl');
}
else {
	$tpl->display(PLUGIN_ROOT . '/templates/session_open.tpl');
}

Changes to caisse/www/admin/style.css.

1
2
3
4
5
6
7
8
9
10
.pos {
	display: grid;
	grid-template-columns: 1fr 2fr;
	grid-column-gap: 1rem;
}

.pos header {
	display: flex;
	justify-content: space-between;
	margin-bottom: 1rem;


|







1
2
3
4
5
6
7
8
9
10
.pos {
	display: grid;
	grid-template-columns: 1fr 1fr;
	grid-column-gap: 1rem;
}

.pos header {
	display: flex;
	justify-content: space-between;
	margin-bottom: 1rem;

Changes to caisse/www/admin/tab.php.

1
2
3
4
5
6
7
8
9
10
11


12
13
14



15
16
17
18
19
20
21
..
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
<?php

namespace Garradin;

use Garradin\Plugin\Caisse\Tab;
use Garradin\Plugin\Caisse\Product;

use function Garradin\Plugin\Caisse\{reload,get_amount};

require __DIR__ . '/_inc.php';



if ($tab_id = $session->get('pos_tab_id')) {
	$tab = new Tab($tab_id);
}




if (!empty($_POST['add_item'])) {
	$tab->addItem((int)key($_POST['add_item']));
	reload();
}
elseif (qg('delete_item')) {
	$tab->removeItem((int)qg('delete_item'));
................................................................................
	reload();
}
elseif (qg('delete_payment')) {
	$tab->removePayment((int) qg('delete_payment'));
	reload();
}
elseif (null !== qg('new')) {
	$id = Tab::open($pos_session->id);
	$session->set('pos_tab_id', $id);
	reload();
}
elseif (!empty($_GET['change'])) {
	$session->set('pos_tab_id', (int) $_GET['change']);
	reload();
}
elseif (!empty($_POST['rename'])) {
	$tab->rename($_POST['rename']);
	reload();
}
elseif (!empty($_POST['close'])) {
	$tab->close();
	$remainder = $tab->getRemainder();
	$session->set('pos_tab_id', null);
	reload();
}
elseif (!empty($_POST['delete'])) {
	$tab->delete();
	$session->set('pos_tab_id', null);
	reload();
}

$tabs = Tab::listForSession($pos_session->id);

if ($tab_id && !isset($tabs[$tab_id])) {
	$tab_id = null;
	$session->set('pos_tab_id', null);
}

$tpl->assign('pos_session', $pos_session);
$tpl->assign('tab_id', $tab_id);

$tpl->assign('products_categories', Product::listByCategory());
$tpl->assign('tabs', $tabs);

if ($tab_id) {
	$tpl->assign('current_tab', $tabs[$tab_id]);
	$tpl->assign('items', $tab->listItems());
	$tpl->assign('existing_payments', $tab->listPayments());
	$tpl->assign('remainder', $tab->getRemainder());











	$tpl->assign('payment_options', $tab->listPaymentOptions());
}

$tpl->register_modifier('show_methods', function ($m) {
	$m = explode(',', $m);
	if (in_array(3, $m)) {
		return '<i>🚲</i>';
	}
});


$tpl->display(PLUGIN_ROOT . '/templates/tab.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
..
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
<?php

namespace Garradin;

use Garradin\Plugin\Caisse\{Session, Tab, Product};


use function Garradin\Plugin\Caisse\{reload,get_amount};

require __DIR__ . '/_inc.php';

$tab = $tab_id = null;

if ($tab_id = qg('id')) {
	$tab = new Tab($tab_id);
}

$current_pos_session = new Session($tab ? $tab->session : Session::getCurrentId());


if (!empty($_POST['add_item'])) {
	$tab->addItem((int)key($_POST['add_item']));
	reload();
}
elseif (qg('delete_item')) {
	$tab->removeItem((int)qg('delete_item'));
................................................................................
	reload();
}
elseif (qg('delete_payment')) {
	$tab->removePayment((int) qg('delete_payment'));
	reload();
}
elseif (null !== qg('new')) {
	$id = Tab::open($current_pos_session->id);
	Utils::redirect(Utils::plugin_url(['file' => 'tab.php', 'query' => 'id=' . $id]));





}
elseif (!empty($_POST['rename'])) {
	$tab->rename($_POST['rename']);
	reload();
}
elseif (!empty($_POST['close'])) {
	$tab->close();


	reload();
}
elseif (!empty($_POST['delete'])) {
	$tab->delete();
	Utils::redirect(Utils::plugin_url(['file' => 'tab.php']));

}

$tabs = Tab::listForSession($current_pos_session->id);






$tpl->assign('pos_session', $current_pos_session);
$tpl->assign('tab_id', $tab_id);

$tpl->assign('products_categories', Product::listByCategory());
$tpl->assign('tabs', $tabs);

if ($tab_id) {
	$tpl->assign('current_tab', $tabs[$tab_id]);
	$tpl->assign('items', $tab->listItems());
	$tpl->assign('existing_payments', $tab->listPayments());
	$tpl->assign('remainder', $tab->getRemainder());

	$options = $tab->listPaymentOptions();
	$eligible = 0;

	foreach ($options as $option) {
		if ($option->id == 3) {
			$eligible = $option->amount;
		}
	}

	$tpl->assign('eligible_alveole', $eligible);
	$tpl->assign('payment_options', $options);
}

$tpl->register_modifier('show_methods', function ($m) {
	$m = explode(',', $m);
	if (in_array(3, $m)) {
		return '<i>🚲</i>';
	}
});

$tpl->assign('title', 'Caisse ouverte le ' . Utils::sqliteDateToFrench($current_pos_session->opened));
$tpl->display(PLUGIN_ROOT . '/templates/tab.tpl');