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: |
a2f5d4d43dffe955a47d34b8cf61fe83 |
User & Date: | alinaar on 2023-03-10 17:02:31 |
Other Links: | branch diff | manifest | tags |
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 | |
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 | {{#restrict section="accounting" level="read"}} {{* ==================== Header ==================== *}} {{:admin_header title="Devis et factures" current="acc"}} | | | 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 | 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 | | | 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 | 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 | | | | 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 | 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 | | > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | | | | | | | | | | | | | | | | | | | > | | | > > > > | | > | | | > | 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 | </ul> </aside> {{:include file='./include/main_nav_tabs.html'}} </nav> {{* ======================= Feedback =========================== *}} | | | > > | | | | | | | | > > > > > > > | > | 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 | <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}} | > > > > > > > > > > > > > | < < < < | > | > > > > > > > > > > > > > > > > > > > > > | | 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 | {{#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;"> | > | | 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 | {{/if}} {{if $_POST.quotation_submit}} {{:assign computed_total=0}} {{:assign check_errors=null}} {{:assign items=null}} | < < < | | < < | 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 | {{:assign VERSION='0.2'}} | | > > | | | > | 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 | <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> | | | | 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 | {{* ==================== Listing ==================== *}} {{if $_GET.q}} <h2 class="ruler">Résultat(s) de recherche pour "{{$_GET.q}}"</h2> {{/if}} | | | | | | > > > > > > > | > > | | | 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 | <li>{{$config.org_web}}</li> {{/if}} <li>Contact : {{$org_contact}}</li> </ul> <ul class="customer_details"> <li> | | | 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 | <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 /> | | | 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 | "description": "Échéance", "type": ["string", "null"], "maxLength": 10 }, "status": { "description": "Statut", "type": "string", | | | 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 →" /> </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="→">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}} |