Overview
Comment:Invoice module: invoice payment workflow implemented
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | invoice_module
Files: files | file ages | folders
SHA3-256: a2f5d4d43dffe955a47d34b8cf61fe83814c92229e31e72a5ec1faba06a2978d
User & Date: alinaar on 2023-03-10 17:02:31
Other Links: branch diff | manifest | tags
Context
2023-03-10
19:13
Invoice module: document actions externalized into a specific controller check-in: bd9b700573 user: alinaar tags: invoice_module
17:02
Invoice module: invoice payment workflow implemented check-in: a2f5d4d43d user: alinaar tags: invoice_module
2023-03-09
18:48
Invoice module: missing file check-in: fff802daac user: alinaar tags: invoice_module
Changes

Modified src/include/lib/Garradin/Utils.php from [d44975dab3] to [8cd5027b61].

300
301
302
303
304
305
306





307
308
309
310
311
312
313
        $uri = self::getSelfURI($qs);

        // Make absolute URI relative to parent URI
        if (strpos($uri, WWW_URI . 'admin/') === 0)
        {
            $uri = substr($uri, strlen(WWW_URI . 'admin/'));
        }






        return ADMIN_URL . ltrim($uri, '/');
    }

    static public function getSelfURI($qs = true)
    {
        $uri = self::getRequestURI();







>
>
>
>
>







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
        $uri = self::getSelfURI($qs);

        // Make absolute URI relative to parent URI
        if (strpos($uri, WWW_URI . 'admin/') === 0)
        {
            $uri = substr($uri, strlen(WWW_URI . 'admin/'));
        }

        // Quick-fix awaiting #227138842234710930f8c8d9bb9b7f9176ef3a0f resolution
        if (strpos($uri, '/m/') === 0) {
            return WWW_URL . ltrim($uri, '/');
        }

        return ADMIN_URL . ltrim($uri, '/');
    }

    static public function getSelfURI($qs = true)
    {
        $uri = self::getRequestURI();

Modified src/skel-dist/modules/invoice/details.html from [f0157b7a72] to [141a38eef1].

1
2
3
4
5
6
7
8
9
10
11
12
13
{{#restrict section="accounting" level="read"}}

{{* ==================== Header ==================== *}}

{{:admin_header title="Devis et factures" current="acc"}}
{{:include file='./include/constants.tpl' keep='DRAFT_STATUS, AWAITING_STATUS, VALIDATED_STATUS, REJECTED_STATUS, TYPE_LABELS, STATUS_LABELS, QUOTATION_TYPE, INVOICE_TYPE'}}

{{:include file='./include/style.tpl'}}

{{if $_GET.action === 'sign' || $_POST.signing_submit || $_GET.action === 'delete'}}
	{{#restrict block=true section="accounting" level="write"}}
		{{if !$_GET.id}}
			{{:assign var='check_errors.' value='Aucun devis sélectionné.'}}





|







1
2
3
4
5
6
7
8
9
10
11
12
13
{{#restrict section="accounting" level="read"}}

{{* ==================== Header ==================== *}}

{{:admin_header title="Devis et factures" current="acc"}}
{{:include file='./include/constants.tpl' keep='DRAFT_STATUS, AWAITING_STATUS, VALIDATED_STATUS, REJECTED_STATUS, PAID_STATUS, DOCUMENT_TYPES, TYPE_LABELS, STATUS_LABELS, INVOICE_STATUS_LABELS, QUOTATION_TYPE, INVOICE_TYPE, VERSION'}}

{{:include file='./include/style.tpl'}}

{{if $_GET.action === 'sign' || $_POST.signing_submit || $_GET.action === 'delete'}}
	{{#restrict block=true section="accounting" level="write"}}
		{{if !$_GET.id}}
			{{:assign var='check_errors.' value='Aucun devis sélectionné.'}}
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
						org_contact=$org_contact
						author_id=$author_id
						last_modification_date=$now|atom_date
						signing_place=$_POST.signing_place
						signing_date=$signing_date
						payment_detail=$payment_detail
						extra_info=$extra_info
						module_version=$module_version
					}}

					{{:http redirect="?id=%d&ok=1"|args:$id}}
				{{/if}}

			{{elseif $_GET.action === 'delete'}}
				{{* Awaiting {{:remove}} implementation #7de607eb3c7396d718da8575f61fd93951498936 *}}







|







54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
						org_contact=$org_contact
						author_id=$author_id
						last_modification_date=$now|atom_date
						signing_place=$_POST.signing_place
						signing_date=$signing_date
						payment_detail=$payment_detail
						extra_info=$extra_info
						module_version=$VERSION
					}}

					{{:http redirect="?id=%d&ok=1"|args:$id}}
				{{/if}}

			{{elseif $_GET.action === 'delete'}}
				{{* Awaiting {{:remove}} implementation #7de607eb3c7396d718da8575f61fd93951498936 *}}
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
						total=$total
						vat_exemption=$vat_exemption
						siret=$siret
						org_contact=$org_contact
						author_id=$logged_user.id|intval
						parent_id=$_GET.id|intval
						last_modification_date=$now|atom_date
						signing_place=null
						signing_date=$now|date:'Y-m-d'
						validation_date=null
						payment_detail=null
						extra_info=null
						module_version=$module_version
					}}
				{{/if}}

				{{:save id=$_GET.id|intval
					validate_schema="./schema/quotation.json"
					key=$key
					type=$type







|




|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
						total=$total
						vat_exemption=$vat_exemption
						siret=$siret
						org_contact=$org_contact
						author_id=$logged_user.id|intval
						parent_id=$_GET.id|intval
						last_modification_date=$now|atom_date
						signing_place=$signing_place
						signing_date=$now|date:'Y-m-d'
						validation_date=null
						payment_detail=null
						extra_info=null
						module_version=$VERSION
					}}
				{{/if}}

				{{:save id=$_GET.id|intval
					validate_schema="./schema/quotation.json"
					key=$key
					type=$type
146
147
148
149
150
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165





166

























































167
168
169
170
171
172
173
174
175
176




177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195

196
197
198




199
200

201
202
203
204

205
206
207
208
209
210
211
					total=$total
					vat_exemption=$vat_exemption
					siret=$siret
					org_contact=$org_contact
					author_id=$author_id
					child_id=$invoice_id|intval
					last_modification_date=$now|atom_date
					signing_place=$_POST.signing_place
					signing_date=$signing_date
					validation_date=$validation_date
					payment_detail=$payment_detail
					extra_info=$extra_info

					module_version=$module_version
				}}

				{{:http redirect="?id=%d&ok=%d"|args:$id:$redirection_code}}
			{{/if}}
			{{/load}}
		{{/if}}
	{{/restrict}}





{{/if}}

























































{{if $_POST.status_update_button}} {{* Only for developers *}}
	{{#restrict block=true section="accounting" level="write"}}
		{{if !$_POST.id}}
			{{:error message='Aucun devis sélectionné.'}}
		{{else}}
			{{:assign var='new_status_label' from='STATUS_LABELS.%s'|args:$_POST.status}}
			{{if $new_status_label === null}}
				{{:assign var='check_errors.' value='Nouveau statut invalide : %s.'|args:$_POST.status}}
			{{else}}
				{{#load id=$_POST.id|intval}}




					{{:save id=$id
						validate_schema="./schema/quotation.json"
						key=$key
						type=$type
						recipient_business_name=$recipient_business_name
						recipient_address=$recipient_address
						recipient_member_id=$recipient_member_id
						recipient_member_numero=$recipient_member_numero
						introduction_text=$introduction_text
						subject=$subject
						date=$date
						deadline=$deadline
						status=$_POST.status
						items=$items
						total=$total
						vat_exemption=$vat_exemption
						siret=$siret
						org_contact=$org_contact
						author_id=$author_id

						last_modification_date=$now|atom_date
						signing_place=$signing_place
						signing_date=$signing_date




						payment_detail=$payment_detail
						extra_info=$extra_info

						module_version=$module_version
					}}

					{{:http redirect="?id=%d&ok=2&show=quotation"|args:$id}}

				{{/load}}
			{{/if}}
			{{#foreach from=$check_errors item='error'}}
				<p class="error block">{{$error}}</p>
			{{/foreach}}
		{{/if}}
	{{/restrict}}







|




>
|







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





|




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

|
>







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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
285
					total=$total
					vat_exemption=$vat_exemption
					siret=$siret
					org_contact=$org_contact
					author_id=$author_id
					child_id=$invoice_id|intval
					last_modification_date=$now|atom_date
					signing_place=$signing_place
					signing_date=$signing_date
					validation_date=$validation_date
					payment_detail=$payment_detail
					extra_info=$extra_info
					parent_id=$_GET.id|intval
					module_version=$VERSION
				}}

				{{:http redirect="?id=%d&ok=%d"|args:$id:$redirection_code}}
			{{/if}}
			{{/load}}
		{{/if}}
	{{/restrict}}
{{elseif $_POST.mark_as_paid_submit}}
	{{#restrict block=true section="accounting" level="write"}}
	{{#load id=$_GET.id|intval}}{{:assign .='invoice'}}{{/load}}
	{{if $invoice.status !== $AWAITING_STATUS}}
		{{:assign var='check_errors.' value='Seuls les factures "en attente de validation" peuvent être payées.'}}
	{{/if}}

	{{:assign date=$_POST.date|date:'Y-m-d'}}
	{{if !$_POST.date}}
		{{:assign var='check_errors.' value="La date est obligatoire."}}
	{{/if}}
	{{if $_POST.date|parse_date === null}} {{* Means data is not a date *}}
		{{:assign var='check_errors.' value="La date du paiement doit être une date."}}
	{{/if}}
	{{if $date < $invoice.date}}
		{{:assign formatted_invoice_date=$invoice.date|date_short}}
		{{:assign var='check_errors.' value="Le paiement doit se situer après la date d'émission de la facture (%s)."|args:$formatted_invoice_date}}
	{{/if}}
	
	{{:include file='./include/check_max_length.tpl' check_value=$_POST.comment check_max=256 check_label='Remarques trop longues' keep='check_errors'}}

	{{:include file='./include/shim/array_last_num_key.tpl' keep='transaction_id, check_errors' array=$_POST.transaction name='transaction_id' error_message='Écriture séléctionnée invalide.'}}
	{{#transactions id=$transaction_id|intval}}{{:assign .='transaction'}}{{/transactions}}
	{{if $transaction_id && !$transaction}}
		{{:assign var='check_errors.' value="Transaction sélectionnée invalide."}}
	{{/if}}

	{{if !$check_errors}}
		{{:save id=$invoice.id|intval
			validate_schema="./schema/invoice.json"
			key=$invoice.key
			type=$invoice.type
			recipient_business_name=$invoice.recipient_business_name
			recipient_address=$invoice.recipient_address
			recipient_member_id=$invoice.recipient_member_id
			recipient_member_numero=$invoice.recipient_member_numero
			introduction_text=null
			subject=$invoice.subject
			date=$invoice.date
			deadline=null
			status=$PAID_STATUS
			items=$invoice.items
			total=$invoice.total
			vat_exemption=$invoice.vat_exemption
			siret=$invoice.siret
			org_contact=$invoice.org_contact
			author_id=$invoice.author_id
			parent_id=$invoice.parent_id
			last_modification_date=$now|atom_date
			signing_place=null
			signing_date=$invoice.signing_date
			validation_date=null
			payment_date=$date
			payment_comment=$_POST.comment
			transaction_id=$transaction.id|intval
			payment_detail=null
			extra_info=null
			module_version=$VERSION
		}}
		{{:http redirect="?id=%d&ok=6&show=invoice"|args:$invoice.id}}
	{{/if}}
	{{/restrict}}
{{/if}}
{{if $_POST.status_update_button}} {{* Only for developers *}}
	{{#restrict block=true section="accounting" level="write"}}
		{{if !$_POST.id}}
			{{:error message='Aucun devis sélectionné.'}}
		{{else}}
			{{:assign var='new_status_label' from='INVOICE_STATUS_LABELS.%s'|args:$_POST.status}}
			{{if $new_status_label === null}}
				{{:assign var='check_errors.' value='Nouveau statut invalide : %s.'|args:$_POST.status}}
			{{else}}
				{{#load id=$_POST.id|intval}}
					{{:assign var='allowed_type' from='DOCUMENT_TYPES.%s'|args:$type}}
					{{if !$allowed_type}}
						{{:assign var='check_errors.' value='Type invalide : %s!'|args:$type}}
					{{else}}
						{{:save id=$id
							validate_schema="./schema/%s.json"|args:$type
							key=$key
							type=$type
							recipient_business_name=$recipient_business_name
							recipient_address=$recipient_address
							recipient_member_id=$recipient_member_id
							recipient_member_numero=$recipient_member_numero
							introduction_text=$introduction_text
							subject=$subject
							date=$date
							deadline=$deadline
							status=$_POST.status
							items=$items
							total=$total
							vat_exemption=$vat_exemption
							siret=$siret
							org_contact=$org_contact
							author_id=$author_id
							parent_id=$parent_id
							last_modification_date=$now|atom_date
							signing_place=$signing_place
							signing_date=$signing_date
							validation_date=$validation_date
							payment_date=$payment_date
							payment_comment=$payment_comment
							transaction_id=$transaction_id
							payment_detail=$payment_detail
							extra_info=$extra_info
							parent_id=$parent_id
							module_version=$VERSION
						}}

						{{:http redirect="?id=%d&ok=2&show=quotation"|args:$id}}
					{{/if}}
				{{/load}}
			{{/if}}
			{{#foreach from=$check_errors item='error'}}
				<p class="error block">{{$error}}</p>
			{{/foreach}}
		{{/if}}
	{{/restrict}}
251
252
253
254
255
256
257
258
259


260
261
262
263
264
265
266
267




268
269
270
271
272



273

274
275
276
277
278
279
280
				</ul>
			</aside>
			{{:include file='./include/main_nav_tabs.html'}}
		</nav>

		{{* ======================= Feedback =========================== *}}

		{{if $_GET.ok === '1'}}
			<p class="block confirm">Devis signé avec succès.</p>


		{{elseif $_GET.ok === '2'}}
			<p class="block confirm">Modification enregistrée.</p>
		{{elseif $_GET.ok === '3'}}
			<p class="block confirm">Brouillon conservé.</p>
		{{elseif $_GET.ok === '4'}}
			<p class="block confirm">Devis marqué avec succès comme refusé.</p>
		{{elseif $_GET.ok === '5'}}
			<p class="block confirm">Devis marqué avec succès comme validé.</p>




		{{/if}}

		{{* ======================= Title =========================== *}}

		{{:assign var="label" from="TYPE_LABELS.%s"|args:$type}}



		{{:assign var="status_label" from="STATUS_LABELS.%s"|args:$status}}

		<h1>{{$label}} n° {{$key}} - {{$status_label}}</h1>

		{{* ======================= Errors =========================== *}}

		{{if $check_errors}}
			{{#foreach from=$check_errors item='error'}}
				<p class="error block">{{$error}}</p>







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





>
>
>
|
>







325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
				</ul>
			</aside>
			{{:include file='./include/main_nav_tabs.html'}}
		</nav>

		{{* ======================= Feedback =========================== *}}

		{{if $_GET.ok}}
			<p class="block confirm">
			{{if $_GET.ok === '1'}}
				Devis signé avec succès.
			{{elseif $_GET.ok === '2'}}
				Modification enregistrée.
			{{elseif $_GET.ok === '3'}}
				Brouillon conservé.
			{{elseif $_GET.ok === '4'}}
				Devis marqué avec succès comme refusé.
			{{elseif $_GET.ok === '5'}}
				Devis marqué avec succès comme validé.
			{{elseif $_GET.ok === '6'}}
				Facture marquée avec succès comme payée.
			{{/if}}
			</p>
		{{/if}}

		{{* ======================= Title =========================== *}}

		{{:assign var="label" from="TYPE_LABELS.%s"|args:$type}}
		{{if $type === $INVOICE_TYPE}}
			{{:assign var="status_label" from="INVOICE_STATUS_LABELS.%s"|args:$status}}
		{{else}}
			{{:assign var="status_label" from="STATUS_LABELS.%s"|args:$status}}
		{{/if}}
		<h1>{{$label}} n° {{$key}} - {{$status_label}}</h1>

		{{* ======================= Errors =========================== *}}

		{{if $check_errors}}
			{{#foreach from=$check_errors item='error'}}
				<p class="error block">{{$error}}</p>
325
326
327
328
329
330
331












332
333
334
335
336
337

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356

357
358
359
360
361
362















363
364
365






366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
					<legend>Validation du devis par le/la client.e</legend>
					{{if !$check_errors}}<p class="error block">Valider le devis est définitif. Vous ne pourrez pas rétablir le devis comme "en attente de validation".<br />Il sera néanmoins possible d'annuler le devis.</p>{{/if}}
					<div class="infos">{{:input type="checkbox" name="invoice" value="1" label="Générer automatiquement une facture"}}</div>
					{{:button type="submit" name="validate_submit" label="Marquer comme validé" shape="check" class="main"}}
				</fieldset>
			</form>
			<h2 class="ruler">Rappel</h2>












		{{/if}}

		{{* ======================= Content =========================== *}}

		<fieldset>
			<legend><h2>Informations</h2></legend>

			{{if $status === $AWAITING_STATUS}}
				<p class="infos">{{$label}} <strong>{{if $type === $QUOTATION_TYPE}}signé{{else}}signée{{/if}} le {{$signing_date|date_short}} à {{$signing_place}}</strong>.</p>
				{{if $type === $INVOICE_TYPE && $parent_id}}
					{{#load id=$parent_id}}{{:assign .='parent'}}{{/load}}
					<p class="infos">Correspondant au {{:link href="details.html?id=%d&show=quotation"|args:$parent.id label="devis n°%s"|args:$parent.key}}.</p>
				{{/if}}
				{{if $type === $QUOTATION_TYPE}}
					<p class="">En attente de validation par le/la client.e.</p>
					<p class="infos">
						{{:linkbutton href="?id=%d&show=quotation&action=ask_validation"|args:$id label="Marquer comme validé et générer la facture" shape="check"}}
						{{:linkbutton href="?id=%d&show=quotation&action=ask_rejection"|args:$id label="Marquer comme refusé" shape="alert"}}
					</p>
				{{else}}
					<p class="">En attente de paiement.</p>
					<p class="infos">
						{{:linkbutton href="#"|args:$id label="Marquer comme payée (prochainement)" shape="check"}}
						{{* {{:linkbutton href="?id=%d&show=quotation&action=ask_rejection"|args:$id label="Marquer comme abandonnée" shape="alert"}} *}}
					</p>
				{{/if}}

			{{elseif $status === $VALIDATED_STATUS}}
				<p class="infos">{{$label}} <strong>validé le {{$validation_date|date_short}}</strong> (signé par l'asso le {{$signing_date|date_short}}).</p>
				{{if $type === $QUOTATION_TYPE}}
					{{#load id=$child_id|intval}}{{:assign .='child'}}{{/load}}
					<p class="infos">Facture correspondante : {{:link href="?id=%d&show=invoice"|args:$child.id label="n°%s"|args:$child.key}}.</p>
				{{/if}}















			{{else}}
				<p class="infos">Statut en cours : {{$status_label}}</p>
			{{/if}}






			{{#users id=$author_id|intval}}{{:assign .='author'}}{{/users}}
			<p>
				{{if $type === $QUOTATION_TYPE}}Rédigé{{else}}Rédigée{{/if}} par : {{:link href="!users/details.php?id=%d"|args:$author.id label=$author.nom}}.
			</p>
			<p>
				Dernière modification : {{$last_modification_date}}.
			</p>
		</fieldset>

		<fieldset>
			<legend><h2>Destinataire</h2></legend>
			<p class="infos">
				<strong>{{$recipient_business_name}}</strong><br />
				{{$recipient_address|escape|nl2br}}
			</p>
			{{if $recipient_member_id}}
				{{#users id=$recipient_member_id|intval}}{{:assign .='member'}}{{/users}}
				{{if !$member}}
					<p class="infos">Associé à l'ancien.ne membre {{if $recipient_member_numero}}n°{{$recipient_member_numero}}{{else}}#{{$recipient_member_id}}{{/if}} (compte supprimé).</p>
				{{else}}







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






>

|
<
<
<
<









|



>


|



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



>
>
>
>
>
>












|







409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436




437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
					<legend>Validation du devis par le/la client.e</legend>
					{{if !$check_errors}}<p class="error block">Valider le devis est définitif. Vous ne pourrez pas rétablir le devis comme "en attente de validation".<br />Il sera néanmoins possible d'annuler le devis.</p>{{/if}}
					<div class="infos">{{:input type="checkbox" name="invoice" value="1" label="Générer automatiquement une facture"}}</div>
					{{:button type="submit" name="validate_submit" label="Marquer comme validé" shape="check" class="main"}}
				</fieldset>
			</form>
			<h2 class="ruler">Rappel</h2>
		{{elseif $_GET.action === 'ask_mark_as_paid'}}
			<form method="POST" action="">
				<fieldset>
					<legend>Marquer la facture comme payée</legend>
					{{if !$check_errors}}<p class="error block">Marquer la facture comme payée est définitif. Vous ne pourrez pas rétablir la facture comme "en attente de paiement".<br />Il sera néanmoins possible d''annuler la facture.</p>{{/if}}
					{{:input type="date" name="date" label="Date du paiement" default=$now required=true}}
					{{:input type="textarea" name="comment" label="Remarque" required=false cols="50" rows="4"}}
					{{:input type="list" name="transaction" label="Écriture correspondante" target="./transaction_selector.inc.tpl" can_delete=true required=false}}
					{{:button type="submit" name="mark_as_paid_submit" label="Marquer comme payée" shape="check" class="main"}}
				</fieldset>
			</form>
			<h2 class="ruler">Rappel</h2>
		{{/if}}

		{{* ======================= Content =========================== *}}

		<fieldset>
			<legend><h2>Informations</h2></legend>
			
			{{if $status === $AWAITING_STATUS}}
				<p class="infos">{{$label}} <strong>{{if $type === $QUOTATION_TYPE}}signé{{else}}émise{{/if}} le {{$signing_date|date_short}} à {{$signing_place}}</strong>.</p>




				{{if $type === $QUOTATION_TYPE}}
					<p class="">En attente de validation par le/la client.e.</p>
					<p class="infos">
						{{:linkbutton href="?id=%d&show=quotation&action=ask_validation"|args:$id label="Marquer comme validé et générer la facture" shape="check"}}
						{{:linkbutton href="?id=%d&show=quotation&action=ask_rejection"|args:$id label="Marquer comme refusé" shape="alert"}}
					</p>
				{{else}}
					<p class="">En attente de paiement.</p>
					<p class="infos">
						{{:linkbutton href="?id=%d&show=invoice&action=ask_mark_as_paid"|args:$id label="Marquer comme payée" shape="check"}}
						{{* {{:linkbutton href="?id=%d&show=quotation&action=ask_rejection"|args:$id label="Marquer comme abandonnée" shape="alert"}} *}}
					</p>
				{{/if}}

			{{elseif $status === $VALIDATED_STATUS}}
				<p class="infos">{{$label}} <strong>validé le {{$validation_date|date_short}}</strong> (signé par l'asso le {{$signing_date|date_short}}).</p>
				{{if $type === $QUOTATION_TYPE && $child_id}}
					{{#load id=$child_id|intval}}{{:assign .='child'}}{{/load}}
					<p class="infos">Facture correspondante : {{:link href="?id=%d&show=invoice"|args:$child.id label="n°%s"|args:$child.key}}.</p>
				{{/if}}

			{{elseif $status === $PAID_STATUS}}
				<p class="infos">{{$label}} <strong>payée le {{$payment_date|date_short}}</strong> (émise par l'asso le {{$signing_date|date_short}}).</p>
				{{if $payment_comment}}
					<h4>Remarques :</h4>
					<p class="infos">{{$payment_comment|escape|nl2br}}</p>
				{{/if}}
				{{if $transaction_id}}
					{{#transactions id=$transaction_id|intval}}
						<p class="infos">Écriture comptable correspondante : {{:link href='!acc/transactions/details.php?id=%d'|args:$id label='n°%d - %s'|args:$id:$label}}.</p>
					{{/transactions}}
				{{else}}
					<p class="infos">Aucune écriture comptable correspondante. {{:linkbutton href="#" label="Associer (prochainement)" shape="right"}}</p>
				{{/if}}

			{{else}}
				<p class="infos">Statut en cours : {{$status_label}}</p>
			{{/if}}

			{{if $type === $INVOICE_TYPE && $parent_id}}
				{{#load id=$parent_id}}{{:assign .='parent'}}{{/load}}
				<p class="infos">Correspondant au {{:link href="details.html?id=%d&show=quotation"|args:$parent.id label="devis n°%s"|args:$parent.key}}.</p>
			{{/if}}

			{{#users id=$author_id|intval}}{{:assign .='author'}}{{/users}}
			<p>
				{{if $type === $QUOTATION_TYPE}}Rédigé{{else}}Rédigée{{/if}} par : {{:link href="!users/details.php?id=%d"|args:$author.id label=$author.nom}}.
			</p>
			<p>
				Dernière modification : {{$last_modification_date}}.
			</p>
		</fieldset>

		<fieldset>
			<legend><h2>Destinataire</h2></legend>
			<p class="infos">
				<strong class="business_name">{{$recipient_business_name}}</strong><br />
				{{$recipient_address|escape|nl2br}}
			</p>
			{{if $recipient_member_id}}
				{{#users id=$recipient_member_id|intval}}{{:assign .='member'}}{{/users}}
				{{if !$member}}
					<p class="infos">Associé à l'ancien.ne membre {{if $recipient_member_numero}}n°{{$recipient_member_numero}}{{else}}#{{$recipient_member_id}}{{/if}} (compte supprimé).</p>
				{{else}}
453
454
455
456
457
458
459

460
461
462
463
464
465
466
467
		{{#restrict section="config" level="admin"}}
		<div style="background-color: black; color: limegreen; padding: 1em;">
		<fieldset style="border-color: limegreen;">
			<legend><h2 style="color: limegreen;">Outils développeur/euse</h2></legend>
			<div class="infos inline">
				<label for="f_status">Statut en cours :</label>
				<form method="POST" action="./details.html" style="display: inline;">

					{{:input type="select" name="status" options=$STATUS_LABELS default=$status required=true}}
					{{:input type="hidden" name="id" default=$id|intval}}
					{{:button type="submit" name="status_update_button" label="Modifier"}}
				</form>
			</div>
		</fieldset>
		</div>
		{{/restrict}}







>
|







568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
		{{#restrict section="config" level="admin"}}
		<div style="background-color: black; color: limegreen; padding: 1em;">
		<fieldset style="border-color: limegreen;">
			<legend><h2 style="color: limegreen;">Outils développeur/euse</h2></legend>
			<div class="infos inline">
				<label for="f_status">Statut en cours :</label>
				<form method="POST" action="./details.html" style="display: inline;">
				{{if $type === $INVOICE_TYPE}}{{:assign options=$INVOICE_STATUS_LABELS}}{{else}}{{:assign options=$STATUS_LABELS}}{{/if}}
					{{:input type="select" name="status" options=$options default=$status required=true}}
					{{:input type="hidden" name="id" default=$id|intval}}
					{{:button type="submit" name="status_update_button" label="Modifier"}}
				</form>
			</div>
		</fieldset>
		</div>
		{{/restrict}}

Modified src/skel-dist/modules/invoice/edit.html from [c86d6286fb] to [b0a4d45aff].

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{{/if}}

{{if $_POST.quotation_submit}}
	{{:assign computed_total=0}}
	{{:assign check_errors=null}}
	{{:assign items=null}}

	{{* Hack to get the unique element since "$my_array|keys" and "$my_array|first" do not exist *}}
	{{#foreach from=$_POST.customer key='id' item='name'}}
		{{if $id != $id|intval|strval}} {{* Hack to check the data is a number *}}
			{{:assign var='check_errors.' value='Membre séléctionné invalide.'}}
		{{/if}}
		{{:assign customer_id=$id|intval}}
	{{/foreach}}
	{{if $customer_id !== null}}
		{{#users id=$customer_id}}
			{{:assign recipient_member_id=$id}}
			{{:assign recipient_member_numero=$numero|strval}}
			{{:assign recipient_business_name=$nom}}
			{{if $adresse}}{{:assign recipient_address=$adresse|cat:"\n":$code_postal:' ':$ville}}{{/if}}
		{{/users}}







<
<
<
|
|
<
<







22
23
24
25
26
27
28



29
30


31
32
33
34
35
36
37
{{/if}}

{{if $_POST.quotation_submit}}
	{{:assign computed_total=0}}
	{{:assign check_errors=null}}
	{{:assign items=null}}




	{{:include file='./include/shim/array_last_num_key.tpl' keep='customer_id, check_errors' array=$_POST.customer name='customer_id' error_message='Membre séléctionné invalide.'}}
	


	{{if $customer_id !== null}}
		{{#users id=$customer_id}}
			{{:assign recipient_member_id=$id}}
			{{:assign recipient_member_numero=$numero|strval}}
			{{:assign recipient_business_name=$nom}}
			{{if $adresse}}{{:assign recipient_address=$adresse|cat:"\n":$code_postal:' ':$ville}}{{/if}}
		{{/users}}

Modified src/skel-dist/modules/invoice/include/constants.tpl from [279321afab] to [f029d9cc20].

1
2
3


4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

20
21
22
23
{{:assign VERSION='0.2'}}
{{:assign DRAFT_STATUS='draft' AWAITING_STATUS='awaiting' REJECTED_STATUS='rejected' VALIDATED_STATUS='validated' MISC_STATUS='misc'}}
{{:assign QUOTATION_TYPE='quotation' INVOICE_TYPE='invoice'}}


{{:assign NONPROFIT_VAT_EXEMPTION_TYPE='nonprofit' PROFIT_VAT_EXEMPTION_TYPE='profit'}}

{{* Labels *}}
{{:assign var='TYPE_LABELS.%s'|args:$QUOTATION_TYPE value='Devis'}}
{{:assign var='TYPE_LABELS.%s'|args:$INVOICE_TYPE value='Facture'}}

{{:assign var='STATUS_LABELS.%s'|args:$DRAFT_STATUS value='Brouillon'}}
{{:assign var='STATUS_LABELS.%s'|args:$AWAITING_STATUS value='En attente de validation'}}
{{:assign var='STATUS_LABELS.%s'|args:$REJECTED_STATUS value='Rejeté'}}
{{:assign var='STATUS_LABELS.%s'|args:$VALIDATED_STATUS value='Validé'}}
{{:assign var='STATUS_LABELS.%s'|args:$MISC_STATUS value='Autre'}}

{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$DRAFT_STATUS value='Brouillon'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$AWAITING_STATUS value='En attente de paiement'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$REJECTED_STATUS value='Rejeté'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$VALIDATED_STATUS value='Validé'}}

{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$MISC_STATUS value='Autre'}}

{{:assign var='VAT_EXEMPTION_TYPE_LABELS.%s'|args:$NONPROFIT_VAT_EXEMPTION_TYPE value='Non-lucratif'}}
{{:assign var='VAT_EXEMPTION_TYPE_LABELS.%s'|args:$PROFIT_VAT_EXEMPTION_TYPE value='Lucratif'}}

|

>
>








|





|
|
>




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
{{:assign VERSION='0.2'}}
{{:assign DRAFT_STATUS='draft' AWAITING_STATUS='awaiting' REJECTED_STATUS='rejected' VALIDATED_STATUS='validated' PAID_STATUS='paid' MISC_STATUS='misc'}}
{{:assign QUOTATION_TYPE='quotation' INVOICE_TYPE='invoice'}}
{{:assign var='DOCUMENT_TYPES.%s'|args:$QUOTATION_TYPE value='Devis'}}
{{:assign var='DOCUMENT_TYPES.%s'|args:$INVOICE_TYPE value='Facture'}}
{{:assign NONPROFIT_VAT_EXEMPTION_TYPE='nonprofit' PROFIT_VAT_EXEMPTION_TYPE='profit'}}

{{* Labels *}}
{{:assign var='TYPE_LABELS.%s'|args:$QUOTATION_TYPE value='Devis'}}
{{:assign var='TYPE_LABELS.%s'|args:$INVOICE_TYPE value='Facture'}}

{{:assign var='STATUS_LABELS.%s'|args:$DRAFT_STATUS value='Brouillon'}}
{{:assign var='STATUS_LABELS.%s'|args:$AWAITING_STATUS value='En attente de validation'}}
{{:assign var='STATUS_LABELS.%s'|args:$REJECTED_STATUS value='Refusé'}}
{{:assign var='STATUS_LABELS.%s'|args:$VALIDATED_STATUS value='Validé'}}
{{:assign var='STATUS_LABELS.%s'|args:$MISC_STATUS value='Autre'}}

{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$DRAFT_STATUS value='Brouillon'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$AWAITING_STATUS value='En attente de paiement'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$REJECTED_STATUS value='Rejetée'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$VALIDATED_STATUS value='Validée'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$PAID_STATUS value='Payée'}}
{{:assign var='INVOICE_STATUS_LABELS.%s'|args:$MISC_STATUS value='Autre'}}

{{:assign var='VAT_EXEMPTION_TYPE_LABELS.%s'|args:$NONPROFIT_VAT_EXEMPTION_TYPE value='Non-lucratif'}}
{{:assign var='VAT_EXEMPTION_TYPE_LABELS.%s'|args:$PROFIT_VAT_EXEMPTION_TYPE value='Lucratif'}}

Modified src/skel-dist/modules/invoice/include/main_nav_tabs.html from [2a79f0f2e9] to [bf0a2dc64e].

1
2
3
4
5
6
7
8
9
10
<ul>
	<li{{if !$_GET.show}} class="current"{{/if}}>{{:link href="./" label="Tous les documents"}}</li>
	<li{{if $_GET.show == 'quotation'}} class="current"{{/if}}>{{:link href="./?show=quotation" label="Devis"}}</li>
	<li{{if $_GET.show == 'invoice'}} class="current"{{/if}}><a href="#" title="Prochainement" style="text-decoration: line-through;">Fact. en souff.</a></li>
	<li{{if $_GET.show == 'paid'}} class="current"{{/if}}><a href="#" title="Prochainement" style="text-decoration: line-through;">Fact. réglées</a></li>
	<li{{if $_GET.show == 'customers'}} class="current"{{/if}}>{{:link href="./customers.html?show=customers" label="Clients"}}</li>
	{{#restrict section='config' level='admin'}}
		<li{{if $_GET.show == 'config'}} class="current"{{/if}}>{{:link href="./config.html?show=config" label="Configuration"}}</li>
	{{/restrict}}
</ul>



|
|





1
2
3
4
5
6
7
8
9
10
<ul>
	<li{{if !$_GET.show}} class="current"{{/if}}>{{:link href="./" label="Tous les documents"}}</li>
	<li{{if $_GET.show == 'quotation'}} class="current"{{/if}}>{{:link href="./?show=quotation" label="Devis"}}</li>
	<li{{if $_GET.show == 'unpaid'}} class="current"{{/if}}>{{:link href="./?show=unpaid" label="Fact. en souff."}}</li>
	<li{{if $_GET.show == 'paid'}} class="current"{{/if}}>{{:link href="./?show=paid" label="Fact. réglées"}}</li>
	<li{{if $_GET.show == 'customers'}} class="current"{{/if}}>{{:link href="./customers.html?show=customers" label="Clients"}}</li>
	{{#restrict section='config' level='admin'}}
		<li{{if $_GET.show == 'config'}} class="current"{{/if}}>{{:link href="./config.html?show=config" label="Configuration"}}</li>
	{{/restrict}}
</ul>

Added src/skel-dist/modules/invoice/include/preview_style.tpl version [d9d19a0772].





















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
<style>
h2.organization_name {
	margin-bottom: 0;
}

.organization_name, .business_name, .signing_place {
	text-transform: uppercase;
}

ul.organization_details, ul.customer_details, ul.document_details {
	list-style-type: none;
}

ul.customer_details {
	text-align: right;
}

td.number {
	text-align: right;
}

td.total {
	font-weight: bold;
	text-align: right;
}
</style>

Added src/skel-dist/modules/invoice/include/shim/array_last_num_key.tpl version [1647c231b9].















>
>
>
>
>
>
>
1
2
3
4
5
6
7
{{* Hack to get the unique element since "$my_array|keys" and "$my_array|first" do not exist *}}
{{#foreach from=$array key='id' item='item'}}
	{{if $id != $id|intval|strval}} {{* Hack to check the data is a number *}}
		{{:assign var='check_errors.' value=$error_message}}
	{{/if}}
	{{:assign var=$name value=$id|intval}}
{{/foreach}}

Modified src/skel-dist/modules/invoice/include/style.tpl from [e8a4fd0788] to [1e09546159].

17
18
19
20
21
22
23




24
25
26
27
28
29
30
	color: red;
	font-weight: bold;
}

.safe, .safe span {
	font-weight: bold;
}





nav.tabs aside.menu ul {
	border: 0;
}

nav.tabs aside.menu li {
	margin: 0;







>
>
>
>







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	color: red;
	font-weight: bold;
}

.safe, .safe span {
	font-weight: bold;
}

.organization_name, .business_name, .signing_place {
	text-transform: uppercase;
}

nav.tabs aside.menu ul {
	border: 0;
}

nav.tabs aside.menu li {
	margin: 0;

Modified src/skel-dist/modules/invoice/index.html from [fe4de32ad8] to [a98e18125d].

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

{{* ==================== Listing ==================== *}}

{{if $_GET.q}}
	<h2 class="ruler">Résultat(s) de recherche pour "{{$_GET.q}}"</h2>
{{/if}}

{{:include file='./include/constants.tpl' keep='DRAFT_STATUS, VALIDATED_STATUS, TYPE_LABELS, STATUS_LABELS, QUOTATION_TYPE, INVOICE_TYPE, INVOICE_STATUS_LABELS'}}

{{if $_GET.show == $QUOTATION_TYPE}}
	{{:assign filter="json_extract(document, '$.type') = '%s'"|args:$QUOTATION_TYPE}}
{{elseif $_GET.show == 'paid'}}
	{{:assign filter="json_extract(document, '$.type') = 'invoice' AND json_extract(document, '$.date_paid') IS NOT NULL"}}
{{elseif $_GET.show == 'unpaid'}}
	{{:assign filter="json_extract(document, '$.type') = 'invoice' AND json_extract(document, '$.date_paid') IS NULL"}}
{{else}}
	{{:assign filter="1"}}
{{/if}}

{{if $_GET.ok === '1'}}
	<p class="block confirm">Devis enregistré.</p>
{{elseif $_GET.ok === '2'}}
	<p class="block confirm">Devis modifié avec succès.</p>
{{elseif $_GET.ok === '4'}}
	<p class="block confirm">Devis supprimé avec succès.</p>
{{/if}}


{{:assign list_select="key; id AS 'Numéro'; datetime($$.date) AS 'Émission'; $$.deadline AS 'Échéance'; $$.recipient_business_name AS 'Tiers'; $$.subject AS 'Intitulé'; $$.total AS 'Montant'; $$.status AS 'Statut'"}}
{{:assign list_where="$$.type IN ('quotation', 'invoice') AND %s"|args:$filter}}
{{:assign list_order=2}}
{{if !$_GET.show}}{{:assign list_select='$$.type AS "Type"; '|cat:$list_select}}{{:assign list_order=3}}{{/if}}
{{if $_GET.q}}{{:assign list_where=$list_where|cat:' AND ':$search_where}}{{/if}}
{{#list
	select=$list_select
	where=$list_where
	order=$list_order

	:searched_id=$searched_id
	:searched_date=$searched_date
	:searched_text=$searched_text


}}
	<tr>
		{{if !$_GET.show}}
			{{:assign var="label" from="TYPE_LABELS.%s"|args:$type}}




			<td>{{$label}}</td>

		{{/if}}
		<td>{{:link href="details.html?id=%d&show=%s"|args:$id:$type label=$key}}</td>
		<td>{{$date|date_short}}</td>
		<td>{{$deadline|date_short}}</td>
		<td>{{$recipient_business_name}}</td>
		<td>{{:link href="details.html?id=%d&show=%s"|args:$id:$type label=$subject}}</td>
		<td class="money">{{$total|money_currency}}</td>
		<td>
			{{if $type === $INVOICE_TYPE}}
				{{:assign var="label" from="INVOICE_STATUS_LABELS.%s"|args:$status}}
			{{else}}
				{{:assign var="label" from="STATUS_LABELS.%s"|args:$status}}
			{{/if}}

			{{$label}}
			{{if $status === $VALIDATED_STATUS}}- {{$validation_date|date_short}}{{/if}}

			{{if $archived}}
				<span title="Archivé">🗃</span>
			{{elseif $type === $INVOICE_TYPE && $payment_date}}
				- Payé le {{$payment_date|date_short}}
			{{/if}}
		</td>
		<td class="actions">
			{{if !$archived && $status == $DRAFT_STATUS}}
			{{:linkbutton shape="edit" label="Modifier" href="edit.html?id=%d"|args:$id}}
			{{/if}}
			{{if $status !== $DRAFT_STATUS}}







|




|

|















|
|





>



>
>




>
>
>
>
|
>













>





|
|







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

{{* ==================== Listing ==================== *}}

{{if $_GET.q}}
	<h2 class="ruler">Résultat(s) de recherche pour "{{$_GET.q}}"</h2>
{{/if}}

{{:include file='./include/constants.tpl' keep='DRAFT_STATUS, AWAITING_STATUS, VALIDATED_STATUS, PAID_STATUS, TYPE_LABELS, STATUS_LABELS, QUOTATION_TYPE, INVOICE_TYPE, INVOICE_STATUS_LABELS'}}

{{if $_GET.show == $QUOTATION_TYPE}}
	{{:assign filter="json_extract(document, '$.type') = '%s'"|args:$QUOTATION_TYPE}}
{{elseif $_GET.show == 'paid'}}
	{{:assign filter="$$.type = :type AND $$.status = :status" type_filter=$INVOICE_TYPE status_filter=$PAID_STATUS}}
{{elseif $_GET.show == 'unpaid'}}
	{{:assign filter="$$.type = :type AND $$.status = :status" type_filter=$INVOICE_TYPE status_filter=$AWAITING_STATUS}}
{{else}}
	{{:assign filter="1"}}
{{/if}}

{{if $_GET.ok === '1'}}
	<p class="block confirm">Devis enregistré.</p>
{{elseif $_GET.ok === '2'}}
	<p class="block confirm">Devis modifié avec succès.</p>
{{elseif $_GET.ok === '4'}}
	<p class="block confirm">Devis supprimé avec succès.</p>
{{/if}}


{{:assign list_select="key; id AS 'Numéro'; datetime($$.date) AS 'Émission'; $$.deadline AS 'Échéance'; $$.recipient_business_name AS 'Tiers'; $$.subject AS 'Intitulé'; $$.total AS 'Montant'; $$.status AS 'Statut'"}}
{{:assign list_where="$$.type IN ('quotation', 'invoice') AND %s"|args:$filter}}
{{:assign list_order=1}}
{{if !$_GET.show}}{{:assign list_select='$$.parent_id AS "↳"; $$.type AS "Type"; '|cat:$list_select}}{{:assign list_order=3}}{{/if}}
{{if $_GET.q}}{{:assign list_where=$list_where|cat:' AND ':$search_where}}{{/if}}
{{#list
	select=$list_select
	where=$list_where
	order=$list_order
	desc=true
	:searched_id=$searched_id
	:searched_date=$searched_date
	:searched_text=$searched_text
	:type=$type_filter
	:status=$status_filter
}}
	<tr>
		{{if !$_GET.show}}
			{{:assign var="label" from="TYPE_LABELS.%s"|args:$type}}
			{{if $type === $INVOICE_TYPE && $parent_id}}
				<td colspan="2" style="text-align:left;">{{$label}} <span title="Associée au devis suivant">↴</span></td>
			{{else}}
				<td></td>
				<td>{{$label}}</td>
			{{/if}}
		{{/if}}
		<td>{{:link href="details.html?id=%d&show=%s"|args:$id:$type label=$key}}</td>
		<td>{{$date|date_short}}</td>
		<td>{{$deadline|date_short}}</td>
		<td>{{$recipient_business_name}}</td>
		<td>{{:link href="details.html?id=%d&show=%s"|args:$id:$type label=$subject}}</td>
		<td class="money">{{$total|money_currency}}</td>
		<td>
			{{if $type === $INVOICE_TYPE}}
				{{:assign var="label" from="INVOICE_STATUS_LABELS.%s"|args:$status}}
			{{else}}
				{{:assign var="label" from="STATUS_LABELS.%s"|args:$status}}
			{{/if}}

			{{$label}}
			{{if $status === $VALIDATED_STATUS}}- {{$validation_date|date_short}}{{/if}}

			{{if $archived}}
				<span title="Archivé">🗃</span>
			{{elseif $type === $INVOICE_TYPE && $status === $PAID_STATUS}}
				- {{$payment_date|date_short}}
			{{/if}}
		</td>
		<td class="actions">
			{{if !$archived && $status == $DRAFT_STATUS}}
			{{:linkbutton shape="edit" label="Modifier" href="edit.html?id=%d"|args:$id}}
			{{/if}}
			{{if $status !== $DRAFT_STATUS}}

Modified src/skel-dist/modules/invoice/preview.html from [a11867ef64] to [eedf87455a].

34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
		<li>{{$config.org_web}}</li>
	{{/if}}
	<li>Contact : {{$org_contact}}</li>
</ul>

<ul class="customer_details">
	<li>
		<strong>{{$recipient_business_name|strtoupper}}</strong><br />
		{{$recipient_address|escape|nl2br}}
	</li>
	{{if $recipient_member_numero || $recipient_member_id}}
		<li>Réf. membre : {{if $recipient_member_numero}}{{$recipient_member_numero}}{{else}}#{{$recipient_member_id}}{{/if}}</li>
	{{/if}}
</ul>








|







34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
		<li>{{$config.org_web}}</li>
	{{/if}}
	<li>Contact : {{$org_contact}}</li>
</ul>

<ul class="customer_details">
	<li>
		<strong class="business_name">{{$recipient_business_name}}</strong><br />
		{{$recipient_address|escape|nl2br}}
	</li>
	{{if $recipient_member_numero || $recipient_member_id}}
		<li>Réf. membre : {{if $recipient_member_numero}}{{$recipient_member_numero}}{{else}}#{{$recipient_member_id}}{{/if}}</li>
	{{/if}}
</ul>

114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	<h3>Informations</h3>
	{{if $payment_detail}}<p>{{$payment_detail|escape|nl2br}}</p>{{/if}}
	{{if $extra_info}}<p>{{$extra_info|escape|nl2br}}</p>{{/if}}
{{/if}}

<p>
	<strong>Bon pour accord</strong> le {{$signing_date|date_short}},<br />
	à {{$signing_place|strtoupper}}.
</p>

{{if $status !== $DRAFT_STATUS && $config.files.signature}}
<figure>
	<img src="{{$config.files.signature}}" alt="Signature association" />
</figure>
{{/if}}







|







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	<h3>Informations</h3>
	{{if $payment_detail}}<p>{{$payment_detail|escape|nl2br}}</p>{{/if}}
	{{if $extra_info}}<p>{{$extra_info|escape|nl2br}}</p>{{/if}}
{{/if}}

<p>
	<strong>Bon pour accord</strong> le {{$signing_date|date_short}},<br />
	à <span class="signing_place">{{$signing_place}}</span>.
</p>

{{if $status !== $DRAFT_STATUS && $config.files.signature}}
<figure>
	<img src="{{$config.files.signature}}" alt="Signature association" />
</figure>
{{/if}}

Modified src/skel-dist/modules/invoice/schema/invoice.json from [3628672791] to [8fceab4c16].

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
			"description": "Échéance",
			"type": ["string", "null"],
			"maxLength": 10
		},
		"status": {
			"description": "Statut",
			"type": "string",
			"enum": ["draft", "awaiting", "rejected", "validated", "misc"]
		},
		"items": {
			"description": "Articles",
			"type": ["array", "null"],
			"items": {
				"type": "object",
				"properties": {







|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
			"description": "Échéance",
			"type": ["string", "null"],
			"maxLength": 10
		},
		"status": {
			"description": "Statut",
			"type": "string",
			"enum": ["draft", "awaiting", "rejected", "validated", "paid", "misc"]
		},
		"items": {
			"description": "Articles",
			"type": ["array", "null"],
			"items": {
				"type": "object",
				"properties": {
104
105
106
107
108
109
110









111
112
113
114
115
116
117
			"maxLength": 10
		},
		"payment_date": {
			"description": "Date à laquelle le paiement a été effectué",
			"type": ["string", "null"],
			"maxLength": 10
		},









		"payment_detail": {
			"description": "Instructions de paiement",
			"type": ["string", "null"],
			"maxLength": 512
		},
		"extra_info": {
			"description": "Informations complémentaires",







>
>
>
>
>
>
>
>
>







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
			"maxLength": 10
		},
		"payment_date": {
			"description": "Date à laquelle le paiement a été effectué",
			"type": ["string", "null"],
			"maxLength": 10
		},
		"payment_comment": {
			"description": "Remarques sur le paiement",
			"type": ["string", "null"],
			"maxLength": 256
		},
		"transaction_id": {
			"description": "Écriture liée",
			"type": ["integer", "null"]
		},
		"payment_detail": {
			"description": "Instructions de paiement",
			"type": ["string", "null"],
			"maxLength": 512
		},
		"extra_info": {
			"description": "Informations complémentaires",

Modified src/skel-dist/modules/invoice/schema/quotation.json from [d797c5cae4] to [70b3d7ed1e].

114
115
116
117
118
119
120





121
122
123
124
125
126
127
128
129
130
131
132
133
			"maxLength": 512
		},
		"extra_info": {
			"description": "Informations complémentaires",
			"type": ["string", "null"],
			"maxLength": 1024
		},





		"last_modification_date": {
			"description": "Date de la derniète modification",
			"type": "string",
			"maxLength": 25
		},
		"module_version": {
			"description": "Module version number from which the document has been generated",
			"type": "string",
			"maxLength": 12
		}
	},
	"required": [ "recipient_business_name", "recipient_address", "subject", "date", "status", "vat_exemption", "author_id", "org_contact", "last_modification_date", "module_version" ]
}







>
>
>
>
>













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
			"maxLength": 512
		},
		"extra_info": {
			"description": "Informations complémentaires",
			"type": ["string", "null"],
			"maxLength": 1024
		},
		"parent_id": {
			"description": "Identique à ID si facture générée (hack pour grouper facture et devis)",
			"type": ["integer", "null"],
			"maxLength": 19
		},
		"last_modification_date": {
			"description": "Date de la derniète modification",
			"type": "string",
			"maxLength": 25
		},
		"module_version": {
			"description": "Module version number from which the document has been generated",
			"type": "string",
			"maxLength": 12
		}
	},
	"required": [ "recipient_business_name", "recipient_address", "subject", "date", "status", "vat_exemption", "author_id", "org_contact", "last_modification_date", "module_version" ]
}

Added src/skel-dist/modules/invoice/transaction_selector.inc.tpl version [bca21e43d7].









































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
{{:admin_header title="Sélectionner un compte"}}

<form method="post" action="{{$request_url}}">
	<h2 class="ruler">
		<input type="text" placeholder="Recherche rapide d'écriture" value="{{$_POST.q}}" name="q" />
		<input type="submit" value="Chercher &rarr;" />
	</h2>
</form>

{{if $_POST.q}}
	{{if $_POST.q|parse_date}}
		{{:assign search_where="date = :searched_date" searched_date=$_POST.q|parse_date}}
	{{else}}
		{{:assign searched_text=$_POST.q|trim|regexp_replace:'/[!%_]/':'!$0'}}
		{{:assign search_where="((label LIKE :searched_text ESCAPE '!') OR (reference LIKE :searched_text ESCAPE '!'))" searched_text="%%%s%%"|args:$searched_text}}
	{{/if}}

	<table class="list">
		<tbody>
		{{#sql tables="acc_transactions" where=$search_where :searched_text=$searched_text :searched_date=$searched_date}}
			<tr>
				<th>
					{{$label}}{{if $reference}} - {{$reference}}{{/if}} - {{$date}}{{if $notes}} - {{$notes}}{{/if}}
				</th>
				<td class="actions">
					<button class="icn-btn" value="{{$id}}" data-label="{{$label}}" data-icon="&rarr;">Sélectionner</button>
				</td>
			</tr>
		{{/sql}}
		</tbody>
	</table>
{{/if}}

<script type="text/javascript">
var buttons = document.querySelectorAll('button');

buttons.forEach((e) => {
	e.onclick = () => {
		window.parent.g.inputListSelected(e.value, e.getAttribute('data-label'));
	};
});

if (buttons.length) {
	buttons[0].focus();
}

var rows = document.querySelectorAll('table tbody tr');

if (rows.length == 1) {
	rows[0].querySelector('button').click();
}

rows.forEach((e) => {
	e.classList.add('clickable');

	e.onclick = (evt) => {
		if (evt.target.tagName && evt.target.tagName == 'BUTTON') {
			return;
		}

		e.querySelector('button').click();
	};
});

document.querySelector('input').focus();
</script>

{{:admin_footer}}