Overview
Comment:Invoice module: creation and edition forms merged + amounts display updated
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | invoice_module
Files: files | file ages | folders
SHA3-256: 5550c809b7ae94f73d4e0bf7a5ce20388c0912447467b53bd4360cec871f0851
User & Date: alinaar on 2023-02-23 17:32:18
Other Links: branch diff | manifest | tags
Context
2023-02-23
18:45
Invoice module: ID and reference added to quotation's items check-in: d61c451ab9 user: alinaar tags: invoice_module
17:32
Invoice module: creation and edition forms merged + amounts display updated check-in: 5550c809b7 user: alinaar tags: invoice_module
15:59
Merge dev branch check-in: 478ec2feb6 user: alinaar tags: invoice_module
Changes

Modified src/skel-dist/modules/invoice/config.html from [0fe6ba5388] to [58dc78e6ce].

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	<p class="block confirm">Configuration enregistrée.</p>
{{/if}}

<h1>{{$page_title}}</h1>
<form method="POST" action="{{$self_url}}">
	<fieldset>
		<legend></legend>
		{{:input required=false name="payment_detail" type="textarea" label="Instructions de paiement" default=$module.config.payment_detail placeholder="BIC :&#10;ABCDEFGH012&#10;FR9901234567890123456789012&#10;La banque eh! tic&#10;&#10;Paiement à réaliser sous 15 jours."}}
		{{:input required=false name="quotation_extra_info" type="textarea" label="Informations complémentaires affichées en bas des devis" default=$module.config.quotation_extra_info placeholder="ex : Site officiel : https://www.mon-asso.fr"}}
	</fieldset>
	{{:button type="submit" name="save" label="Enregistrer la configuration"}}
</form>

<!--
<form method="POST" action="{{$self_url}}">
	<fieldset>
		<legend>Création d'un devis</legend>
		<ul>







|
|

|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
	<p class="block confirm">Configuration enregistrée.</p>
{{/if}}

<h1>{{$page_title}}</h1>
<form method="POST" action="{{$self_url}}">
	<fieldset>
		<legend></legend>
		{{:input required=false name="payment_detail" type="textarea" label="Instructions de paiement" default=$module.config.payment_detail placeholder="BIC :&#10;ABCDEFGH012&#10;FR9901234567890123456789012&#10;La banque eh! tic&#10;&#10;Paiement à réaliser sous 15 jours." cols="50" rows="5"}}
		{{:input required=false name="quotation_extra_info" type="textarea" label="Informations complémentaires affichées en bas des devis" default=$module.config.quotation_extra_info placeholder="ex : Site officiel : https://www.mon-asso.fr" cols="50" rows="3"}}
	</fieldset>
	{{:button type="submit" name="save" label="Enregistrer la configuration" class="main"}}
</form>

<!--
<form method="POST" action="{{$self_url}}">
	<fieldset>
		<legend>Création d'un devis</legend>
		<ul>

Modified src/skel-dist/modules/invoice/details.html from [f4e6da0ea7] to [8b243d71f9].

46
47
48
49
50
51
52

53
54
55
56
57
58
59
	<p class="error block">Aucun document séléctionné.</p>
{{else}}
	{{if $_GET.ok}}<p class="block confirm">Modification enregistrée.</p>{{/if}}
	{{#load id=$_GET.id|intval}}

		<nav class="tabs">
			<aside>

				{{if $status == 'draft'}}
					{{:linkbutton href="./edit.html?id=%d"|args:$id label="Modifier le devis" shape="edit"}}
				{{else}} {{* Hack awaiting #ac34cf8f45a5a79815b16ea505da08ffad2268cf implementation *}}
					{{:button name="hack" title="Ce document n'est plus un brouillon et ne peut plus être modifié" label="Modifier le devis" disabled=true}}
				{{/if}}
			</aside>
			{{:include file='./include/main_nav_tabs.html'}}







>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
	<p class="error block">Aucun document séléctionné.</p>
{{else}}
	{{if $_GET.ok}}<p class="block confirm">Modification enregistrée.</p>{{/if}}
	{{#load id=$_GET.id|intval}}

		<nav class="tabs">
			<aside>
				{{:linkbutton href="edit.html" label="Nouveau devis" shape="plus"}}
				{{if $status == 'draft'}}
					{{:linkbutton href="./edit.html?id=%d"|args:$id label="Modifier le devis" shape="edit"}}
				{{else}} {{* Hack awaiting #ac34cf8f45a5a79815b16ea505da08ffad2268cf implementation *}}
					{{:button name="hack" title="Ce document n'est plus un brouillon et ne peut plus être modifié" label="Modifier le devis" disabled=true}}
				{{/if}}
			</aside>
			{{:include file='./include/main_nav_tabs.html'}}
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
		
		<fieldset>
			<legend><h2>Objet</h2></legend>
			<ul>
				<li>Objet : {{$subject}}</li>
				<li>Date : {{$date|date_short}}</li>
				{{if $deadline}}<li>Échéance : {{$deadline|date_short}}</li>{{/if}}
				<li>Total : {{$total|floatval|money_int|raw|money_currency}}</li>
			</ul>
		</fieldset>
		
		<fieldset>
			<legend><h2>Articles</h2></legend>
			{{if $items}}
				<table id="item_list">
					<tr>
						<th>Dénomination</th>
						<th>Description</th>
						<th>Prix unitaire</th>
						<th>Quantité</th>
					</tr>
					{{#foreach from=$items item='item'}}
						<tr>
							<td>{{$item.name}}</td>
							<td>{{$item.description}}</td>
							<td>{{$item.unit_price}}</td>
							<td>{{$item.quantity}}</td>
						</tr>
					{{/foreach}}
				</table>

				</ul>
			{{else}}







|

















|







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
		
		<fieldset>
			<legend><h2>Objet</h2></legend>
			<ul>
				<li>Objet : {{$subject}}</li>
				<li>Date : {{$date|date_short}}</li>
				{{if $deadline}}<li>Échéance : {{$deadline|date_short}}</li>{{/if}}
				<li>Total : {{$total|floatval|money_currency:false}}</li>
			</ul>
		</fieldset>
		
		<fieldset>
			<legend><h2>Articles</h2></legend>
			{{if $items}}
				<table id="item_list">
					<tr>
						<th>Dénomination</th>
						<th>Description</th>
						<th>Prix unitaire</th>
						<th>Quantité</th>
					</tr>
					{{#foreach from=$items item='item'}}
						<tr>
							<td>{{$item.name}}</td>
							<td>{{$item.description}}</td>
							<td>{{$item.unit_price|intval|money:false}}</td>
							<td>{{$item.quantity}}</td>
						</tr>
					{{/foreach}}
				</table>

				</ul>
			{{else}}

Modified src/skel-dist/modules/invoice/edit.html from [39e9ea2fd5] to [7b985d001b].

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
142
143
144
145
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
{{#restrict section="accounting" level="write"}}

{{if $_GET.id}}
	{{#load id=$_GET.id}}
		{{:assign .="doc"}}
	{{/load}}
{{else}}
	{{:error message="Aucun document sélectionné."}}
{{/if}}

{{:admin_header title="Devis et factures" current="acc"}}
<nav class="tabs">
	<aside>
		{{:linkbutton href="new_quotation.html" label="Nouveau devis" shape="plus"}}
	</aside>
	{{:include file='./include/main_nav_tabs.html'}}
</nav>
{{:include file='./include/constants.tpl' keep='type_labels,status_labels,status_options'}}






<h1>Édition du devis n°{{$doc.key}} "{{$doc.subject}}"</h1>




{{if $doc.status !== 'draft'}}
	{{:error message="Ce document n'est plus un brouillon et ne peut plus être modifié"}}
{{/if}}


{{if $_POST.quotation_submit}}
	{{:assign computed_total=0}}
	{{:assign errors=null}}
	{{:assign items=null}}
	{{#foreach from=$_POST.items key='index' item='item'}}
		{{if $item.name === ''}}{{:assign var='errors[]' value="Le nom de l'article est requis."}}{{/if}}
		{{:assign var='unit_price' value=$item.unit_price|replace:',':'.'}}
		{{:assign var='quantity' value=$item.quantity|replace:',':'.'}}
		{{if $unit_price < 0 || $unit_price != $unit_price|floatval|strtolower}} {{* Hack to check the data is a number *}}
			{{:assign var='errors[]' value='Le prix saisi pour "%s" est invalide.'|args:$item.name}}
		{{/if}}
		{{if $item.quantity < 0 || $item.quantity != $item.quantity|floatval|strtolower}}{{:assign var='errors[]' value='La quantité saisie pour "%s" est invalide.'|args:$item.name}}{{/if}}

		{{:assign var='computed_item' value=$item}}
		{{:assign var='computed_item[unit_price]' value='%d * 100'|math:$item.unit_price|floatval}}
		{{:assign var='computed_item[quantity]' value=$item.quantity|intval}}
		{{:assign var='items[]' value=$computed_item}}
		{{:assign var='computed_total' value="%d + %d * %d"|args:$computed_total:$item.unit_price:$item.quantity|math}}

	{{/foreach}}

	{{if ($computed_total != $_POST.quotation_total) || ($computed_total < 0)}}
		{{:assign var='errors[]' value='Erreur de calcul du total. Enregistrement du devis refusé.'}}
	{{/if}}

	{{if $errors|count}}
		{{#foreach from=$errors item='error'}}
			<p class="error block">{{$error}}</p>
		{{/foreach}}
	{{else}}















		{{:save id=$_POST.id|intval
			validate_schema="./quotation.schema.json"

			key=$_POST.key
			type='quotation'
			recipient_business_name=$_POST.recipient_business_name
			recipient_address=$_POST.recipient_address
			subject=$_POST.subject
			date=$_POST.date
			deadline=$_POST.deadline
			status=$_POST.status
			items=$items
			total=$computed_total
			contact_info=$_POST.contact_info
			payment_detail=$_POST.payment_detail
			extra_info=$_POST.extra_info
		}}
		{{:save key="config" last_id=$new_key last_quotation_id=$id}}
		{{:http redirect="./index.html?ok=2"}}
	{{/if}}
{{/if}}



{{*

{{if $_POST.save}}
	{{if !$_POST.date|trim|parse_date}}
		{{:assign error="Date d'émission invalide ou vide."}}
	{{elseif $_POST.date_required|trim|parse_date === false}}
		{{:assign error="Date d'échéance invalide ou vide."}}
	{{else}}
		{{if $doc.paid_date}}
			{{:assign date_paid=$doc.paid_date}}
		{{elseif $_POST.paid && !$doc.paid}}
			{{:assign date_paid=$now}}
		{{else}}
			{{:assign date_paid=null}}
		{{/if}}

		{{if $doc.type}}
			{{:assign type=$doc.type}}
		{{else}}
			{{:assign type=$_POST.type}}
		{{/if}}

		{{if !$_POST.number}}
			{{:assign number=$_POST.number|trim|strtoupper}}
		{{else}}
			{{#load select="COUNT(*) + 1 AS count" where="json_extract('$.type') = :type" :type=$type}}
				{{if $type == 'invoice'}}
					{{:assign key="F%06d"|args:$count}}
				{{else}}
					{{:assign key="D%06d"|args:$count}}
				{{/if}}
			{{/load}}
		{{/if}}

		{{:assign total=0}}

		{{#foreach from=$_POST.rows}}
			{{:assign amount=$value.amount|money_int}}
			{{:assign total=$total|math:'+':$amount}}
			{{:assign var="rows[]" label=$value.label|trim amount=$amount}}
		{{/foreach}}

		{{:save key=$key
			validate_schema="./document.schema.json"
			draft=true
			date_paid=null
			archived=false
			type=$type
			date=$_POST.date|parse_date
			date_required=$date_required|parse_date
			id_transaction1=null
			id_transaction2=null
			total=$total
			rows=$rows
		}}

		{{:http redirect="doc.html?key=%s"|args:$key}}
	{{/if}}
{{/if}}

*}}

<form method="post" action="" id="docForm" data-type="{{$doc.type}}" data-disable-progress="1">

	<fieldset>
		<legend><h2>Destinataire</h2></legend>
		{{:input type="text" name="recipient_business_name" label="Raison sociale" source=$doc placeholder="ex : SARL J'aime les deux vies" required=true}}
		{{:input type="textarea" name="recipient_address" label="Adresse" source=$doc placeholder="" required=true}}
	</fieldset>
	<fieldset>
		<legend><h2>Objet</h2></legend>
		<ul>
			<li>
				{{:input type="hidden" name="id" default=$doc.id|intval}}
				{{:input type="text" name="key" label="Numéro" source=$doc help="Ce numéro doit être unique. Laisser vide pour générer un nouveau numéro."}}
			</li>
			<li>{{:input type="text" name="subject" label="Objet" source=$doc placeholder="ex : Devis pour une location de barnum" required=true}}</li>
			<li>{{:input type="date" name="date" label="Date d'émission" source=$doc placeholder="" required=true}}</li>
			<li>{{:input type="date" name="deadline" label="Échéance pour validation" source=$doc placeholder="" required=false}}</li>
			<li>{{:input type="text" name="contact_info" label="Contact" source=$doc required=true}}</li>
			<li>
				<dt><label for="status">Statut</label></dt>
				<dd>
					{{:input type="select" name="status" options=$status_options source=$doc required=true}}
				</dd>
			</li>
		</ul>
	</fieldset>
	
	{{:assign items=$doc.items}}
	{{:include file='./include/item_list.tpl'}}

<p class="submit">
	{{:button type="submit" name="quotation_submit" label="Enregistrer" class="main"}}
</p>

</form>

<script type="text/javascript">
(function () {
	const form = $('#docForm');

	$('#f_type_invoice, #f_type_quote').forEach((e) => {
		e.onchange = () => typeChanged(e.value, true);
	});

	function typeChanged(t, change_number) {
		if (change_number) {
			let num = t == 'quote' ? 'D' : 'F';
			num += $('#f_number').dataset.lastNumber;
			$('#f_number').value = num;
		}

		g.toggle('.invoice-only', t == 'quote' ? false : true);
	}

	if (e = $('#f_type_invoice')) {
		typeChanged(e.selected ? 'invoice' : 'quote', true);

	}
	else if (form.dataset.type) {
		typeChanged(form.dataset.type, false);
	}
})();


</script>


{{:admin_footer}}

{{else}}
	{{:error message="Seuls les membres avec accès en écriture à la comptabilité peuvent générer ce document"}}
{{/restrict}}


|
<
<
<
<
<
<




|




>

>
>
>
>
|
>
>
>

|


<






|



|

|


|
|
|
|
>


|
|







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

|

>
|













<
<
<
<

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


<
<
<
<
<
<
<
<
|
<
|

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


|
|




<
<
|
<
|
|
|
|



|




|
|


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




|

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
142
143
144
145
146
147
148
149
150
{{#restrict section="accounting" level="write"}}

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







{{:admin_header title="Devis et factures" current="acc"}}
<nav class="tabs">
	<aside>
		{{:linkbutton href="edit.html" label="Nouveau devis" shape="plus"}}
	</aside>
	{{:include file='./include/main_nav_tabs.html'}}
</nav>
{{:include file='./include/constants.tpl' keep='type_labels,status_labels,status_options'}}
{{* {{:include file='./include/style.tpl'}} *}}

{{if $_GET.id}}
	{{#load id=$_GET.id}}
		{{:assign .="document"}}
	{{/load}}
	<h1>Édition du devis n°{{$document.key}} "{{$document.subject}}"</h1>
{{else}}
	<h1>Création d'un devis</h1>
{{/if}}

{{if $document && $document.status !== 'draft'}}
	{{:error message="Ce document n'est plus un brouillon et ne peut plus être modifié"}}
{{/if}}


{{if $_POST.quotation_submit}}
	{{:assign computed_total=0}}
	{{:assign errors=null}}
	{{:assign items=null}}
	{{#foreach from=$_POST.items key='index' item='item'}}
		{{if $item.name === ''}}{{:assign var='errors.' value="Le nom de l'article est requis."}}{{/if}}
		{{:assign var='unit_price' value=$item.unit_price|replace:',':'.'}}
		{{:assign var='quantity' value=$item.quantity|replace:',':'.'}}
		{{if $unit_price < 0 || $unit_price != $unit_price|floatval|strtolower}} {{* Hack to check the data is a number *}}
			{{:assign var='errors.' value='Le prix saisi pour "%s" est invalide.'|args:$item.name}}
		{{/if}}
		{{if $quantity < 0 || $quantity != $quantity|floatval|strtolower}}{{:assign var='errors.' value='La quantité saisie pour "%s" est invalide.'|args:$item.name}}{{/if}}

		{{:assign var='computed_item' value=$item}}
		{{:assign var='computed_item.unit_price' value=$unit_price|money_int}}
		{{:assign var='computed_item.quantity' value=$quantity|floatval}}
		{{:assign var='items.' value=$computed_item}}
		{{:assign var='computed_total' value="%d + %d * %F"|args:$computed_total:$computed_item.unit_price:$computed_item.quantity|math}}

	{{/foreach}}

	{{if ($computed_total != $_POST.quotation_total|money_int) || ($computed_total < 0)}}
		{{:assign var='errors.' value='Erreur de calcul du total. Enregistrement du devis refusé.'}}
	{{/if}}

	{{if $errors|count}}
		{{#foreach from=$errors item='error'}}
			<p class="error block">{{$error}}</p>
		{{/foreach}}
	{{else}}
		{{if $_POST.key}}
			{{:assign key=$_POST.key}}
		{{else}}
			{{#load select="MAX(key) AS last" where="json_extract(document, '$.type') = :type" :type='quotation'}} 
				{{:assign last_numeric=$last|regexp_replace:'~\D~':''}}
				{{:assign next_numeric='%d+1'|math:$last_numeric}}
				{{:assign key="D%06d"|args:$next_numeric}}
			{{/load}}
		{{/if}}
		{{if $document}}
			{{:assign id=$document.id|intval}}
		{{else}}
			{{:assign id=null}}
		{{/if}}

		{{:save 
			validate_schema="./quotation.schema.json"
			id=$id
			key=$key
			type='quotation'
			recipient_business_name=$_POST.recipient_business_name
			recipient_address=$_POST.recipient_address
			subject=$_POST.subject
			date=$_POST.date
			deadline=$_POST.deadline
			status=$_POST.status
			items=$items
			total=$computed_total
			contact_info=$_POST.contact_info
			payment_detail=$_POST.payment_detail
			extra_info=$_POST.extra_info
		}}





		{{if !$document}}
			{{:http redirect="./index.html?ok=1"}}







		{{else}}







			{{:http redirect="./index.html?ok=2"}}




		{{/if}}









	{{/if}}

{{/if}}


<form method="POST" action="{{$request_url}}">




























	<fieldset>
		<legend><h2>Destinataire</h2></legend>
		{{:input type="text" name="recipient_business_name" label="Raison sociale" source=$document placeholder="ex : SARL J'aime les deux vies" required=true}}
		{{:input type="textarea" name="recipient_address" label="Adresse" source=$document placeholder="" required=true}}
	</fieldset>
	<fieldset>
		<legend><h2>Objet</h2></legend>
		<ul>


			<li>{{:input type="text" name="key" label="Numéro" source=$document help="Ce numéro doit être unique. Laisser vide pour générer un nouveau numéro."}}</li>

			<li>{{:input type="text" name="subject" label="Objet" source=$document placeholder="ex : Devis pour une location de barnum" required=true}}</li>
			<li>{{:input type="date" name="date" label="Date du devis" source=$document placeholder="" required=true}}</li>
			<li>{{:input type="date" name="deadline" label="Échéance pour validation" source=$document placeholder="" required=false}}</li>
			<li>{{:input type="text" name="contact_info" label="Contact" source=$document default=$config.org_email required=true}}</li>
			<li>
				<dt><label for="status">Statut</label></dt>
				<dd>
					{{:input type="select" name="status" options=$status_options source=$document default=$status required=true}}
				</dd>
			</li>
		</ul>
	</fieldset>

	{{:assign items=$document.items}}
	{{:include file='./include/item_list.tpl'}}


	{{if $module.config.payment_detail || $module.config.quotation_extra_info}}
		<fieldset>
			<legend><h2>Informations complémentaires affichées en bas du devis</h2></legend>
			<ul>
			{{if $module.config.payment_detail}}
				<li>{{:input type="textarea" name="payment_detail" label="Instructions de paiement" source=$document default=$module.config.payment_detail cols="50" rows="5"}}</li>
			{{/if}}

			{{if $module.config.quotation_extra_info}}



				<li>{{:input type="textarea" name="extra_info" label="Informations complémentaires" source=$document default=$module.config.quotation_extra_info cols="50" rows="2"}}</li>





			{{/if}}
			</ul>


		{{if !$document}}<p>(La valeur pré-remplie de ces informations est modifiable dans la configuration du module.)</p>{{/if}}


		</fieldset>
	{{/if}}




	<p class="submit">
		{{:button type="submit" name="quotation_submit" label="Valider la création de devis" class="main"}}
	</p>
</form>

{{:admin_footer}}

{{else}}
	{{:error message="Seuls les membres avec accès en écriture à la comptabilité peuvent générer ce document."}}
{{/restrict}}

Modified src/skel-dist/modules/invoice/index.html from [58c6ec30be] to [ed56514aae].

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

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

{{:admin_header title="Devis et factures" current="acc"}}
<nav class="tabs">
	<aside>
		{{:linkbutton href="new_quotation.html" label="Nouveau devis" shape="plus"}}
	</aside>
	{{:include file='./include/main_nav_tabs.html'}}
</nav>
{{:include file='./include/style.tpl'}}

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








|







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

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

{{:admin_header title="Devis et factures" current="acc"}}
<nav class="tabs">
	<aside>
		{{:linkbutton href="edit.html" label="Nouveau devis" shape="plus"}}
	</aside>
	{{:include file='./include/main_nav_tabs.html'}}
</nav>
{{:include file='./include/style.tpl'}}

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

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
				<td>{{$label}}</td>
			{{/if}}
			<td><a href="details.html?id={{$id|intval}}">{{$key}}</a></td>
			<td>{{$date|date_short}}</td>
			<td>{{$deadline|date_short}}</td>
			<td>{{$recipient_business_name}}</td>
			<td><a href="details.html?id={{$id|intval}}">{{$subject}}</a></td>
			<td class="money">{{$total|floatval|money_int|raw|money_currency}}{{* Hacks awaiting #495af6eee05e451d9369b80023c38b8e128fa6cd resolution *}}</td>
			<td>
				{{:assign var="label" from="status_labels.%s"|args:$status}}
				{{$label}}

				{{if $archived}}
					<span title="Archivé">🗃</span>
				{{elseif $date_paid}}







|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
				<td>{{$label}}</td>
			{{/if}}
			<td><a href="details.html?id={{$id|intval}}">{{$key}}</a></td>
			<td>{{$date|date_short}}</td>
			<td>{{$deadline|date_short}}</td>
			<td>{{$recipient_business_name}}</td>
			<td><a href="details.html?id={{$id|intval}}">{{$subject}}</a></td>
			<td class="money">{{$total|money_currency}}</td>
			<td>
				{{:assign var="label" from="status_labels.%s"|args:$status}}
				{{$label}}

				{{if $archived}}
					<span title="Archivé">🗃</span>
				{{elseif $date_paid}}

Deleted src/skel-dist/modules/invoice/new_quotation.html version [0ef91b4f29].

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
{{#restrict section="accounting" level="write"}}

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

{{:admin_header title="Devis et factures" current="acc"}}
<nav class="tabs">
	<aside>
		{{:linkbutton href="new_quotation.html" label="Nouveau devis" shape="plus"}}
	</aside>
	{{:include file='./include/main_nav_tabs.html'}}
</nav>
{{:include file='./include/constants.tpl' keep='type_labels,status_labels,status_options'}}
{{* {{:include file='./include/style.tpl'}} *}}

<h1>Création d'un devis</h1>

{{if $_POST.quotation_submit}}
	{{:assign computed_total=0}}
	{{:assign errors=null}}
	{{:assign items=null}}
	{{#foreach from=$_POST.items key='index' item='item'}}
		{{if $item.name === ''}}{{:assign var='errors.' value="Le nom de l'article est requis."}}{{/if}}
		{{if $item.unit_price < 0 || $item.unit_price != $item.unit_price|floatval|strtolower}} {{* Hack to check the data is a number *}}
			{{:assign var='errors.' value='Le prix saisi pour "%s" est invalide.'|args:$item.name}}
		{{/if}}
		{{if $item.quantity < 0 || $item.quantity != $item.quantity|floatval|strtolower}}{{:assign var='errors.' value='La quantité saisie pour "%s" est invalide.'|args:$item.name}}{{/if}}

		{{:assign var='computed_item' value=$item}}
		{{:assign var='computed_item.unit_price' value='%d * 100'|math:$item.unit_price|floatval}}
		{{:assign var='computed_item.quantity' value=$item.quantity|intval}}
		{{:assign var='items.' value=$computed_item}}
		{{:assign var='computed_total' value="%d + %d * %d"|args:$computed_total:$item.unit_price:$item.quantity|math}}
	{{/foreach}}

	{{if ($computed_total != $_POST.quotation_total) || ($computed_total < 0)}}
		{{:assign var='errors.' value='Erreur de calcul du total. Enregistrement du devis refusé.'}}
	{{/if}}

	{{if $errors|count}}
		{{#foreach from=$errors item='error'}}
			<p class="error block">{{$error}}</p>
		{{/foreach}}
	{{else}}
		{{if $_POST.key}}
			{{:assign key=$_POST.key}}
		{{else}}
			{{#load select="MAX(key) AS last" where="json_extract(document, '$.type') = :type" :type='quotation'}} 
				{{:assign last_numeric=$last|regexp_replace:'~\D~':''}}
				{{:assign next_numeric='%d+1'|math:$last_numeric}}
				{{:assign key="D%06d"|args:$next_numeric}}
			{{/load}}
		{{/if}}

		{{:save 
			validate_schema="./quotation.schema.json"
			key=$key
			type='quotation'
			recipient_business_name=$_POST.recipient_business_name
			recipient_address=$_POST.recipient_address
			subject=$_POST.subject
			date=$_POST.date
			deadline=$_POST.deadline
			status=$_POST.status
			items=$items
			total=$computed_total
			contact_info=$_POST.contact_info
			payment_detail=$_POST.payment_detail
			extra_info=$_POST.extra_info
		}}

		{{:http redirect="./index.html?ok=1"}}
	{{/if}}
{{/if}}

<form method="POST" action="">
	<fieldset>
		<legend><h2>Destinataire</h2></legend>
		{{:input type="text" name="recipient_business_name" label="Raison sociale" placeholder="ex : SARL J'aime les deux vies" required=true}}
		{{:input type="textarea" name="recipient_address" label="Adresse" placeholder="" required=true}}
	</fieldset>
	<fieldset>
		<legend><h2>Objet</h2></legend>
		<ul>
			<li>{{:input type="text" name="key" label="Numéro" help="Ce numéro doit être unique. Laisser vide pour générer un nouveau numéro."}}</li>
			<li>{{:input type="text" name="subject" label="Objet" placeholder="ex : Devis pour une location de barnum" required=true}}</li>
			<li>{{:input type="date" name="date" label="Date du devis" placeholder="" required=true}}</li>
			<li>{{:input type="date" name="deadline" label="Échéance pour validation" placeholder="" required=false}}</li>
			<li>{{:input type="text" name="contact_info" label="Contact" default=$config.org_email required=true}}</li>
			<li>
				<dt><label for="status">Statut</label></dt>
				<dd>
					{{:input type="select" name="status" options=$status_options default=$status required=true}}
				</dd>
			</li>
		</ul>
	</fieldset>

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

	{{if $module.config.payment_detail || $module.config.quotation_extra_info}}
		<fieldset>
			<legend><h2>Informations complémentaires affichées en bas du devis</h2></legend>
			<ul>
			{{if $module.config.payment_detail}}
				<li>{{:input type="textarea" name="payment_detail" label="Instructions de paiement" default=$module.config.payment_detail}}</li>
			{{/if}}
			{{if $module.config.quotation_extra_info}}
				<li>{{:input type="textarea" name="extra_info" label="Informations complémentaires" default=$module.config.quotation_extra_info}}</li>
			{{/if}}
			</ul>
		<p>(La valeur pré-remplie de ces informations est modifiable dans la configuration du module.)</p>
		</fieldset>
	{{/if}}

	{{*<input type="submit" name="quotation_submit" label="" value="Valider la création de devis" />*}}
	<p class="submit">
		{{:button type="submit" name="quotation_submit" label="Valider la création de devis" class="main"}}
	</p>
</form>

{{:admin_footer}}

{{else}}
	{{:error message="Seuls les membres avec accès en lecture à la comptabilité peuvent visualiser cette page."}}
{{/restrict}}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































































































































































































































Modified src/skel-dist/modules/invoice/quotation.schema.json from [f795bf9dcc] to [de28802c8e].

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
			"type": ["array", "null"],
			"items": {
				"type": "object",
				"properties": {
					"name": { "type": "string", "minLength": 1, "maxLength": 128 },
					"description": { "type": "string", "maxLength": 512 },
					"unit_price": { "type": "number", "minimum": 0 },
					"quantity": { "type": "integer", "minimum": 0 }
				},
				"required" : ["name"]
			}
		},
		"total": {
			"description": "Total",
			"type": ["number", "integer"],







|







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
			"type": ["array", "null"],
			"items": {
				"type": "object",
				"properties": {
					"name": { "type": "string", "minLength": 1, "maxLength": 128 },
					"description": { "type": "string", "maxLength": 512 },
					"unit_price": { "type": "number", "minimum": 0 },
					"quantity": { "type": "number", "minimum": 0 }
				},
				"required" : ["name"]
			}
		},
		"total": {
			"description": "Total",
			"type": ["number", "integer"],