Overview
Comment: | Invoice module: ID and reference added to quotation's items |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | invoice_module |
Files: | files | file ages | folders |
SHA3-256: |
d61c451ab95f41bb3685b3ae3d5dbd5d |
User & Date: | alinaar on 2023-02-23 18:45:31 |
Other Links: | branch diff | manifest | tags |
Context
2023-02-24
| ||
16:11 | Invoice module: quotation creation/edition's strong validation implemented check-in: 8363c78855 user: alinaar tags: invoice_module | |
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 | |
Changes
Modified src/skel-dist/modules/invoice/details.html from [8b243d71f9] to [1e48361aa8].
︙ | ︙ | |||
93 94 95 96 97 98 99 | <li>Total : {{$total|floatval|money_currency:false}}</li> </ul> </fieldset> <fieldset> <legend><h2>Articles</h2></legend> {{if $items}} | | > > | 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 | <li>Total : {{$total|floatval|money_currency:false}}</li> </ul> </fieldset> <fieldset> <legend><h2>Articles</h2></legend> {{if $items}} <table id="item_list" class="list"> <tr> <th>Réf.</th> <th>Dénomination</th> <th>Description</th> <th>Prix unitaire</th> <th>Quantité</th> </tr> {{#foreach from=$items item='item'}} <tr> <td>{{$item.reference}}</td> <td>{{$item.name}}</td> <td>{{$item.description}}</td> <td>{{$item.unit_price|intval|money:false}}</td> <td>{{$item.quantity}}</td> </tr> {{/foreach}} </table> |
︙ | ︙ |
Modified src/skel-dist/modules/invoice/edit.html from [7b985d001b] to [584e57d50d].
1 2 3 4 5 6 7 8 9 10 11 12 | {{#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'}} | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | {{#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}} |
︙ | ︙ | |||
35 36 37 38 39 40 41 42 43 44 45 46 47 48 | {{: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}} | > | 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | {{: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.id' value=$index|intval}} {{: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}} |
︙ | ︙ | |||
135 136 137 138 139 140 141 | {{/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"> | > | > > > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | {{/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"> {{if !$document}} {{:button type="submit" name="quotation_submit" label="Valider la création de devis" class="main"}} {{else}} {{:button type="submit" name="quotation_submit" label="Modifier le devis" class="main"}} {{/if}} </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/include/item_list.tpl from [01c4314796] to [d16e7ab4b7].
1 2 3 4 5 6 7 8 | <script type="text/javascript"> function compute_total() { let items = document.getElementById('item_list').getElementsByClassName('item'); let total = 0.0; let unit_price; let quantity; for (let i = 0; i < items.length; ++i) { | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <script type="text/javascript"> function compute_total() { let items = document.getElementById('item_list').getElementsByClassName('item'); let total = 0.0; let unit_price; let quantity; for (let i = 0; i < items.length; ++i) { unit_price = items[i].children[3].firstChild.firstChild.value.replace(',', '.'); quantity = items[i].children[4].firstChild.value.replace(',', '.'); if (!isNaN(unit_price) && !isNaN(quantity) && unit_price > 0) total += parseFloat(unit_price) * parseFloat(quantity); } return total; } function refresh_total() { |
︙ | ︙ | |||
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 | <fieldset> <legend><h2>Liste des articles</h2></legend> <p id="item_list_no_item_message" style="display: {{if !$items}}block{{else}}none{{/if}};">Aucun article pour le moment.</p> <table id="item_list" class="list" style="display: {{if $items}}block{{else}}none{{/if}};"> <thead> <tr> <th>Dénomination</th> <th>Description</th> <th>Prix unitaire</th> <th>Quantité</th> <th></th> </tr> </thead> <tbody> {{#foreach from=$items key='key' item='item'}} <tr id={{"item_%d_row"|args:$key}} class="item" data-item-id="{{$key}}"> <td>{{:input type="text" name="items[%d][name]"|args:$key default=$item.name}}</td> <td>{{:input type="textarea" cols="50" rows="2" name="items[%s][description]"|args:$key default=$item.description class="full-width"}}</td> <td>{{:input type="money" name="items[%d][unit_price]"|args:$key default=$item.unit_price class="impact_total"}}</td> <td>{{:input type="number" name="items[%d][quantity]"|args:$key default=$item.quantity class="impact_total"}}</td> <td>{{:button name="item_%d_delete_button" label="" shape="delete" onclick="remove_item(%d)"|args:$key}}</td> </tr> {{/foreach}} | > > | 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 | <fieldset> <legend><h2>Liste des articles</h2></legend> <p id="item_list_no_item_message" style="display: {{if !$items}}block{{else}}none{{/if}};">Aucun article pour le moment.</p> <table id="item_list" class="list" style="display: {{if $items}}block{{else}}none{{/if}};"> <thead> <tr> <th>Réf.</th> <th>Dénomination</th> <th>Description</th> <th>Prix unitaire</th> <th>Quantité</th> <th></th> </tr> </thead> <tbody> {{#foreach from=$items key='key' item='item'}} <tr id={{"item_%d_row"|args:$key}} class="item" data-item-id="{{$key}}"> <td>{{:input type="text" name="items[%d][reference]"|args:$key default=$item.reference class="reference"}}</td> <td>{{:input type="text" name="items[%d][name]"|args:$key default=$item.name}}</td> <td>{{:input type="textarea" cols="50" rows="2" name="items[%s][description]"|args:$key default=$item.description class="full-width"}}</td> <td>{{:input type="money" name="items[%d][unit_price]"|args:$key default=$item.unit_price class="impact_total"}}</td> <td>{{:input type="number" name="items[%d][quantity]"|args:$key default=$item.quantity class="impact_total"}}</td> <td>{{:button name="item_%d_delete_button" label="" shape="delete" onclick="remove_item(%d)"|args:$key}}</td> </tr> {{/foreach}} |
︙ | ︙ |
Modified src/skel-dist/modules/invoice/include/style.tpl from [066e53cb5e] to [693e89cd54].
1 | <style> | | | | | 1 2 3 4 5 6 | <style> #item_list .reference { min-width: 0; max-width: 7em; } </style> |
Modified src/skel-dist/modules/invoice/item_form.html from [6acd31765f] to [4b3ccf311a].
︙ | ︙ | |||
20 21 22 23 24 25 26 27 28 29 30 31 32 33 | input.size = 8; input.class = 'money'; input.autocomplete = 'off'; } } if (name === 'unit_price' || name === 'quantity') input.classList.add('impact_total'); input.name = 'items[' + index + '][' + name + ']'; input.id = 'item_' + name + '_' + index; return (input); } function generate_item_empty_line() { let row_line; | > > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | input.size = 8; input.class = 'money'; input.autocomplete = 'off'; } } if (name === 'unit_price' || name === 'quantity') input.classList.add('impact_total'); if (name === 'reference') input.classList.add('reference'); input.name = 'items[' + index + '][' + name + ']'; input.id = 'item_' + name + '_' + index; return (input); } function generate_item_empty_line() { let row_line; |
︙ | ︙ | |||
41 42 43 44 45 46 47 | row_line.setAttribute('data-item-id', index); return row_line; } function add_item() { let row_line; let td; | | | | | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | row_line.setAttribute('data-item-id', index); return row_line; } function add_item() { let row_line; let td; let item_properties = [['reference', 'text'], ['name', 'text'], ['description', 'textarea'], ['unit_price', 'money'], ['quantity', 'number']]; let input; let nobr; row_line = generate_item_empty_line(); for (let i = 0; i < item_properties.length; ++i) { td = document.createElement('td'); td.classList.add('item_' + item_properties[i][0]); input = generate_item_input(item_properties[i][1], item_properties[i][0], row_line.id); input.value = document.getElementById('f_item_' + item_properties[i][0]).value; if (item_properties[i][1] === 'money') { nobr = document.createElement('nobr'); nobr.appendChild(input); input = nobr; } td.appendChild(input); row_line.appendChild(td); |
︙ | ︙ | |||
73 74 75 76 77 78 79 | } </script> <form method="POST" action="" id="item_creation_form" onsubmit="add_item()"> <fieldset> <legend>Ajouter un article</legend> <ul> | > | | > | > > | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | } </script> <form method="POST" action="" id="item_creation_form" onsubmit="add_item()"> <fieldset> <legend>Ajouter un article</legend> <ul> <li>{{:input type="text" name="item_reference" label="Référence" placeholder="ex : S-812"}}</li> <li>{{:input type="text" name="item_name" label="Dénomination" placeholder="ex : Location vélo - Forfait six jours"}}</li> <li>{{:input type="textarea" name="item_description" label="Description"}}</li> <li> <label for="item_unit_price">Prix unitaire</label><input type="text" name="item_unit_price" id="f_item_unit_price" label="" placeholder="" value="0" /> {{* Awaiting #eeb7d3e36ef4e3d7f2e8bc49c18c3c6b672f2e18 resolution {{:input type="money" name="item_unit_price" id="item_unit_price" label="Prix unitaire" default="0"}} *}} </li> <li>{{:input type="number" name="item_quantity" label="Quantité" default="1"}}</li> </ul> <input type="submit" name="" id="item_addition_button" value="Ajouter l'article au devis" /> </fieldset> </form> {{:admin_footer}} |
Modified src/skel-dist/modules/invoice/quotation.schema.json from [de28802c8e] to [0c8633bf2e].
︙ | ︙ | |||
29 30 31 32 33 34 35 36 37 38 39 40 | }, "items": { "description": "Articles", "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 } }, | > > | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | }, "items": { "description": "Articles", "type": ["array", "null"], "items": { "type": "object", "properties": { "id": { "type": "integer" }, "reference": { "type": "string", "maxLength": 128 }, "name": { "type": "string", "minLength": 1, "maxLength": 128 }, "description": { "type": "string", "maxLength": 512 }, "unit_price": { "type": "number", "minimum": 0 }, "quantity": { "type": "number", "minimum": 0 } }, "required" : ["id", "name"] } }, "total": { "description": "Total", "type": ["number", "integer"], "minimum": 0 }, |
︙ | ︙ |