diff --git a/LICENSE b/LICENSE deleted file mode 100644 index efb9808..0000000 --- a/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/README.md b/README.md index 0a13046..80a255e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ -# materiel_reservation +# Module de gestion de matériels pour Paheko -Permet de gérer un inventaire de matériels, ainsi que de suivre les prêts, les réservations dans le logiciel Paheko \ No newline at end of file +Ce module permet de gérer les matériels de l'association: stock, +entrées, sorties, classés par catégorie. + +Un matériel peut entrer dans l'association : +- temporairement (location, emprunt, ...) +- définitivement (achat, ...) + +Dans les deux cas, il est possible de lui associer une écriture de la +compta ou un fichier. + +Un matériel appartenant à l'association peut sortir : +- temporairement (prêt, ...) : il est possible de lui associer un lieu + de stockage ainsi qu'un membre dépositaire du matériel et une date + de retour ; il peut ensuite revenir dans l'association. +- définitivement (vente, ...) : il est possible de lui associer un + membre bénéficiaire du matériel. + +Il est possible de suivre les matériels prêtés ou loués et de savoir +si la date de retour est proche ou dépassée. + +Un matériel présent temporairement dans l'association peut être +retourné à son propriétaire. + +Un matériel dont il n'existe plus d'exemplaire en stock peut être archivé. + +On peut lister l'ensemble des mouvements des matériels ou seulement +ceux d'un matériel donné. + +Il est possible de créer des catégories de matériels, des types +d'entrées et sorties, des lieux de stockage. + +## Réservations de matériel +Il est possible de réserver le matériel depuis le site web en mode anonyme +ou depuis l'interface des membres. Les réservations doivent être validées par un administrateur. + +## Droits d'accès +Le module est accessible uniquement pour les membres ayant au moins le +droit d'écriture en gestion des membres. \ No newline at end of file diff --git a/_filtres.tpl b/_filtres.tpl new file mode 100644 index 0000000..cda31cb --- /dev/null +++ b/_filtres.tpl @@ -0,0 +1,70 @@ +{{* + Inventaire des matériels en stock dans l'association ou chez les particuliers + Paramètres : + - cat_key : clé de la catégorie + - prop : =1 si matériel propriété de l'association, 0 sinon +*}} + +{{* filtrer selon la catégorie *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.cat_key == null}} + {{:assign selected_category=$user_filters.stock_cat_key}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} + {{:assign var="user_filters.stock_cat_key" value=$selected_category}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="$$.category = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition="1"}} +{{/if}} + +{{* filtrer selon appartenance *}} +{{if $_GET.prop == null}} + {{:assign selected_prop=$user_filters.stock_prop}} +{{else}} + {{if $_GET.prop == -1}} + {{:assign selected_prop=null}} + {{else}} + {{:assign selected_prop=$_GET.prop}} + {{/if}} + {{:assign var="user_filters.stock_prop" value=$selected_prop}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{if $selected_prop == null}} + {{:assign prop_condition="1"}} +{{elseif $selected_prop == 1}} + {{:assign prop_condition="$$.stock NOT NULL"}} +{{else}} + {{:assign prop_condition="$$.notowned != 0"}} +{{/if}} + +{{* sélecteurs de catégories et d'appartenances *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?cat_key=-1"}} +{{#load module="equipment" type="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$key value=$name}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?cat_key=%s"|args:$key + }} +{{/load}} +{{*:debug catopt=$cat_options*}} + +{{:assign var="prop_options." value="" label="Tous les matériels" href="?prop=-1"}} +{{:assign var="prop_options." value="1" label="Matériels propriété de l'association" href="?prop=1"}} +{{:assign var="prop_options." value="0" label="Matériels NON propriété de l'association" href="?prop=0"}} \ No newline at end of file diff --git a/_get_config.html b/_get_config.html new file mode 100644 index 0000000..6599026 --- /dev/null +++ b/_get_config.html @@ -0,0 +1,29 @@ +{{* -*- brindille -*- *}} + +{{* + Récupérer la config + résultat : config_defaut, directions, config.input_nature et config.output_nature +*}} + +{{* config par défaut *}} +{{:read file="./default.json" assign="config_defaut"}} +{{:assign config_defaut=$config_defaut|json_decode}} +{{:assign var="directions.input" value="entrée"}} +{{:assign var="directions.output" value="sortie"}} + +{{#foreach from=$directions key="direction"}} + {{* config par défaut *}} + {{:assign var="nature_defaut" from="config_defaut.%ss"|args:$direction}} + {{:assign keys_defaut=$nature_defaut|keys}} + {{#foreach from=$nature_defaut item="elem"}} + {{:assign var="config.%s_nature.%s"|args:$direction:$key value=$elem}} + {{/foreach}} + + {{* config enregistrée *}} + {{:assign var="nature" from="module.config.%s_nature"|args:$direction}} + {{#foreach from=$nature item="elem"}} + {{if ! $elem.key|in:$keys_defaut}} + {{:assign var="config.%s_nature.%s"|args:$direction:$key value=$elem}} + {{/if}} + {{/foreach}} +{{/foreach}} \ No newline at end of file diff --git a/_inventory.html b/_inventory.html new file mode 100644 index 0000000..66aa4b6 --- /dev/null +++ b/_inventory.html @@ -0,0 +1,148 @@ +{{* -*- brindille -*- *}} + +{{* + Inventaire des matériels en stock dans l'association +*}} + +{{* filtrer selon la catégorie *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.cat_key == null}} + {{:assign selected_category=$user_filters.stock_cat_key}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} + {{:assign var="user_filters.stock_cat_key" value=$selected_category}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="$$.category = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition="1"}} +{{/if}} + +{{* filtrer selon appartenance *}} +{{if $_GET.prop == null}} + {{:assign selected_prop=$user_filters.stock_prop}} +{{else}} + {{if $_GET.prop == -1}} + {{:assign selected_prop=null}} + {{elseif $_GET.prop == 1 || $_GET.prop == 0}} + {{:assign selected_prop=$_GET.prop}} + {{else}} + {{:assign selected_prop=$user_filters.stock_prop}} + {{/if}} + {{:assign var="user_filters.stock_prop" value=$selected_prop}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{if $selected_prop == null}} + {{:assign prop_condition="1"}} +{{elseif $selected_prop == 1}} + {{:assign prop_condition="$$.stock NOT NULL"}} +{{else}} + {{:assign prop_condition="$$.notowned != 0"}} +{{/if}} + +{{* sélecteurs de catégorie et d'appartenance *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?cat_key=-1"}} +{{#load type="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$key value=$name}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?cat_key=%s"|args:$key + }} +{{/load}} + +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +{{:assign var="prop_options." value="" label="Tous les matériels" href="?prop=-1"}} +{{:assign var="prop_options." value="1" label="Matériels propriété de l'association" href="?prop=1"}} +{{:assign var="prop_options." value="0" label="Matériels NON propriété de l'association" href="?prop=0"}} + +
+ Filtrer par appartenance + {{:dropdown + title="Filtrer par appartenance" + options=$prop_options + value="%s"|args:$selected_prop + }} +
+ +
+

Inventaire des matériels présents dans l'association

+
+ +{{#list + select=" + $$.name AS 'Matériel' ; + (SELECT $$.name + FROM @TABLE as cat + WHERE cat.key = @TABLE.$$.category) AS 'Catégorie' ; + $$.stock AS 'Stock' ; + (SELECT COALESCE($$.notowned, 0)) AS 'Temp' ; + (SELECT $$.stock + COALESCE($$.notowned, 0)) AS 'Total' ; + $$.out AS 'Sorti' ; + (SELECT $$.stock - $$.out) AS 'Disponible' + " + type="equipment" + where="$$.status <> 'archived' AND %s AND %s"|args:$cat_condition:$prop_condition + order=1 + }} + {{:assign var=cat_name from=categories.%s|args:$category}} + + {{if $selected_prop == null}} + {{:assign prop=""}} + {{else}} + {{:assign prop="&prop=%s"|args:$selected_prop}} + {{/if}} + {{:link href="equipment_history.html?key=%s&prop=%s"|args:$key:$selected_prop label=$name}} + {{$cat_name}} + {{$stock}} + {{$col4}} + {{$col5}} + {{$out}} + {{$col7}} + + {{:linkbutton + label="Mouvements" + href="equipment_history.html?key=%s&prop=%s"|args:$key:$selected_prop + shape="table"}} + {{:linkbutton + label="Modifier" + href="modify_equipment.html?key=%s&prop=%s"|args:$key:$selected_prop + shape="edit" + target="_dialog"}} + + +{{else}} +

Aucun matériel.

+{{/list}} + + + \ No newline at end of file diff --git a/_nav.html b/_nav.html new file mode 100644 index 0000000..39c17ca --- /dev/null +++ b/_nav.html @@ -0,0 +1,83 @@ +{{* -*- brindille -*- *}} + \ No newline at end of file diff --git a/_resa_date_check.html b/_resa_date_check.html new file mode 100644 index 0000000..994fd82 --- /dev/null +++ b/_resa_date_check.html @@ -0,0 +1,30 @@ +{{* Vérifier la date de réservation + - loan_date + *}} +{{:assign loan_date=$loan_date|parse_date}} +{{#select + count(td_web.key) AS CNT + FROM !table AS td_web + WHERE ((:date BETWEEN $$.loan_date AND $$.return_date) AND $$.equipment={$equipment_key|strval}) + ; + !table=module_data_web + :date=$loan_date + }} + + {{if $CNT>=1}} + {{:error message="La date indiquée est déjà réservée !"}} + {{/if}} +{{/select}} +{{#select + count(td_equ.key) AS CNT + FROM !table AS td_equ + WHERE ((:date BETWEEN $$.loan_date AND $$.return_date) AND $$.equipment={$equipment_key|strval}) + ; + !table=module_data_equipment + :date=$loan_date + }} + + {{if $CNT>=1}} + {{:error message="La date indiquée est déjà réservée !"}} + {{/if}} +{{/select}} \ No newline at end of file diff --git a/_resa_inventory.html b/_resa_inventory.html new file mode 100644 index 0000000..98f2532 --- /dev/null +++ b/_resa_inventory.html @@ -0,0 +1,225 @@ +{{* -*- brindille -*- *}} + +{{* + Inventaire des matériels en stock dans l'association +*}} + +{{* filtrer selon la catégorie *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.cat_key == null}} + {{:assign selected_category=$user_filters.stock_cat_key}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} + {{:assign var="user_filters.stock_cat_key" value=$selected_category}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="$$.category = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition="1"}} +{{/if}} + +{{* filtrer selon appartenance *}} +{{if $_GET.prop == null}} + {{:assign selected_prop=$user_filters.stock_prop}} +{{else}} + {{if $_GET.prop == -1}} + {{:assign selected_prop=null}} + {{elseif $_GET.prop == 1 || $_GET.prop == 0}} + {{:assign selected_prop=$_GET.prop}} + {{elseif $_GET.prop == 1 || $_GET.prop == 0}} + {{:assign selected_prop=$_GET.prop}} + {{else}} + {{:assign selected_prop=$user_filters.stock_prop}} + {{/if}} + {{:assign var="user_filters.stock_prop" value=$selected_prop}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{if $selected_prop == null}} + {{:assign prop_condition="1"}} +{{elseif $selected_prop == 1}} + {{:assign prop_condition="$$.stock != 0"}} +{{else}} + {{:assign prop_condition="$$.notowned != 0"}} +{{/if}} + +{{* sélecteurs de catégorie et d'appartenance *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?cat_key=-1"}} +{{#load type="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$key value=$name}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?cat_key=%s"|args:$key + }} +{{/load}} + +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +{{:assign var="prop_options." value="" label="Tous les matériels" href="?prop=-1"}} +{{:assign var="prop_options." value="1" label="Matériels propriété de l'association" href="?prop=1"}} +{{:assign var="prop_options." value="0" label="Matériels NON propriété de l'association" href="?prop=0"}} + +
+ Filtrer par appartenance + {{:dropdown + title="Filtrer par appartenance" + options=$prop_options + value="%s"|args:$selected_prop + }} +
+ +

Inventaire des matériels présents dans l'association et réservations

+

Légende :
+ {{:icon shape="check"}} : réservation acceptée
+ {{:icon shape="help"}} : réservation en attente de traitement
+ {{:icon shape="calendar"}} : réservation non traitée à temps (périmée) ou date de retour dépassée !
+ {{:icon shape="import"}} : date de retour échue !
+ {{:icon shape="export"}} : réservation en cours +

+ + +{{* Liste des réservations *}} +{{:include file="_resa_load.html" st_condition="WHERE 1=1" st_condition_cal="1=1" keep="_resa_lignes"}} + +{{* Liste de matériel *}} +{{#list + select=" + $$.name AS 'Matériel' ; + (SELECT $$.name FROM @TABLE as cat WHERE cat.key = @TABLE.$$.category) AS 'Catégorie' ; + $$.stock AS 'Stock' ; + (SELECT COALESCE($$.notowned, 0)) AS 'Stock Temp.' ; + (SELECT $$.stock + COALESCE($$.notowned, 0)) AS 'Total' ; + $$.out AS 'Sorti' ; + (SELECT $$.stock + COALESCE($$.notowned, 0) - $$.out) AS 'Disponible'; + (SELECT 0) AS 'Reservation(s)' + " + type="equipment" + where="$$.status <> 'archived' AND %s AND %s"|args:$cat_condition:$prop_condition + order=1 + }} + {{:assign var=cat_name from=categories.%s|args:$category}} + + {{* Charge les réservations pour le matériel *}} + {{:assign _resa_count=0}} + {{:assign _resa_status=null}} + + {{#foreach from=$_resa_lignes}} + {{if $equipment == $key}} + {{if $status == "acceptée"}} + {{:assign var="_resa_status.%s"|args:$wres_key value=$status shape="check" href="reservation/resa_details.html?key=%s"|args:$wres_key}} + {{:assign var="_resa_count" value="%d+1"|math:$_resa_count|intval}} + {{elseif $status == "en cours"}} + {{:assign var="_resa_count" value="%d+1"|math:$_resa_count|intval}} + {{* Si date de retour est < now : matériel à récupérer ! *}} + {{if $return_date|strtotime < $now}} + {{*:debug return_date=$return_date|strtotime now=$now *}} + {{:assign var="_resa_status.%s"|args:$wres_key value="retour" shape="import" href="reservation/resa_details.html?key=%s"|args:$wres_key}} + {{else}} + {{:assign var="_resa_status.%s"|args:$wres_key value="retour" shape="export" href="reservation/resa_details.html?key=%s"|args:$wres_key}} + {{/if}} + {{elseif $status == "en attente" }} + {{* Vérifie la date *}} + {{*:debug date=$loan_date|strtotime now=$now key=$wres_key*}} + {{if $loan_date|strtotime < $now}} + {{:assign var="_resa_status.%s"|args:$wres_key value="périmée" shape="calendar" href="reservation/resa_details.html?key=%s"|args:$wres_key}} + {{else}} + {{:assign var="_resa_status.%s"|args:$wres_key value=$status shape="help" href="reservation/resa_details.html?key=%s"|args:$wres_key}} + {{/if}} + {{:assign var="_resa_count" value="%d+1"|math:$_resa_count|intval}} + {{*elseif $equipment_resa.status == "refusée" || $equipment_resa.status == "archivée"}} + {{:assign var="_resa_status.%s"|args:$wres_key value=null href=null}} + {{:assign var="_resa_count" value="%d-1"|math:$_resa_count|intval*}} + {{/if}} + {{/if}} + {{/foreach}} + + {{if $selected_prop == null}} + {{:assign prop=""}} + {{else}} + {{:assign prop="&prop=%s"|args:$selected_prop}} + {{/if}} + + {{* Valeur prop/temp en fonction de l'appartenance de l'objet *}} + {{if $stock >= 1}} + {{:assign prop=1}} + {{else}} + {{:assign prop=0}} + {{/if}} + + {{if $is_admin}} + {{:link href="equipment_history.html?key=%s&prop=%s"|args:$key:$prop label=$name}} + {{else}} + {{:link href="index.html?key=%s&prop=%s&fonc=voir"|args:$key:$prop label=$name}} + {{/if}} + + {{$cat_name}} + {{$stock}} + {{$col4}} + {{$col5}} + {{$out}} + {{$col7}} + {{*:debug _eq_resa_status=$_resa_status*}} + {{if $_resa_count > 0}} + + {{#foreach from=$_resa_status key="key" item="value"}} + {{*$key}} - {{$value.value}} - {{$href*}} + {{if $value.value == "acceptée" || $value.value == "en attente" || $value.value == "périmée" || $value.value == "retour"}} + {{if $is_admin}} + {{*:linkbutton href=$href label=$value.value shape=$shape*}} + {{:linkbutton href=$href shape=$shape}} + {{else}} + {{$_resa_count}} + {{/if}} + {{/if}} + {{/foreach}} + + {{else}} + {{$col8}} + {{/if}} + + {{if $is_admin}} + {{:linkbutton label="Mouvements" href="equipment_history.html?key=%s&prop=%d"|args:$key:$prop shape="table"}} + {{:linkbutton label="Modifier" href="modify_equipment.html?key=%s&prop=%d"|args:$key:$prop shape="edit" target="_dialog"}} + {{else}} + {{if $stock >= 1}} + {{:linkbutton label="Réserver" href="index.html?key=%s&fonc=resa"|args:$key shape="table"}} + {{else}} + {{:linkbutton label="Contactez nous" href="/contact.html?key=%s&fonc=resa"|args:$key shape="mail" target="_dialog"}} + {{/if}} + {{/if}} + + +{{else}} +

Aucun matériel.

+{{/list}} + + + \ No newline at end of file diff --git a/_resa_load.html b/_resa_load.html new file mode 100644 index 0000000..7950c5c --- /dev/null +++ b/_resa_load.html @@ -0,0 +1,21 @@ +{{* + Charge les réservations depuis WEB et EQUIPMENT + Cette page doit être incluse avec le paramètre suivant : + - st_condition & st_condition_cal +*}} + {{*:debug st_condition_cal=$st_condition_cal*}} + {{#load module=web type="reservation" assign="web_resa_lignes." where="$$.equipment IS NOT NULL AND %s"|args:$st_condition_cal}} + {{/load}} + {{*:debug lignes=$web_resa_lignes*}} + {{* Liste des réservations des membres : module_data_equipment *}} + {{#load module="%s"|args:$module.name type="reservation" assign="equ_resa_lignes." where="$$.equipment IS NOT NULL AND %s"|args:$st_condition_cal}} + {{/load}} + {{*:debug lignes=$equ_resa_lignes*}} + + {{* Liste des réservations des membres et non membres : merge les 2 listes *}} + {{#foreach from=$equ_resa_lignes}} + {{:assign var="_resa_lignes." wres_id=$id wres_key=$key member=$member name=$name contact=$contact equipment=$equipment amount=$amount loan_date=$loan_date return_date=$return_date comment=$comment shape="print" signed=$signed status=$status}} + {{/foreach}} + {{#foreach from=$web_resa_lignes}} + {{:assign var="_resa_lignes." wres_id=$id wres_key=$key member=$member name=$name contact=$contact equipment=$equipment amount=$amount loan_date=$loan_date return_date=$return_date comment=$comment shape="globe" signed=$signed status=$status}} + {{/foreach}} diff --git a/_resa_status_color.html b/_resa_status_color.html new file mode 100644 index 0000000..2de86f0 --- /dev/null +++ b/_resa_status_color.html @@ -0,0 +1,31 @@ +{{* + Renvoi un joli texte coloré en fonction du status de la réservation + Cette page doit être incluse avec la variable suivante valorisée : + - status = [acceptée,refusée,archivée,en attente(périmée)] + Options : + - color_only = [true] +*}} +{{if $status}} + {{if $status == "acceptée"}} + {{*:assign var="_tag_color" value="--tag-color: lightgreen;"*}} + {{:assign _tag_color="lightgreen" _text_color="black"}} + {{elseif $status == "refusée"}} + {{:assign _tag_color="darksalmon" _text_color="black"}} + {{elseif $status == "archivée"}} + {{:assign _tag_color="lightgrey" _text_color="black"}} + {{elseif $status == "en attente"}} + {{:assign _tag_color="lightblue" _text_color="black"}} + {{elseif $status == "périmée"}} + {{:assign _tag_color="darkred" _text_color="white"}} + {{elseif $status == "en cours"}} + {{:assign _tag_color="darkblue" _text_color="white"}} + {{/if}} +{{else}} + {{:assign _tag_color="darkorchid" _text_color="white"}} + {{* +
Supprimée
+ *}} +{{/if}} +{{if !$color_only}} +
{{$status|or:"Supprimée"}}
+{{/if}} \ No newline at end of file diff --git a/_web_calendar.html b/_web_calendar.html new file mode 100644 index 0000000..c582a81 --- /dev/null +++ b/_web_calendar.html @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/_web_contract.html b/_web_contract.html new file mode 100644 index 0000000..4283546 --- /dev/null +++ b/_web_contract.html @@ -0,0 +1,296 @@ +{{* -*- brindille -*- *}} +{{if $_POST.signed && $_POST.rid >= 1}} + {{:save id=$_POST.rid + type="reservation" + signed=$_POST.signed|trim + }} +

Réservation effectuée et signée

+ {{if !$is_logged}} + {{* Invité Ano *}} + {{:linkbutton label="Télécharger la convention" href="./equipment.html?ok=1&fonc=save_resa&rid=%s"|args:$_POST.rid shape="reset" target="_dialog"}} + {{:linkbutton label="Retour" href="./equipment.html?ok=1&fonc=saved_resa&rid=%s"|args:$_POST.rid shape="home"}} + {{else}} + {{* Admin *}} + {{#restrict section="accounting" level="write"}} + {{:admin_header title="Réservation"}} + {{:linkbutton label="Télécharger la convention" href="%sequipment.html?ok=1&fonc=save_resa&rid=%s"|args:$site_url:$_POST.rid shape="reset" target="_blank"}} + {{#load id=$_POST.rid assign="resa"}} + {{:linkbutton label="Retour" href="?key=%s"|args:$resa.key shape="home"}} + {{/load}} + {{* Membre *}} + {{else}} + {{:linkbutton label="Télécharger la convention" href="%sequipment.html?ok=1&fonc=save_resa&rid=%s"|args:$site_url:$_POST.rid shape="reset" target="_dialog"}} + {{:linkbutton label="Retour" href="./index.html?ok=1&fonc=saved_resa&rid=%s"|args:$_POST.rid shape="home"}} + {{/restrict}} + {{/if}} +{{else}} + {{* + Réservation d'un matériel - Convention (membre et non-membre) + *}} + + + + {{if !$is_logged}} + {{* Invité Ano *}} + {{:assign _module="web"}} + {{else}} + {{:assign _module="equipment"}} + {{/if}} + + {{:assign reservation_id=$_GET.rid|trim}} + {{* récupérer les infos de la réservation *}} + {{#load module="%s"|args:$_module id=$reservation_id assign="resa"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$reservation_id}} + {{/load}} + {{*:debug rsa=$resa*}} + {{* récupérer les infos du matériel associé *}} + {{#load module="equipment" key=$resa.equipment assign="equipment"}} + {{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$resa.equipment}} + {{/load}} + {{#load module="equipment" key=$equipment.category assign="category"}}{{/load}} + {{*:debug rsa=$equipment*}} + {{#module name="equipment"}} + {{*Sa configuration est : {{:debug config=$config}}*}} + {{:assign var="states" value=$config.states|explode:","}} + {{:assign var="_equip_config_state" from="states.%d"|args:$equipment.state}} + {{*:debug config=$_equip_config_states*}} + {{* Récupère le membre si présent *}} + {{if $config.member >= 1}} + {{#users id=$config.member}} + {{:assign var="_rep_name" value=$_name}} + {{/users}} + {{/if}} + {{else}} + Le module Équipement est désactivé. + {{/module}} + + {{* formulaire contrat de location de matériel *}} +
+
+ Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}}) +

Convention de prêt de matériel

+

Entre les soussignés :

+

Nom de l’association : {{$config.org_name}}

+

Adresse du siège : {{$config.org_full_address}}

+

Représentée par : {{$_rep_name}}

+

Fonction : Membre du conseil collégial

+

Ci-après dénommée « l’Association ».

+ +

Emprunteur

+

Nom : {{$resa.name}}

+

Adresse : {{$resa.address}}

+

Contact(Tel/email) : {{$resa.contact}} / {{$resa.email}}

+

N° d’adhérent : {{$resa.member}}

+

Ci-après dénommé « l’Emprunteur ».

+ +

Il a été convenu ce qui suit :

+ +

Article 1 — Objet de la convention

+

L’Association met à disposition de l’Emprunteur, à titre gratuit, le matériel suivant :

+

Désignation : {{$equipment.name}}

+

Description :

{{$equipment.description}}
+

Numéro de série : {{$equipment.serialno}}

+

État du matériel au moment du prêt : {{$_equip_config_state}}

+

Accessoires fournis :

+
+ +

Article 2 — Durée du prêt

+

Le présent prêt est consenti :

+

À compter du : {{$now|date_short}}

{{*$resa.loan_date|date_short*}} +

Jusqu’au : {{$resa.return_date|date_short}}

+

+ Le matériel devra être restitué au plus tard à cette date, sauf accord préalable de l’Association. +

+ +

Article 3 — Conditions d’utilisation

+

+ L’emprunteur s’engage à :
+

    +
  • Utiliser le matériel conformément à son usage normal et dans le respect des règles de sécurité,
  • +
  • Prendre toutes les précautions nécessaires pour éviter toute dégradation, perte ou vol,
  • +
  • Ne pas prêter ou céder le matériel à un tiers,
  • +
  • Restituer le matériel propre et dans l’état dans lequel il a été remis, hors usure normale,
  • +
  • Remplacer les consommables prêtés avec le matériel,
  • +
  • Signaler immédiatement tout dysfonctionnement ou incident.
  • +
+

+ +

Article 4 — Assurance responsabilité civile

+

+ L’emprunteur certifie être couvert par une assurance responsabilité civile en cours de validité
+ couvrant les dommages pouvant être causés aux tiers ainsi que, le cas échéant, les dommages liés
+ à l’utilisation du matériel prêté.
+ Une attestation d’assurance pourra être demandée par le prêteur avant la remise du matériel.
+ À défaut d’assurance valide, le prêteur pourra refuser la mise à disposition du matériel. +

+ +

Article 5 — Responsabilité

+

L’emprunteur est responsable du matériel pendant toute la durée du prêt.
+ En cas de détérioration, perte ou vol, l’emprunteur s’engage à :
+

    +
  • Informer immédiatement l’Association ;
  • +
  • Prendre en charge les frais de réparation ou de remplacement du matériel, sauf décision contraire du bureau de l’Association ou cas de force majeure.
  • +
+

+ +

Article 6 — Restitution

+

+ La restitution du matériel aura lieu : +

Lieu : Ressourcerie / chez le prêteur

+

Date : {{$resa.return_date|date_short}}

+ Un état du matériel pourra être réalisé contradictoirement lors du retour. +

+ + {{* TODO : gratuit (membres) ou payant ? *}} + {{#foreach from=$equipment.fields key="key"}} + {{if $label >= "Tarif par jour"}} + {{:assign var="prix" value=$value}} + {{/if}} + {{/foreach}} + {{if $prix >= 1}} +

Article 7 — Tarif

+

L'emprunteur s'engage a régler à l'association le tarif journalier de {{$prix}}€.

+ {{else}} +

Article 7 — Gratuité

+

Le présent prêt est consenti à titre gratuit et sans contrepartie financière.

+ {{/if}} + +

Article 8 — Litiges

+

Les parties s’efforceront de régler à l’amiable tout différend relatif à l’exécution de la présente convention.
+ À défaut d’accord amiable, le litige relèvera des juridictions compétentes.

+

Signatures

+

Fait à : L'île d'Arz

+

Le : {{$resa.date|date_long}}

+ +
+
+

Pour l’Association

+

Nom : {{$_rep_name}}

+

Fonction : Membre du conseil collégial

+

Signature

+
+ {{:input class="signature" type="text" name="assosigned" required=true default=$_rep_name readonly=true}} + {{*:captcha html=true verify=true*}} +
+
+
+

L’Emprunteur

+

Signature

+
+ {{:input class="signature" type="text" name="signed" required=true label="Tapez votre nom pour signer le document" default=$resa.name }} + {{*:captcha html=true verify=true*}} +
+
+
+
+

+ {{:input type="hidden" name="rid" required=true default=$resa.id readonly=true}} + {{:button type="submit" name="sign" label="Signer" value="res" shape="right" class="icn-btn"}} +

+
+{{/if}} \ No newline at end of file diff --git a/_web_inventory.html b/_web_inventory.html new file mode 100644 index 0000000..6738754 --- /dev/null +++ b/_web_inventory.html @@ -0,0 +1,196 @@ +{{* -*- brindille -*- *}} +{{* + Inventaire des matériels en stock dans l'association ou chez les particuliers + Paramètres : + - cat_key : clé de la catégorie + - prop : =1 si matériel propriété de l'association, 0 sinon +*}} + +{{* filtrer selon la catégorie *}} +{{if $_GET.cat_key == null}} + {{:assign selected_category=null}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} +{{/if}} + +{{* -- Conditions de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="$$.category = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition="1"}} +{{/if}} + +{{* filtrer selon appartenance *}} +{{if $_GET.prop == null}} + {{:assign selected_prop=null}} +{{else}} + {{if $_GET.prop == -1}} + {{:assign selected_prop=null}} + {{else}} + {{:assign selected_prop=$_GET.prop}} + {{/if}} +{{/if}} +{{if $selected_prop == null}} + {{:assign prop_condition="1"}} +{{elseif $selected_prop == 1}} + {{:assign prop_condition="$$.stock != 0"}} +{{else}} + {{:assign prop_condition="$$.notowned != 0"}} +{{/if}} +{{:assign var="prop_options." value="" label="Tous les matériels" href="?prop=-1"}} +{{:assign var="prop_options." value="1" label="Matériels propriété de l'association" href="?prop=1"}} +{{:assign var="prop_options." value="0" label="Matériels NON propriété de l'association" href="?prop=0"}} +{{*:debug propopt=$prop_options selected_prop=$selected_prop*}} + + +{{* sélecteurs de catégories et d'appartenances *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?cat_key=-1"}} +{{#load module="equipment" type="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$key value=$name}} + {{:assign var="cat_options." value=$key label=$name href="?cat_key=%s"|args:$key}} +{{/load}} +{{*:debug cats=$categories selected_category=$selected_category cat_key=$cat_key cat_condition=$cat_condition *}} +{{* +
+

Inventaire des matériels présents dans l'association

+
+*}} +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} + Filtrer par appartenance + {{:dropdown + title="Filtrer par appartenance" + options=$prop_options + value="%s"|args:$selected_prop + }} +
+
+ {{*:linkbutton class="main" label="Affichage vignette" href="equipment.html?prop=%s&cat_key=%s&fonc=inv2"|args:$selected_prop:$selected_category shape="list-ul"*}} + {{:linkbutton class="main" label="Affichage Mobile" href="equipment.html?prop=%s&cat_key=%s&fonc=inv3"|args:$selected_prop:$selected_category shape="list-ul"}} +
+{{* + +*}} +{{* +
+ + + ☰ +
+*}} + + +{{*:debug catcond=$cat_condition*}} +{{*:debug propcond=$prop_condition*}} + +{{#list module="equipment" + select=" + $$.name AS 'Matériel' ; + (SELECT $$.name + FROM @TABLE as cat + WHERE cat.key = @TABLE.$$.category) AS 'Catégorie' ; +{{* $$.stock AS 'Stock' ; + (SELECT COALESCE($$.notowned, 0)) AS 'Temp' ; + (SELECT $$.stock + COALESCE($$.notowned, 0)) AS 'Total' ; +*}} + $$.out AS 'Sorti' ; + (SELECT $$.stock - $$.out) AS 'Disponible' + " + type="equipment" + where="$$.status <> 'archived' AND %s AND %s"|args:$cat_condition:$prop_condition + order=1 + max=10 + }} + {{:assign var=cat_name from=categories.%s|args:$category}} + + {{if $selected_prop == null}} + {{:assign prop=""}} + {{else}} + {{:assign prop="&prop=%s"|args:$selected_prop}} + {{/if}} + {{:link href="equipment.html?key=%s&fonc=voir"|args:$key label=$name}} + {{$cat_name}} +{{* {{$stock}} + {{$col4}} + {{$col5}} + {{$out}} + {{$col7}} +*}} + {{$out}} + {{$col4}} + + {{*if $col4 >= 1}} + {{:linkbutton class="main" label="Réserver" href="equipment.html?key=%s&fonc=resa"|args:$key shape="plus"}} + {{else}} + {{:linkbutton class="main" label="Contacter nous!" href="contact.html?key=%s&fonc=resa"|args:$key shape="plus"}} + {{/if*}} + + + {{* Sauvegarde chaque entrée dans une variable *}} + {{*:assign var="_equipment.%s"|args:$key name=$name catname=$cat_name out=$out dispo=$col4 href="equipment.html?key=%s&fonc=voir"|args:$key*}} + {{* + Charge les réservations acceptées/refusées/archivées de ce matériel depuis le module equipment. + Met a jour le status de la réservation dans le module web + TODO à supprimer + *}} + {{*#load module="equipment" type="reservation" equipement_id=$id assign="reservations"}} + {{*:debug reservations=$reservations}} + {{*:save key="%s"|args:$reservations.key status=$reservations.status|strval}} + {{else}} + {{*error: message="Pas de réservations pour ce matériel %s"|args:$equipment.id}} + {{/load*}} +{{else}} +

Aucun matériel.

+{{/list}} +{{* + +*}} \ No newline at end of file diff --git a/_web_inventory2.html b/_web_inventory2.html new file mode 100644 index 0000000..ced09cd --- /dev/null +++ b/_web_inventory2.html @@ -0,0 +1,150 @@ +{{* -*- brindille -*- *}} +{{* + Inventaire sous forme de vignettes des matériels en stock dans l'association ou chez les particuliers + Paramètres : + - cat_key : =-1 toutes, ou n° de la catégorie + - prop : =1 si matériel propriété de l'association, 0 sinon +*}} + +{{* filtrer selon l'appartenance *}} +{{if $_GET.prop == null}} + {{:assign selected_prop=null}} +{{else}} + {{:assign selected_prop=$_GET.prop}} +{{/if}} + +{{* filtrer selon la catégorie *}} +{{if $_GET.cat_key == null}} + {{:assign selected_category=null}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="key = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition="1"}} +{{/if}} + +{{* sélecteurs de catégories *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?fonc=inv2&cat_key=-1"}} +{{#load module="equipment" type="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$key value=$name}} + {{:assign var="cat_options." value=$key label=$name href="?fonc=inv2&cat_key=%s"|args:$key }} +{{/load}} + +{{*:debug cats=$categories selected_category=$selected_category cat_key=$cat_key cat_condition=$cat_condition *}} + +
+

Inventaire des matériels présents dans l'association

+
+
+ {{:linkbutton class="main" label="Affichage liste" href="equipment.html?prop=%s&cat_key=%s&fonc=inv"|args:$selected_prop:$selected_category shape="list-ul"}} +
+{{* +
+ Filtrer +
+ + ☰ +
+
+*}} +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +{{* Affichage des équipements en mode vignette *}} +{{#load module="equipment" type="category" where=$cat_condition}} + {{:assign lignes=null}} + {{#select + td_equ.key AS wequ_key, + json_extract(td_equ.document, '$.name') AS "name", + json_extract(td_equ.document, '$.category') AS "category", + (SELECT json_extract(cat.document, '$.name') AS "catname" FROM !table as cat WHERE cat.key=json_extract(td_equ.document, '$.category')) AS catname, + json_extract(td_equ.document, '$.status') AS "status", + json_extract(td_equ.document, '$.stock') AS "stock", + json_extract(td_equ.document, '$.out') AS "out", + json_extract(td_equ.document, '$.notowned') AS "notowned", + json_extract(td_equ.document, '$.state') AS "state", + json_extract(td_equ.document, '$.serialno') AS "serialno", + json_extract(td_equ.document, '$.description') AS "description", + json_extract(td_equ.document, '$.member') AS "member", + json_extract(td_equ.document, '$.images') AS "images", + img.value AS image + FROM !table AS td_equ + LEFT JOIN json_each(td_equ.document, '$.images') img + WHERE ($$.category={$key|strval}) + ORDER BY (catname) + ; + !table=module_data_equipment + assign="lignes." + }} + {{* + FROM !table AS td_equ, json_each(td_equ.document, '$.images') img + WHERE ($$.images NOT NULL AND $$.category={$key|strval}) + ORDER BY (catname) + {{$name}} {{$image}} {{$catname}}
*}} + {{else}} + {{/select}} + {{if $lignes}} +
+ {{$name}} + + + {{#foreach from=$lignes}} + {{if $_key!=$wequ_key}} + + {{/if}} + {{/foreach}} + +
+ {{:assign var="_key" value=$wequ_key}} + {{*:debug img=$image*}} + {{if $image === null}} + {{:assign var="_image" value="equipment_no_image.png"|url_encode}} + {{:assign var="thumbnail_src" value="%s?h=%s"|args:$_image:$version_hash}} + {{:assign var="img_src" value="%s"|args:$_image}} + {{else}} + {{:assign var="_image" value=$image|url_encode}} + {{:assign var="thumbnail_src" value="/ext/m/equipment/public/image-%s/%s.150px.webp?h=%s"|args:$_key:$_image:$version_hash}} + {{:assign var="img_src" value="/ext/m/equipment/public/image-%s/%s"|args:$wequ_key:$_image}} + {{/if}} +
+
{{:link href="equipment.html?key=%s&fonc=voir"|args:$_key label=$name}} + {{$description}} +
+ {{* Reservation si stock dispo *}} + {{:assign _dispo="%d-%d"|math:$stock:$out}} + {{if $_dispo >= 1}} +   + {{:linkbutton label="Réserver" href="equipment.html?key=%s&fonc=resa"|args:$_key shape="plus"}} + {{else}} +   + {{:linkbutton label="Contacter nous!" href="contact.html?key=%s&fonc=resa"|args:$_key shape="plus"}} + {{/if}} +
+
+
+ {{/if}} +{{/load}} \ No newline at end of file diff --git a/_web_inventory3.html b/_web_inventory3.html new file mode 100644 index 0000000..d53f168 --- /dev/null +++ b/_web_inventory3.html @@ -0,0 +1,133 @@ +{{* -*- brindille -*- *}} +{{*:assign var=page.title value="Notre Matériel"}} +{{:assign var=page.path value="equipment.html"}} +

{{$page.title|remove_leading_number}}

+*}} + +{{* liste des catégories *}} +{{#sql select="json_extract(document, '$.name') as catname" tables="module_data_equipment" where="json_extract(document, '$.type') = 'category'"}} + {{:assign var="cat_options." value=$catname|strval label=$catname }} +{{/sql}} +{{*:debug cat_options=$cat_options*}} + +
+
+ Filtrer par catégorie +
{{:input name="cat" type="select" default_empty="Toutes les catégories" options=$cat_options label="Catégorie"}}
+
+
+
+ {{:linkbutton class="main" label="Affichage liste" href="equipment.html?prop=%s&cat_key=%s&fonc=inv"|args:$selected_prop:$selected_category shape="list-ul"}} +
+ +{{* lister les états matériels possibles *}} +{{#module name="equipment"}} + {{:assign var="states" value=$config.states|explode:","}} +{{/module}} + +{{* Affichage des équipements en mode vignette *}} +{{#load module="equipment" type="category" where=$cat_condition}} + {{:assign lignes=null}} + {{#select + td_equ.id AS wequ_id, + td_equ.key AS wequ_key, + json_extract(td_equ.document, '$.name') AS "name", + json_extract(td_equ.document, '$.category') AS "category", + (SELECT json_extract(cat.document, '$.name') AS "catname" FROM !table as cat WHERE cat.key=json_extract(td_equ.document, '$.category')) AS catname, + (SELECT json_extract(mvt.document, '$.date') AS "mvtdate" FROM !table as mvt WHERE td_equ.key=json_extract(mvt.document, '$.equipment')) AS mvtdate, + json_extract(td_equ.document, '$.status') AS "status", + json_extract(td_equ.document, '$.stock') AS "stock", + json_extract(td_equ.document, '$.out') AS "out", + json_extract(td_equ.document, '$.notowned') AS "notowned", + json_extract(td_equ.document, '$.state') AS "state", + json_extract(td_equ.document, '$.serialno') AS "serialno", + json_extract(td_equ.document, '$.description') AS "description", + json_extract(td_equ.document, '$.member') AS "member", + json_extract(td_equ.document, '$.images') AS "images", + img.value AS image + FROM !table AS td_equ + LEFT JOIN json_each(td_equ.document, '$.images') img + WHERE ($$.category={$key|strval}) + ORDER BY (catname) + ; + !table=module_data_equipment + assign="lignes." + }} + {{else}} + {{/select}} + {{*:debug l=$lignes*}} + {{if $lignes}} +
+ {{$name}} +
+ {{#foreach from=$lignes}} + {{if $_key!=$wequ_key}} +
+ {{:assign var="_key" value=$wequ_key}} + {{*:debug img=$image*}} + {{if $image === null}} + {{:assign var="_image" value="equipment_no_image.png"|url_encode}} + {{:assign var="thumbnail_src" value="%s?h=%s"|args:$_image:$version_hash}} + {{:assign var="img_src" value="%s"|args:$_image}} + {{else}} + {{:assign var="_image" value=$image|url_encode}} + {{:assign var="thumbnail_src" value="/ext/m/equipment/public/image-%s/%s?250px&h=%s"|args:$_key:$_image:$version_hash}} + {{:assign var="img_src" value="/ext/m/equipment/public/image-%s/%s"|args:$wequ_key:$_image}} + {{/if}} +
+ {{$description}} +
+ {{$stock}} +
+
    + {{*#load module="equipment" type="movement" direction="input" limit=1 where="$$.equipment = :key" :key=$_key order="$$.date"}} +
  • entré en stock le {{$date|relative_date}}
  • + {{/load*}} +
  • entré en stock le {{$mvtdate|relative_date}}
  • +
  • numéro unique : {{$wequ_id}}
  • +
  • {{:link href="equipment.html?key=%s&fonc=voir"|args:$_key label=$name}}
  • +
  • Qt Disponible : {{$stock}}
  • +
  • Qt Sorti : {{$out}}
  • + {{:assign var="_state" from="states.%d"|args:$state}} +
  • État : {{$_state}}
  • +
  • {{$description|truncate:80:"(...)":false}}
  • +
+ {{* Reservation si stock dispo *}} + {{:assign _dispo="%d-%d"|math:$stock:$out}} + {{if $_dispo >= 1}} + {{:linkbutton class="main" label="Réserver" href="equipment.html?key=%s&fonc=resa"|args:$_key shape="plus"}} + {{else}} + {{:linkbutton class="main" label="Contacter nous!" href="contact.html?key=%s&fonc=resa"|args:$_key shape="plus"}} + {{/if}} +
+
+ {{/if}} + {{/foreach}} +
+ + {{/if}} +{{/load}} + + \ No newline at end of file diff --git a/_web_resa.html b/_web_resa.html new file mode 100644 index 0000000..04e0e68 --- /dev/null +++ b/_web_resa.html @@ -0,0 +1,118 @@ +{{* -*- brindille -*- *}} + +{{* + Réservation d'un matériel (membre et non-membre) +*}} +{{*:debug*}} +{{:assign equipment_key=$_GET.key|trim}} + +{{* Charge le matériel *}} +{{#load module="equipment" key=$_GET.key assign="equipment"}} +{{else}} + {{:error message="Pas de matériel avec la clé %s"|args:$equipment_key}} +{{/load}} + +{{if !$is_logged}} + {{* Invité Ano *}} + {{:assign _name=""}} +{{else}} + {{:assign _member_adress="%s %s %s"|args:$logged_user.adresse:$logged_user.code_postal:$logged_user.ville}} + {{:assign _disabled="readonly"}} + {{:assign _name=$logged_user._name}} + {{*:debug logged_user=$logged_user*}} + {{*$logged_user._name}}{{$logged_user._email}}{{$logged_user._number}} {{$logged_user.telephone}} + {{'05/05/2026'|relative_date:false*}} +{{/if}} + +{{* + -------------------- Enregistrer la réservation -------------------- +*}} +{{#form on="save"}} + + {{* Vérifier la date *}} + {{:assign loan_date=$_POST.loan_date|parse_date}} + {{:include file="./_resa_date_check.html" loan_date=$loan_date}} + + {{* Vérifier la date trop courte (J+12 heures) ou dans le passé *}} + {{if $loan_date|strtotime < "%d+%d"|math:$now:43200}} + {{:assign _date=$loan_date|date:'d/m/Y'}} + {{:error message="Impossible de saisir une date dans le passé (%s) ou pour le jour même !"|args:$_date}} + {{/if}} + + {{* Enregistrer la réservation *}} + {{:assign resa_key=""|uuid}} + + {{:save assign_new_id="rid" + key=$resa_key + validate_schema="./reservation.schema.json" + type="reservation" + member=$logged_user._number|intval|or:null + name=$_POST.name|trim + contact=$_POST.contact|trim + email=$_POST.email|trim + address=$_POST.address|trim|or:null + equipment=$equipment_key + date=$now|date_short|parse_date + loan_date=$_POST.loan_date|parse_date + return_date=$_POST.return_date|parse_date + amount=$_POST.amount|intval + comment=$_POST.comment|trim|or:null + secret=$_POST.secret|trim|or:null + status=$_POST.status|trim|or:null + }} + {{if !$is_logged}} + {{:redirect url="./equipment.html?ok=1&fonc=confirm_resa&rid=%s"|args:$rid}} + {{else}} + {{:redirect url="./index.html?ok=1&fonc=confirm_resa&rid=%s"|args:$rid}} + {{/if}} +{{/form}} +{{:form_errors}} + +{{* + -------------------- Préparer la saisie -------------------- +*}} + +{{* récupérer les infos de la catégorie *}} +{{:assign category_key=$equipment.category}} +{{#load module="equipment" type="category" key=$category_key assign="category"}}{{/load}} +{{*:debug equi=$category*}} + +{{* Dates déjà réservées pour ce matériel *}} +{{* Liste des réservations *}} +{{:assign today=$now|date:'Y-m-d'}} +{{:include file="_resa_load.html" st_condition_cal="$$.equipment='%s' AND $$.status IN ('en attente','acceptée') AND $$.return_date > '%s'"|args:$equipment_key:$today keep="_resa_lignes"}} + +{{* formulaire de réservation de matériel *}} +
+
+ Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}}) +
+ {{if !$is_logged}} + {{:input type="text" name="name" label="Nom & Prénom" default=$_name required=true}} + {{else}} + {{:input type="hidden" name="name" label="Nom & Prénom" default=$_name required=true}} {{$_name}} + {{/if}} + {{:input type="text" name="email" label="Courriel" default=$logged_user._email required=true}} + {{:input type="text" name="contact" label="Téléphone" default=$logged_user.telephone}} + {{:input type="textarea" cols=40 rows=2 name="address" label="Adresse" default=$_member_adress|trim}} + {{:input type="hidden" name="equipment" required=true value=$equipment_key}} + {{:input type="date" name="loan_date" size="12" label="Date souhaitée" help="Merci de vérifier les dates déjà réservées ci-dessous avant de faire votre choix :" required=true}} +
+ {{#foreach from=$_resa_lignes}} + - du {{$loan_date|date_long}} au {{$return_date|date_long}}
+ {{/foreach}} +
+ {{:input type="date" name="return_date" label="Date de retour prévue" required=true}} + {{:input type="number" name="amount" label="Quantité souhaitée" min=1 required=true default=1}} + {{:input type="textarea" cols=40 rows=2 name="comment" label="Commentaire additionnel" required=false}} + {{if !$is_logged}} + {{:input type="text" name="secret" label="Votre code secret" help="Permet de retrouver votre réservation pour l'annuler ou la modifier." required=true}} + {{/if}} + {{:input type="hidden" name="status" required=true default="en attente"}} + {{*:captcha html=true verify=true*}} +
+
+

+ {{:button type="submit" name="save" label="Étape suivante" shape="right" class="main"}} +

+
\ No newline at end of file diff --git a/_web_resadel.html b/_web_resadel.html new file mode 100644 index 0000000..94a365b --- /dev/null +++ b/_web_resadel.html @@ -0,0 +1,42 @@ +{{* -*- brindille -*- *}} +{{* + Ce code permet de supprimer une réservation dans la table module_data_web depuis l'interface Web en étant logué comme admin + fonc = resadel + id = id de la réservation dans la table (confirmation demandée) + key = key de la réservation dans la table (pas de confirmation et retour à la réservation du module equipment) + TODO : liste des réservations avec possibilité de cliquer sur l'id directement +*}} +{{#restrict block=true section="accounting" level="admin"}}{{/restrict}} + +{{if $_GET.id}} + {{#load id=$_GET.id assign="resa"}} + {{else}} + {{*:error message="Reservation introuvable"*}} + {{/load}} + + {{#form on="delete"}} + {{if !$_POST.confirm_delete}} + {{:error message="Merci de cocher la case"}} + {{/if}} + {{:delete id=$resa.id type="reservation"}} + {{:redirect parent="equipment.html?fonc=resadel"}} + {{/form}} + {{:form_errors}} + + {{:delete_form + legend="Suppression de réservation" + warning="Supprimer la réservation n°%d ?"|args:$resa.id + info="La réservation lié sera également supprimée" + alert="La réservation sera définitivement perdue !" + confirm="Cocher cette case pour confirmer la suppression de la réservation" + }} +{{elseif $_GET.key}} + {{:delete key=$_GET.key type="reservation"}} + {{:redirect reload="resa_details.html?key=%s"|args:$_GET.key}} +{{else}} + {{#load type="reservation" assign="reservations"}} + {{:linkbutton href="equipment.html?fonc=resadel&id=%d"|args:$reservations.id label="Supprime %d"|args:$reservations.id shape="minus"}}  + {{else}} + {{:error message="Pas de réservations trouvées"}} + {{/load}} +{{/if}} \ No newline at end of file diff --git a/_web_saved_resa.html b/_web_saved_resa.html new file mode 100644 index 0000000..e5f2182 --- /dev/null +++ b/_web_saved_resa.html @@ -0,0 +1,239 @@ +{{* -*- brindille -*- *}} +{{:http type="application/pdf" download="convention_%s_%d.pdf"|args:$now:$_GET.rid}} +{{if !$is_logged}} + {{* Invité Ano *}} + {{:assign _module="web"}} +{{else}} + {{:assign _module="equipment"}} +{{/if}} +{{:assign reservation_id=$_GET.rid|trim}} +{{* récupérer les infos de la réservation *}} +{{#load module="%s"|args:$_module id=$reservation_id assign="resa"}} +{{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$reservation_id}} +{{/load}} +{{*:debug rsa=$resa*}} +{{* récupérer les infos du matériel associé *}} +{{#load module="equipment" key=$resa.equipment assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$resa.equipment}} +{{/load}} +{{* récupérer les infos de la catégorie associée *}} +{{#load module="equipment" key=$equipment.category assign="category"}}{{/load}} +{{*:debug rsa=$equipment*}} +{{#module name="equipment"}} + {{*Sa configuration est : {{:debug config=$config}}*}} + {{:assign var="states" value=$config.states|explode:","}} + {{:assign var="_equip_config_state" from="states.%d"|args:$equipment.state}} + {{* Récupère le membre si présent *}} + {{if $config.member >= 1}} + {{#users id=$config.member}} + {{:assign var="_rep_name" value=$_name}} + {{/users}} + {{/if}} +{{else}} + Le module Équipement est désactivé. +{{/module}} + + +{{* + Réservation d'un matériel - Convention (membre et non-membre) +*}} + + + + +{{* Convention *}} +
+ Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}}) +

Convention de prêt de matériel

+

Entre les soussignés :

+

Nom de l’association : {{$config.org_name}}

+

Adresse du siège : {{$config.org_full_address}}

+

Représentée par : {{$_rep_name}}

+

Fonction : Membre du conseil collégial

+

Ci-après dénommée « l’Association ».

+ +

Emprunteur

+

Nom : {{$resa.name}}

+

Adresse : {{$resa.address}}

+

Contact(Tel/email) : {{$resa.contact}}/{{$resa.email}}

+

N° d’adhérent : {{$resa.member}}

+

Ci-après dénommé « l’Emprunteur ».

+ +

Il a été convenu ce qui suit :

+ +

Article 1 — Objet de la convention

+

L’Association met à disposition de l’Emprunteur, à titre gratuit, le matériel suivant :

+

Désignation : {{$equipment.name}}

+

Description :

{{$equipment.description}}
+

Numéro de série : {{$equipment.serialno}}

+

État du matériel au moment du prêt : {{$_equip_config_state}}

+

Accessoires fournis :

+
+ +

Article 2 — Durée du prêt

+

Le présent prêt est consenti :

+

À compter du : {{$resa.loan_date|date_short}}

+

Jusqu’au : {{$resa.return_date|date_short}}

+

+ Le matériel devra être restitué au plus tard à cette date, sauf accord préalable de l’Association. +

+ +

Article 3 — Conditions d’utilisation

+

+ L’emprunteur s’engage à :
+

+

+ +

Article 4 — Assurance responsabilité civile

+

+ L’emprunteur certifie être couvert par une assurance responsabilité civile en cours de validité couvrant les dommages pouvant être causés aux tiers ainsi que, le cas échéant, les dommages liés à l’utilisation du matériel prêté.
+ Une attestation d’assurance pourra être demandée par le prêteur avant la remise du matériel.
+ À défaut d’assurance valide, le prêteur pourra refuser la mise à disposition du matériel. +

+ +

Article 5 — Responsabilité

+

L’emprunteur est responsable du matériel pendant toute la durée du prêt.
+ En cas de détérioration, perte ou vol, l’emprunteur s’engage à :
+

+

+ +

Article 6 — Restitution

+

+ La restitution du matériel aura lieu : +

Lieu : ?????

+

Date : {{$resa.return_date|date_short}}

+ Un état du matériel pourra être réalisé contradictoirement lors du retour. +

+ + {{* TODO : gratuit (membres) ou payant ? *}} + {{#foreach from=$equipment.fields key="key"}} + {{if $label >= "Tarif par jour"}} + {{:assign var="prix" value=$value}} + {{/if}} + {{/foreach}} + {{if $prix >= 1}} +

Article 7 — Tarif

+

L'emprunteur s'engage a régler à l'association le tarif journalier de {{$prix}}€.

+ {{else}} +

Article 7 — Gratuité

+

Le présent prêt est consenti à titre gratuit et sans contrepartie financière.

+ {{/if}} + +

Article 8 — Litiges

+

+ Les parties s’efforceront de régler à l’amiable tout différend relatif à l’exécution de la présente convention.
+ À défaut d’accord amiable, le litige relèvera des juridictions compétentes. +

+

Signatures

+

Fait à : L'île d'Arz

+

Le : {{$resa.date|date_long}}

+ +
+
+

Pour l’Association

+

Nom : {{$_rep_name}}

+

Fonction : Membre du conseil collégial

+

Signature

+
{{$_rep_name}} + {{*:input class="signature" type="text" name="assosigned" required=true default=$_rep_name readonly=true*}} + {{*:captcha html=true verify=true*}} +
+
+
+

L’Emprunteur

+

Signature

+
{{$resa.name}} + {{*:input class="signature" type="text" name="signed" required=true help="Tapez votre nom pour signer le document"*}} + {{*:captcha html=true verify=true*}} +
+
+
+
\ No newline at end of file diff --git a/_web_view.html b/_web_view.html new file mode 100644 index 0000000..8b5ac36 --- /dev/null +++ b/_web_view.html @@ -0,0 +1,163 @@ +{{* -*- brindille -*- *}} +{{* + Paramètres : + - key : clé du matériel à visionner + - prop : =1 si matériel propriété de l'association, 0 sinon +*}} +{{:assign equipment_key=$_GET.key|trim}} +{{#load module="equipment" key=$_GET.key assign="equipment"}} +{{else}} + {{:error message="Pas de matériel avec la clé %s"|args:$equipment_key}} +{{/load}} +{{:assign default_category=$equipment.category}} + +{{* lister les catégories disponibles +{{#load module="equipment" type="category" assign="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$category.key value=$category.name}} +{{/load}} +*}} +{{* Récupère la catégorie *}} +{{#load module="equipment" type="category" key="%s"|args:$equipment.category }} + {{:assign var="cat_name" value=$name}} +{{/load}} + +{{* Récupère l'état *}} +{{#module name="equipment"}} + {{:assign var="_states" value=$config.states|explode:","}} + {{:assign var="_state" from="_states.%d"|args:$equipment.state}} +{{/module}} + +{{* Quantités stock ou temp *}} +{{if $equipment.stock >= 1}} + {{:assign _amount=$equipment.stock|intval}} + {{:assign _operation="définitif"}} +{{elseif $equipment.notowned >= 1}} + {{:assign _amount=$equipment.notowned|intval}} + {{:assign _operation="temporaire"}} +{{/if}} + +{{* Champs personnalisés *}} +{{#module name="equipment"}} + {{*:debug conf=$config.fields*}} + {{:assign var="_html" value=""}} + {{#foreach from=$config.fields key="i" item="field"}} + {{if $field.assignedto == 'M' && $field.published == true}} + {{*:debug types=$equipment.fields*}} + {{:assign var="champ" from="equipment.fields.%d"|args:$i}} + {{*:debug i=$i label=$champ.label valeur=$champ.value*}} + {{if $field.type == 'checkbox'}} + {{:assign retval="Oui"}} + {{else}} + {{:assign var="retval" value=""}} + {{if $champ.value !== null}} + {{:assign var="retval" value=$champ.value}} + {{/if}} + {{*:debug i=$i val=$retval*}} + {{/if}} + {{if $field.type == 'monetary'}} + {{*:input name="fields[%s]"|args:$i label=$field.label type="number" help=$field.help required=$field.required default=$retval value=$retval min="0" step="any"*}} + {{:assign var="_html" value="%s
%s
%s €
"|args:$_html:$field.label:$retval}} + {{else}} + {{*:input name="fields[%s]"|args:$i label=$field.label type=$field.type help=$field.help required=$field.required default=$retval value=$retval*}} + {{:assign var="_html" value="%s
%s
%s
"|args:$_html:$field.label:$retval}} + {{/if}} + {{/if}} + {{/foreach}} +{{/module}} + +
+ Voir un matériel +
+
Catégorie
{{$cat_name}}
+
Désignation
{{$equipment.name}}
+
Description
{{$equipment.description}}
+
Statut
{{$equipment.status}}
+
Quantité ({{$_operation}})
{{$_amount}}
+
État
{{$_state}}
+
N° de série
{{$equipment.serialno}}
+ {{$_html|raw}} +
+
+{{* View and Add Public files *}} +
+ Images associées + {{*:debug equi=$equipment.images*}} + {{*#foreach from=$equipment.images key="key" item="value"}} + {{:assign var="_value" value=$value|url_encode}} + {{:assign var="thumbnail_src" value="/ext/m/equipment/public/image-%s/%s.150px.webp?h=%s"|args:$equipment_key:$_value:$version_hash}} + {{:assign var="img_src" value="/ext/m/equipment/public/image-%s/%s"|args:$equipment_key:$value}} + {{$value}} + {{/foreach*}} + {{#sql select="path AS img_path, name as img_name, mime as img_mime" tables="files" where="parent = :parent AND image = :image" :parent="ext/m/equipment/public/image-%s"|args:$equipment_key :image=1}} + {{:assign var="thumbnail_src" value="%s.150px.webp?h=%s"|args:$img_path:$version_hash}} + {{:assign var="img_src" value="%s"|args:$img_path}} + {{$img_name}} + {{/sql}} +
+ +{{* Charge les réservations EQUIPEMENT en cours, en attente et acceptées dans le calendrier *}} +{{:include file="_resa_load.html" st_condition_cal="$$.equipment='%s' AND $$.status IN ('en attente','acceptée', 'en cours')"|args:$equipment_key keep="_resa_lignes"}} + +{{*:debug equi=$_events_light*}} +
+ Calendrier des réservations +
+
+ {{#foreach from=$_resa_lignes}} + {{:assign var="_events" value="%s{title: 'Réservation', start: '%s', end: '%s'},"|args:$_events:$loan_date:$return_date}} +

Réservation du {{$loan_date|date_short}} au {{$return_date|date_short}}

+ {{/foreach}} +
+
+

+ {{if $is_admin}} + {{:linkbutton class="main" label="Retour" href="equipment_history.html" shape="list-ul"}} + {{elseif $is_logged}} + {{:linkbutton class="main" label="Retour" href="index.html" shape="list-ul"}} + {{if $_operation=="définitif"}} + {{:linkbutton class="main" label="Réserver" href="/m/equipment/index.html?key=%s&fonc=resa"|args:$equipment_key shape="export"}} + {{else}} + {{:linkbutton class="main" label="Contacter nous!" href="/contact.html?key=%s&fonc=resa"|args:$equipment_key shape="mail" target="_dialog"}} + {{/if}} + {{else}} + {{:linkbutton class="main" label="Retour" href="equipment.html" shape="list-ul"}} + {{if $_operation=="définitif"}} + {{:linkbutton class="main" label="Réserver" href="equipment.html?key=%s&fonc=resa"|args:$equipment_key shape="export"}} + {{else}} + {{:linkbutton class="main" label="Contacter nous!" href="contact.html?key=%s&fonc=resa"|args:$equipment_key shape="mail"}} + {{/if}} + {{/if}} +

+ \ No newline at end of file diff --git a/archives.html b/archives.html new file mode 100644 index 0000000..5d9369a --- /dev/null +++ b/archives.html @@ -0,0 +1,85 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{:admin_header title="Matériels archivés" current="module_%s"|args:$module.name}} +{{:include file="_nav.html" current="archives"}} + +{{if $_GET.ok}} +

Matériel remis en service

+{{/if}} + +{{* filtrer selon la catégorie *}} +{{if $_GET.cat_key == null}} + {{:assign selected_category=$module.config.archive_cat_key}} +{{elseif $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{:save key="config" archive_cat_key=null}} +{{else}} + {{:assign selected_category=$_GET.cat_key}} + {{:save key="config" archive_cat_key=$selected_category}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category == null}} + {{:assign cat_condition="1"}} +{{else}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="$$.category == %s"|args:$cat_key}} +{{/if}} + +{{* Sélecteur catégories *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?cat_key=-1"}} +{{#load type="category" order="$$.name"}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?cat_key=%s"|args:$key + }} +{{/load}} + +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +
+

Matériels qui ne sont plus dans l'association

+
+ +{{* Liste des matériels archivés *}} +{{#list + select=" + $$.name AS 'Matériel' ; + (SELECT $$.name + FROM @TABLE as cat + WHERE cat.key = @TABLE.$$.category) AS 'Catégorie' + " + type="equipment" + where="$$.status='archived' AND %s"|args:$cat_condition + order=1 +}} + + + {{:link href="equipment_history.html?key=%s&prop=1¤t=archives"|args:$key label=$name}} + {{$col2}} + + {{:linkbutton + label="Mouvements" + href="equipment_history.html?key=%s&prop=1¤t=archives"|args:$key + shape="table"}} + {{:linkbutton + label="Modifier" + href="unarchive_equipment.html?key=%s"|args:$key + shape="edit" + target="_dialog"}} + + +{{else}} +

Aucun matériel.

+{{/list}} diff --git a/categories/add_category.html b/categories/add_category.html new file mode 100644 index 0000000..7ad546d --- /dev/null +++ b/categories/add_category.html @@ -0,0 +1,45 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + + {{* Vérifier s'il existe déjà une catégorie avec le même nom *}} + {{#load type="category" where="$$.name = :name COLLATE U_NOCASE" :name=$_POST.name|trim limit=1}} + {{:error message="Impossible d'ajouter la catégorie « %s » car elle existe déjà !"|args:$name|trim}} + {{/load}} + + {{:assign key=""|uuid}} + {{:assign cat_name=$_POST.name|trim}} + {{:save + key=$key + validate_schema="./category.schema.json" + type="category" + name=$cat_name + }} + {{:redirect force="./index.html?ok=1&msg=ajout"}} +{{/form}} + +{{:admin_header title="Gestion des matériels" current="module_%s"|args:$module.name}} +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="config" subcurrent="categories"}} +{{/if}} + +{{:form_errors}} + +{{* formulaire d'ajout de catégorie *}} +
+
+ Ajouter une catégorie +
+ {{:input type="text" name="name" label="Nom" autofocus=true required=true maxlength="100"}} +
+

+ {{:button type="submit" name="save" label="Ajouter" shape="right" class="main"}} +

+
+
+ +{{:admin_footer}} diff --git a/categories/category.schema.json b/categories/category.schema.json new file mode 100644 index 0000000..aa22047 --- /dev/null +++ b/categories/category.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["category"] + }, + "name": { + "type": "string" + } + }, + "required": ["type", "name"] +} diff --git a/categories/delete_category.html b/categories/delete_category.html new file mode 100644 index 0000000..21b7031 --- /dev/null +++ b/categories/delete_category.html @@ -0,0 +1,28 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{#load key=$_GET.key assign="category"}} +{{else}} + {{:error message="Catégorie introuvable"}} +{{/load}} + +{{#form on="delete"}} + {{* Vérifier s'il reste des matériels dans cette catégorie *}} + {{#load type="equipment" category=$_GET.key limit="1"}} + {{:redirect force="./index.html?err=1&msg=suppression"}} + {{else}} + {{* supprimer la catégorie sélectionnée*}} + {{:delete where="key = :key" :key=$category.key}} + {{:redirect force="./index.html?ok=1&msg=suppression"|args:$msg}} + {{/load}} +{{/form}} + +{{:admin_header title="Supprimer une catégorie" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{:delete_form + legend="Supprimer une catégorie" + warning="Supprimer la catégorie « %s » ?"|args:$category.name + info="La suppression n'est possible que si la catégorie ne possède plus de matériel" +}} diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 0000000..4396730 --- /dev/null +++ b/categories/index.html @@ -0,0 +1,50 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{:admin_header title="Configuration" current="module_%s"|args:$module.name}} + +{{* barre de navigation *}} +{{:include file="../_nav.html" current="config" subcurrent="categories"}} + +{{if $_GET.ok}} + {{if $_GET.msg == "modification"}} +

Modification enregistrée

+ {{elseif $_GET.msg == "suppression"}} +

Catégorie supprimée

+ {{elseif $_GET.msg == "ajout"}} +

Catégorie ajoutée

+ {{/if}} +{{elseif $_GET.err}} + {{if $_GET.msg == "suppression"}} +

+ Cette catégorie ne peut être supprimée car elle contient encore des matériels +

+ {{/if}} +{{/if}} + +{{* afficher les catégories déjà enregistrées *}} +
+ {{#list select="$$.name AS 'Catégorie'" order="1" where="$$.type = 'category'"}} + {{:assign category_key=$key}} + {{* voir s'il y a des matériels dans cette catégorie *}} + {{:assign materiel_present=true}} + {{#load type="equipment" where="$$.category = :category_key" :category_key=$category_key limit=1}} + {{else}} + {{:assign materiel_present=false}} + {{/load}} + + {{$name}} + + {{if ! $materiel_present}} + {{:linkbutton label="Supprimer" href="delete_category.html?key=%s"|args:$key shape="delete" target="_dialog"}} + {{/if}} + {{:linkbutton label="Modifier" href="modify_category.html?key=%s"|args:$key shape="edit" target="_dialog"}} + + + {{else}} +

Il n'y a aucune catégorie : vous devez en ajouter.

+ {{/list}} +
+ +{{:admin_footer}} diff --git a/categories/modify_category.html b/categories/modify_category.html new file mode 100644 index 0000000..796dcc6 --- /dev/null +++ b/categories/modify_category.html @@ -0,0 +1,40 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{#load key=$_GET.key assign="category"}} +{{else}} + {{:error message="Catégorie introuvable"}} +{{/load}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + {{* Vérifier s'il existe déjà une catégorie avec le même nom *}} + {{#load type="category" where="$$.name = :name COLLATE U_NOCASE" :name=$_POST.name|trim limit=1}} + {{:error message="Modification impossible car ce nom de catégorie (« %s ») existe déjà !"|args:$name|trim}} + {{/load}} + + {{:save + key=$category.key + validate_schema="./category.schema.json" + type="category" + name=$_POST.name|trim + }} + {{:redirect force="./index.html?ok=1&msg=modification"}} +{{/form}} + +{{:admin_header title="Modifier une catégorie" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* formulaire de modification de catégorie *}} +
+
+ Modifier la catégorie « {{$category.name}} » +
+ {{:input type="text" name="name" label="Nom" default=$category.name required=true maxlength="100"}} +
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+
diff --git a/config.html b/config.html new file mode 100644 index 0000000..0f027a4 --- /dev/null +++ b/config.html @@ -0,0 +1,69 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{:admin_header title="Configuration" current="module_%s"|args:$module.name}} + +{{* barre de navigation *}} +{{:include file="_nav.html" current="config" subcurrent="typesES"}} + +{{if $_GET.ok}} +

Configuration enregistrée.

+{{/if}} + +{{* lecture config *}} +{{:include file="./_get_config.html" keep="config_defaut, config, directions"}} + +{{* interdire la modification et la suppression des types de mouvement prédéfinis *}} +{{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config_defaut.%ss"|args:$direction}} + {{#foreach from=$nature item="elem"}} + {{:assign var="default_keys." value=$key}} + {{/foreach}} +{{/foreach}} + +{{#foreach from=$directions key="direction" item="item"}} + + {{* types de mouvements qui ne peuvent être supprimés *}} + {{#load type="movement" where="$$.direction=:direction" :direction=$direction group="$$.operation"}} + {{:assign var="locked." value=$operation}} + {{/load}} + +

{{$item|ucfirst}}s

+ + + + + + + + + + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key=key}} + {{:assign sortie_temp=false}} + {{if $direction == 'output'}} + {{:assign var="type" from="nature.%s.type"|args:$key}} + {{if $type == 'temporaire'}} + {{:assign sortie_temp=true}} + {{/if}} + {{/if}} + + + + + + {{/foreach}} + +
LibelléType
{{$label}}{{$type}} + {{if ! $default_keys|has:$key && ! $locked|has:$key}} + {{:linkbutton label="Supprimer" shape="delete" href="config/delete_movement_type.html?dir=%s&op_key=%s"|args:$direction:$key target="_dialog"}} + {{/if}} + {{if ! $default_keys|has:$key || $sortie_temp}} + {{:linkbutton label="Modifier" shape="edit" href="config/modify_movement_type.html?dir=%s&op_key=%s"|args:$direction:$key target="_dialog"}} + {{/if}} +
+ +{{/foreach}} + +{{:admin_footer}} diff --git a/config.schema.json b/config.schema.json new file mode 100644 index 0000000..1f9213c --- /dev/null +++ b/config.schema.json @@ -0,0 +1,49 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "input_nature": { + "description": "Nature des entrées", + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "key" : { + "type" : "string" + }, + "label" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : ["définitif", "temporaire", "retour"] + } + } + } + }, + "output_nature": { + "description": "Nature des sorties", + "type": ["array", "null"], + "items": { + "type": "object", + "properties": { + "key" : { + "type" : "string" + }, + "label" : { + "type" : "string" + }, + "type" : { + "type" : "string", + "enum" : ["définitif", "temporaire", "retour"] + }, + "fee" : { + "description" : "tarif sortie temporaire", + "type" : ["string", "null"], + "enum" : ["gratuit", "payant"] + } + } + } + } + } +} diff --git a/config/add_movement_type.html b/config/add_movement_type.html new file mode 100644 index 0000000..2ade04c --- /dev/null +++ b/config/add_movement_type.html @@ -0,0 +1,183 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres : + - dir : input ou output +*}} + +{{* Traiter l'envoi du formulaire *}} + +{{* lecture config *}} +{{:include file="../_get_config.html" keep="config, directions, config_defaut"}} + +{{if ! $directions|has_key:$_GET.dir}} + {{:error message="Direction « %s » inconnue !"|args:$_GET.dir}} +{{/if}} + +{{#form on="save"}} + {{if $_POST.output_fields.type == "temporaire"}} + {{* vérifier si le tarif a été choisi *}} + {{if $_POST.tarif == null}} + {{:error message="Vous n'avez pas choisi le tarif"}} + {{/if}} + {{/if}} + + {{* vérifier s'il existe un libellé de même nom dans la même direction *}} + {{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key="key" item="elem"}} + {{:assign var="fields" from="_POST.%s_fields"|args:$_GET.dir}} + {{if $_GET.dir == $direction && $fields.label|trim|tolower == $elem.label|trim|tolower}} + {{:error message="Le libellé « %s » est déjà présent"|args:$fields.label}} + {{/if}} + {{:assign var="%s_nature"|args:$direction value=$elem}} + {{:assign var="%s_nature.key"|args:$direction value=$key}} + {{:assign var="%s_natures."|args:$direction from="%s_nature"|args:$direction}} + {{/foreach}} + + {{* ajouter le nouveau type de mouvement *}} + {{if $_GET.dir == $direction}} + {{:assign var="newlabel" from="_POST.%s_fields.label"|args:$direction}} + {{:assign newlabel=$newlabel|trim}} + {{:assign var="%s_nature.key"|args:$direction value=""|uuid}} + {{:assign var="%s_nature.label"|args:$direction value=$newlabel}} + {{:assign var="%s_nature.type"|args:$direction from="_POST.%s_fields.type"|args:$direction}} + {{if $_POST.output_fields != null}} + {{if $_POST.output_fields.type == "temporaire"}} + {{:assign var="output_nature.fee" value=$_POST.tarif}} + {{else}} + {{:assign var="output_nature.fee" value=null}} + {{/if}} + {{/if}} + {{:assign var="%s_natures."|args:$direction from="%s_nature"|args:$direction}} + {{/if}} + {{/foreach}} + + {{:save + key="config" + validate_schema="../config.schema.json" + input_nature=$input_natures + output_nature=$output_natures + }} + {{:redirect to="./config.html?ok=1"}} +{{/form}} + +{{:admin_header title="Gestion des matériels" current="module_%s"|args:$module.name}} +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="config" subcurrent="typesES"}} +{{/if}} + +{{:form_errors}} + +{{if $_GET.dir == 'input'}} + {{* types d'entrées *}} + {{#foreach from=$config_defaut.inputs}} + {{:assign var='input_types.%s'|args:$type value=$type}} + {{/foreach}} +
+
+ Type d'entrée +
+ + {{:input type="select" + label="Type d'entrée" + name="input_fields[type]" + options=$input_types + default=$type + required=true + default_empty="— Choisir un type —"}} + + + {{:input + type="text" + label="Libellé de l'entrée" + name="input_fields[label]" + required=true}} + +
+
+

Signification du type d'entrée

+
    +
  • définitif : l'asso devient propriétaire du matériel (ex : achat, don)
  • +
  • temporaire : l'asso ne devient pas propriétaire du matériel (ex : location, emprunt)
  • +
  • retour : matériel qui revient après une sortie temporaire (ex : retour de location ou de prêt)
  • +
+
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{else}} + {{* types de sorties *}} + {{#foreach from=$config_defaut.outputs}} + {{:assign var='output_types.%s'|args:$type value=$type}} + {{/foreach}} + +
+
+ Type de sortie +
+ {{:input type="select" + label="Type de sortie" + name="output_fields[type]" + options=$output_types + default=$type + required=true + default_empty="— Choisir un type —"}} + {{:input + type="text" + label="Libellé de la sortie" + name="output_fields[label]" + required=true}} +
+ {{:input type="radio-btn" name="tarif" value="gratuit" label="Gratuit" required=true prefix_title="Tarification"}} + {{:input type="radio-btn" name="tarif" value="payant" label="Payant" required=true}} +
+
+
+

Signification du type de sortie

+
    +
  • définitif : le matériel n'appartient plus à l'asso (ex : vente, casse, perte, vol, ...)
  • +
  • temporaire : le matériel sort temporairement de l'asso qui en reste propriétaire (ex : location, prêt) ; dans ce cas, il faut indiquer si ce type de sortie est gratuit ou payant
  • +
  • retour : le matériel non propriété de l'asso est rendu à son propriétaire (ex : retour de location ou d'emprunt)
  • +
+
+
+

Tarification

+
    +
  • Une sortie temporaire gratuite sera classée dans l'onglet Prêt
  • +
  • Une sortie temporaire payante sera classée dans l'onglet Locations
  • +
+
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{/if}} + + diff --git a/config/custom_fields.html b/config/custom_fields.html new file mode 100644 index 0000000..27f3746 --- /dev/null +++ b/config/custom_fields.html @@ -0,0 +1,92 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{:assign var="types" + checkbox="Case à cocher" + date="Date" + number="Nombre" + monetary="Montant €" + text="Texte" + textarea="Texte multi-lignes" +}} + +{{#form on="save"}} + {{#foreach from=$_POST.fields|array_transpose item="field"}} + {{if !$field.label|trim || !$field.type}} + {{:continue}} + {{/if}} + {{if !$types|keys|has:$field.type}} + {{:error message="Type inconnu: %s"|args:$field.type}} + {{/if}} + {{:assign var="fields." required=$field.required|boolval published=$field.published|boolval assignedto=$field.assignedto type=$field.type name=$field.name label=$field.label help=$field.help|or:null}} + {{/foreach}} + {{:save key="config" fields=$fields|arrayval}} + {{:redirect to="?ok=1"}} +{{/form}} + +{{:admin_header title="Configuration" current="module_%s"|args:$module.name}} +{{:include file="../_nav.html" current="config" subcurrent="custom_fields"}} +{{:form_errors}} + +{{if $_GET.ok}} +

Configuration enregistrée.

+{{/if}} + + +
+
+
+

+ À utiliser optionnellement pour associer des informations supplémentaires aux matériels et/ou objets. +

+ + + + + + + + + + + + + + + {{:assign var="select" 0="Facultatif" 1="Obligatoire"}} + {{:assign var="select2" 0="Masquer" 1="Afficher"}} + {{:assign var="select3" M="Matériels" C="Catégories" E="Emplacements" T="Tous"}} + {{#foreach from=$module.config.fields item="field"}} + + + + + + + + + + + {{else}} + + + + + + + + + + + {{/foreach}} + +
Type de champNom du champLibellé du champTexte d'aide en dessous du champChamp obligatoire ?Page publiqueAssocié à
{{:input type="select" name="fields[type][]" default=$field.type options=$types}}{{:input type="text" name="fields[name][]" default=$field.name}}{{:input type="text" name="fields[label][]" default=$field.label}}{{:input type="text" name="fields[help][]" default=$field.help}}{{:input type="select" name="fields[required][]" default=$field.required options=$select required=true}}{{:input type="select" name="fields[published][]" default=$field.published options=$select2 required=true}}{{:input type="select" name="fields[assignedto][]" default=$field.assignedto options=$select3 required=true}}{{:button shape="minus" label="Enlever cette ligne" onclick="this.parentNode.parentNode.remove();"}}
{{:input type="select" name="fields[type][]" options=$types default="text"}}{{:input type="text" name="fields[name][]" default=$field.name}}{{:input type="text" name="fields[label][]" default=$field.label}}{{:input type="text" name="fields[help][]" default=$field.help}}{{:input type="select" name="fields[required][]" default=$field.required options=$select required=true}}{{:input type="select" name="fields[published][]" default=$field.published options=$select2 required=true}}{{:input type="select" name="fields[assignedto][]" default=$field.assignedto options=$select3 required=true}}{{:button shape="minus" label="Enlever ce champ" onclick="this.parentNode.parentNode.remove();"}}
+

+ {{:button shape="plus" label="Ajouter un champ" onclick="var a = $('.fields tbody')[0].lastElementChild; var b = a.cloneNode(true); b.querySelectorAll('input, select').forEach((e) => e.value = null); a.parentNode.append(b);"}} +

+
+

+ {{:button type="submit" shape="right" name="save" label="Enregistrer" class="main"}} +

+ \ No newline at end of file diff --git a/config/delete_movement_type.html b/config/delete_movement_type.html new file mode 100644 index 0000000..faed556 --- /dev/null +++ b/config/delete_movement_type.html @@ -0,0 +1,63 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres : + - dir : input ou output + - op_key : clé du type de mouvement à supprimer +*}} + + +{{* lecture config (défaut ou enregistrée) *}} +{{:include file="../_get_config.html" keep="config_defaut, config, directions"}} + +{{if ! $directions|has_key:$_GET.dir}} + {{:error message="Direction « %s » inconnue !"|args:$_GET.dir}} +{{/if}} + +{{* interdire la suppression des types de mouvement prédéfinis *}} +{{:assign var="nature" from="config_defaut.%ss"|args:$_GET.dir}} +{{#foreach from=$nature item="elem"}} + {{:assign var="default_keys." value=$key}} +{{/foreach}} +{{if $default_keys|has:$_GET.op_key}} + {{:error message="Ce type de mouvement ne peut être supprimé"}} +{{/if}} + +{{#form on="delete"}} + {{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key="key" item="elem"}} + {{if $_GET.dir == $direction && $key != $_GET.op_key || $_GET.dir != $direction}} + {{:assign var="%s_nature"|args:$direction value=$elem}} + {{:assign var="%s_nature.key"|args:$direction value=$key}} + {{:assign var="%s_natures."|args:$direction from="%s_nature"|args:$direction}} + {{/if}} + {{/foreach}} + {{/foreach}} + + {{:save + key="config" + validate_schema="../config.schema.json" + input_nature=$input_natures + output_nature=$output_natures + }} + {{:redirect to="./config.html?ok=1"}} +{{/form}} + +{{:admin_header title="Gestion des matériels" current="module_%s"|args:$module.name}} +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="config" subcurrent="typesES"}} +{{/if}} +{{:form_errors}} + +{{:assign var="mvt_label" from="config.%s_nature.%s.label"|args:$_GET.dir:$_GET.op_key}} +{{:assign var="dir_label" from="directions.%s"|args:$_GET.dir}} +{{:delete_form + legend="Supprimer cette %s ?"|args:$dir_label + warning="Supprimer « %s » ?"|args:$mvt_label +}} + +{{:admin_footer}} diff --git a/config/misc.html b/config/misc.html new file mode 100644 index 0000000..4c6099d --- /dev/null +++ b/config/misc.html @@ -0,0 +1,40 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{#form on="save"}} + {{* vérifier la validité de la durée saisie *}} + {{if $_POST.loan_duration < 0}} + {{:error message="Durée (%s) erronée ; doit être >= 0"|args:$_POST.loan_duration}} + {{/if}} + + {{:save + key="config" + loan_duration=$_POST.loan_duration + }} + +{{/form}} + +{{:admin_header title="Configuration" current="module_%s"|args:$module.name}} +{{:include file="../_nav.html" current="config" subcurrent="divers"}} +{{:form_errors}} + +{{if $_GET.ok}} +

Configuration enregistrée.

+{{/if}} + +{{* lecture config *}} +{{:include file="../_get_config.html" keep="loan_duration"}} + +
+
+ Autres paramètres +
+ {{:input type="number" name="loan_duration" label="Durée de prêt par défaut" min=0 default=$module.config.loan_duration help="Durée en nombre de jours ; mettre 0 pour supprimer la durée par défaut"}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{:admin_footer}} \ No newline at end of file diff --git a/config/modify_movement_type.html b/config/modify_movement_type.html new file mode 100644 index 0000000..b752f5d --- /dev/null +++ b/config/modify_movement_type.html @@ -0,0 +1,123 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres : + - dir : input ou output + - op_key : clé du type de mouvement dont on veut modifier le libellé ou le tarif +*}} + +{{* lecture config (défaut ou enregistrée) *}} +{{:include file="../_get_config.html" keep="config_defaut, config, directions"}} + +{{#form on="save"}} + {{if $_POST.tarif == null && $_POST.name == null}} + {{:redirect to="./config.html"}} + {{/if}} + {{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key="key" item="elem"}} + {{if $_POST.name == null}} + {{:assign label=$elem.label}} + {{else}} + {{if $_GET.dir == $direction && $key != $_GET.op_key && + $_POST.name|trim|tolower == $elem.label|trim|tolower}} + {{:error message="Le libellé « %s » est déjà présent"|args:$_POST.name}} + {{/if}} + {{if $_GET.dir == $direction && $key == $_GET.op_key}} + {{:assign label=$_POST.name|trim}} + {{else}} + {{:assign label=$elem.label}} + {{/if}} + {{/if}} + {{:assign var="%s_nature"|args:$direction value=$elem}} + {{:assign var="%s_nature.label"|args:$direction value=$label}} + {{:assign var="%s_nature.key"|args:$direction value=$key}} + {{if $_POST.tarif != null && $key == $_GET.op_key}} + {{:assign var="%s_nature.fee"|args:$direction value=$_POST.tarif}} + {{/if}} + {{:assign var="%s_natures."|args:$direction from="%s_nature"|args:$direction}} + {{/foreach}} + {{/foreach}} + + {{:save + key="config" + validate_schema="../config.schema.json" + input_nature=$input_natures + output_nature=$output_natures + }} + {{:redirect to="./config.html?ok=1"}} +{{/form}} + +{{:admin_header title="Gestion des matériels" current="module_%s"|args:$module.name}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="config" subcurrent="typesES"}} +{{/if}} +{{:form_errors}} + +{{* vérifier que $_GET.dir est bien une direction connue *}} +{{if ! $directions|has_key:$_GET.dir}} + {{:error message="Direction « %s » inconnue !"|args:$_GET.dir}} +{{/if}} + +{{* vérifier que $_GET.op_key est bien dans la liste des opérations *}} +{{:assign var="config_nature" from="config.%s_nature"|args:$_GET.dir}} +{{if ! $config_nature|keys|has:$_GET.op_key}} + {{:error message="Type de mouvement inconnu !"}} +{{/if}} + +{{* sortie temporaire ? *}} +{{:assign sortie_temp=false}} +{{if $_GET.dir == 'output'}} + {{:assign var="elem" from="config_nature.%s"|args:$_GET.op_key}} + {{if $elem.type == 'temporaire'}} + {{:assign sortie_temp=true}} + {{:assign fee=$elem.fee}} + {{/if}} +{{/if}} + +{{* mouvement prédéfini ? *}} +{{:assign var="default_nature" from="config_defaut.%ss"|args:$_GET.dir}} +{{#foreach from=$default_nature item="elem"}} + {{:assign var="default_keys." value=$key}} +{{/foreach}} + +{{:assign label_mod=true}} +{{if $default_keys|has:$_GET.op_key}} + {{:assign label_mod=false}} +{{/if}} + +{{if ! $label_mod && ! $sortie_temp}} + {{:error message="Ce type de mouvement ne peut être modifié"}} +{{/if}} + +{{:assign var="default_label" from="config.%s_nature.%s.label"|args:$_GET.dir:$_GET.op_key}} +
+
+ Paramètres +
+ {{if $label_mod}} + {{:input type="text" name="name" label="Libellé" default=$default_label required=true maxlength="100"}} + {{/if}} + {{if $sortie_temp}} +
+ {{:input type="radio-btn" name="tarif" value="gratuit" label="Gratuit" required=true default=$fee prefix_title=Tarif}} + {{:input type="radio-btn" name="tarif" value="payant" label="Payant" required=true default=$fee}} +
+ {{/if}} +
+ {{if $sortie_temp}} +
+

Tarification

+
    +
  • Une sortie temporaire gratuite sera classée dans l'onglet Prêt
  • +
  • Une sortie temporaire payante sera classée dans l'onglet Locations
  • +
+
+ {{/if}} +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+
diff --git a/config/reservations.html b/config/reservations.html new file mode 100644 index 0000000..b84390b --- /dev/null +++ b/config/reservations.html @@ -0,0 +1,96 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{#form on="save"}} + {{* vérifier la validité du champ états *}} + {{if $_POST.resaactif == true}} + {{:assign resa_active=true}} + {{else}} + {{:assign resa_active=false}} + {{/if}} + {{* vérifier la validité du champ états *}} + {{:assign var="states_table" value=$_POST.states|explode:","}} + {{if $states_table == null}} + {{:error message="Chaine de caractères erronée ; chaque état doit être séparé du suivant par une virgule!"}} + {{/if}} + {{* Enregistrer membre *}} + {{if $_POST.user|count > 1}} + {{:error message="Un membre au plus peut être associé à un équipement !"}} + {{else}} + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + {{/if}} + {{:save + key="config" + resa_active=$resa_active|boolval + states=$_POST.states|trim + member=$user.id|intval|or:null + }} +{{:redirect url="?ok=1&msg=%s"|args:"Configuration enregistrée." }} +{{/form}} + +{{#form on="import"}} + {{#load module="equipment" type="equipment" assign="eq_lignes."}}{{/load}} + {{:save from=$eq_lignes}} + {{#load module="equipment" type="category" assign="ca_lignes."}}{{/load}} + {{:save from=$ca_lignes}} + {{#load module="equipment" type="movement" assign="mo_lignes."}}{{/load}} + {{:save from=$mo_lignes}} + {{#load module="equipment" type="link" assign="li_lignes."}}{{/load}} + {{:save from=$li_lignes}} + {{#load module="equipment" type="storage" assign="st_lignes."}}{{/load}} + {{:save from=$st_lignes}} +{{:redirect url="?ok=1&msg=%s"|args:"Import effectué." }} +{{/form}} + +{{:admin_header title="Configuration" current="module_%s"|args:$module.name}} +{{:include file="../_nav.html" current="config" subcurrent="resaconfig"}} +{{:form_errors}} + + +{{if $_GET.ok}} +

{{$_GET.msg}}

+{{/if}} + +{{* Récupère le membre si présent *}} +{{if $module.config.member >= 1}} + {{#users id=$module.config.member}} + {{:assign var="user.%s"|args:$_id value=$_name}} + {{/users}} +{{/if}} + +{{* États du matériel par défaut *}} +{{if !$module.config.states}} + {{:assign _states="très mauvais, mauvais, moyen, bon, très bon, excellent, neuf"}} +{{else}} + {{:assign _states=$module.config.states}} +{{/if}} + +
+
+ Réservations +
+ {{:input type="checkbox" name="resaactif" label="Activer les réservations" help="Activer ou désactiver les réservations de matériel" checked=$module.config.resa_active value=true}} +
+
+ {{:input type="text" name="states" label="États possibles du matériel" default=$_states help="Ajouter ou supprimer des états, séparés par des virgules (à ajouter à la fin de la liste pour ne pas casser l'ordre !)"}} +
+
+ {{:input type="list" name="user" label="Représentant" target="!users/selector.php" default=$user multiple=false can_delete=true help="Représentant de l'association pour la convention de prêt/location"}} +
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+
+ Import données depuis le module Gestion de Matériel +
+ {{:button type="submit" name="import" label="Importer" shape="right" class="main"}} +
+
+
+{{*:debug mod=$module.config*}} +{{:admin_footer}} \ No newline at end of file diff --git a/default.json b/default.json new file mode 100644 index 0000000..ab06a2c --- /dev/null +++ b/default.json @@ -0,0 +1,44 @@ + +{ + "inputs": [ + { + "key": "c3a955e3-4e6e-414e-90f4-ede7ac3e9e33", + "label": "Achat", + "type": "définitif" + }, + { + "key": "9e909c25-14dc-4e02-b97e-73c34ab2ee9b", + "label" : "Location", + "type": "temporaire" + }, + { + "key": "30eb854c-f89a-4c19-85e4-baa5e34a0317", + "label" : "Retour de Location/Prêt", + "type" : "retour" + } + ], + "outputs": [ + { + "key": "f0eb189b-0b72-46c7-8b48-c23eed7e9672", + "label" : "Vente", + "type" : "définitif" + }, + { + "key" : "c9ba00d9-26ee-448b-9f02-73e479ec2980", + "label" : "Prêt", + "type" : "temporaire", + "fee" : "gratuit" + }, + { + "key" : "5c6c20bf-53e9-49dc-bcd6-e3cac23a6786", + "label" : "Location", + "type" : "temporaire", + "fee" : "payant" + }, + { + "key" : "fefefa51-1a85-46ca-ab78-b594b10390ff", + "label" : "Retour de Location/Emprunt", + "type" : "retour" + } + ] +} diff --git a/equipment.schema.json b/equipment.schema.json new file mode 100644 index 0000000..0537cb6 --- /dev/null +++ b/equipment.schema.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["equipment"] + }, + "category" : { + "description": "Clé de la catégorie", + "type": "string" + }, + "name": { + "description": "Désignation du matériel", + "type": "string" + }, + "description": { + "description": "Description du matériel", + "type": ["string", "null"] + }, + "serialno": { + "description": "Identifiant unique : numéro de série, code-barre...", + "type": ["string", "null"] + }, + "status": { + "description": "Statut du matériel", + "type": "string", + "enum": ["disponible", "archivé", "archived","available"] + }, + "state": { + "description": "État du matériel", + "type": "integer" + }, + "member": { + "description": "N° membre de la personne liée", + "type": ["integer", "null"] + }, + "stock": { + "description": "Quantité en stock", + "type" : ["integer", "null"], + "minimum": 0 + }, + "out": { + "description": "Quantité sortie", + "type" : ["integer", "null"], + "minimum": 0 + }, + "notowned": { + "description": "Quantité en stock temporaire", + "type" : ["integer", "null"], + "minimum": 0 + }, + "fields": { + "type": ["null", "array"] + }, + "images": { + "type": ["null", "array"] + } + }, + "required": ["type", "category", "name", "status", "stock", "out", "notowned"] +} \ No newline at end of file diff --git a/equipment_history.html b/equipment_history.html new file mode 100644 index 0000000..7152214 --- /dev/null +++ b/equipment_history.html @@ -0,0 +1,379 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Afficher l'historique des mouvements d'un matériel + paramètres + - key : clé du matériel + - prop : = 1 si matériel appartient à l'asso + - ok : vrai si opération terminée avec succès + - err : vrai si opération terminée en erreur (ça fait doublon avec ok, non ?) + - msg : message de retour +*}} + +{{:assign equipment_key=$_GET.key|trim}} +{{#load key=$equipment_key assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé %s"|args:$equipment_key}} +{{/load}} + +{{#load type="category" where="key = :cle" :cle=$equipment.category assign="category"}} +{{else}} + {{:error message="Le matériel %s n'appartient à aucune catégorie"|args:$equipment.name}} +{{/load}} + +{{:admin_header title="Gestion des matériels" custom_css="./style.css" current="module_%s"|args:$module.name}} + +{{* barre de navigation *}} +{{:assign current=$_GET.current|or:"inventaire"}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="./_get_config.html" keep="config"}} + +{{* filtrer selon appartenance *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.prop == null}} + {{:assign selected_prop=$user_filters.eqpmt_hist_prop}} +{{else}} + {{if $_GET.prop == -1}} + {{:assign selected_prop=null}} + {{elseif $_GET.prop == 1 || $_GET.prop == 0}} + {{:assign selected_prop=$_GET.prop}} + {{else}} + {{:assign selected_prop=$user_filters.eqpmt_hist_prop}} + {{/if}} + {{:assign var="user_filters.eqpmt_hist_prop" value=$selected_prop}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* déterminer les types de mouvements selon l'appartenance du matériel *}} +{{#foreach from=$config.input_nature key="key"}} + {{if $selected_prop == null}} + {{* les deux sortes de matériel *}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{if $type == 'temporaire'}} + {{:assign var="temp_inputs." value=$key|quote_sql}} + {{/if}} + {{elseif $selected_prop == 1}} + {{* matériel propriété de l'asso *}} + {{if $type != 'temporaire'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{/if}} + {{else}} + {{* matériel non propriété de l'asso *}} + {{if $type == 'temporaire'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{:assign var="temp_inputs." value=$key|quote_sql}} + {{/if}} + {{/if}} +{{/foreach}} + +{{#foreach from=$config.output_nature key="key"}} + {{if $selected_prop == null}} + {{* les deux sortes de matériel *}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{if $type == "temporaire"}} + {{:assign var="temp_outputs." value=$key|quote_sql}} + {{/if}} + {{elseif $selected_prop == 1}} + {{* matériel propriété de l'asso *}} + {{if $type != 'retour'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{if $type == "temporaire"}} + {{:assign var="temp_outputs." value=$key|quote_sql}} + {{/if}} + {{/if}} + {{else}} + {{* matériel non propriété de l'asso *}} + {{if $type == 'retour'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{/if}} + {{/if}} +{{/foreach}} +{{:assign key_cond=$mvt_keys|implode:","}} +{{:assign key_cond="("|cat:$key_cond|cat:")"}} + +{{if $selected_prop == null}} + {{:assign prop_condition="1"}} +{{else}} + {{:assign prop_condition="$$.operation in %s"|args:$key_cond}} +{{/if}} + +{{* calculer et mémoriser les quantités pour que le tri de la liste affiche les valeurs correctes *}} +{{:assign stock=0}} +{{:assign exterieur=0}} +{{:assign nonproprio=0}} + +{{#load type="movement" where="$$.equipment = :key" :key=$equipment_key order="$$.date"}} + {{if $direction == 'input'}} + {{:assign var="type_mvt" from="config.input_nature.%s.type"|args:$operation}} + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d+%d"|math:$stock:$amount}} + {{elseif $type_mvt == 'retour'}} + {{:assign exterieur="%d-%d"|math:$exterieur:$amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign nonproprio="%d+%d"|math:$nonproprio:$amount}} + {{/if}} + {{else}} + {{:assign var="type_mvt" from="config.output_nature.%s.type"|args:$operation}} + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d-%d"|math:$stock:$amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign exterieur="%d+%d"|math:$exterieur:$amount}} + {{elseif $type_mvt == 'retour'}} + {{:assign nonproprio="%d-%d"|math:$nonproprio:$amount}} + {{/if}} + {{/if}} + {{:assign dispo_final="%d-%d"|math:$stock:$exterieur}} + {{:assign var="quantites.%s.stock"|args:$id value=$stock}} + {{:assign var="quantites.%s.exterieur"|args:$id value=$exterieur}} + {{:assign var="quantites.%s.dispo"|args:$id value=$dispo_final}} + {{:assign var="quantites.%s.nonproprio"|args:$id value=$nonproprio}} +{{/load}} + +{{if $selected_prop == null || $selected_prop}} + {{* calculer la quantité sortie temporairement de chaque matériel *}} + {{:assign output_ops=$temp_outputs|implode:","}} + {{:assign output_ops="("|cat:$output_ops|cat:")"}} + + {{#select + mvt.key AS mvt_key, + mvt.$$.amount - IFNULL(SUM(mvt2.$$.amount), 0) AS reste + FROM !table AS mvt + LEFT JOIN !table AS link ON mvt.key = link.$$.temp_key + LEFT JOIN !table AS mvt2 ON mvt2.key = link.$$.return + WHERE + mvt.$$.operation IN !op + AND mvt.$$.equipment = :eqpmt_key + GROUP by mvt.key + ; + !table=$module.table + !op = $output_ops + :eqpmt_key = $_GET.key + }} + {{:assign var="reste.%s"|args:$mvt_key value=$reste}} + {{/select}} +{{/if}} + +{{if $selected_prop == null || ! $selected_prop}} + {{* calculer la quantité présente temporairement de chaque matériel *}} + {{:assign input_ops=$temp_inputs|implode:","}} + {{:assign input_ops="("|cat:$input_ops|cat:")"}} + + {{#select + mvt.key AS mvt_key, + mvt.$$.amount - IFNULL(SUM(mvt2.$$.amount), 0) AS present + FROM !table AS mvt + LEFT JOIN !table AS link ON mvt.key = link.$$.temp_key + LEFT JOIN !table AS mvt2 ON mvt2.key = link.$$.return + WHERE + mvt.$$.operation IN !op + AND mvt.$$.equipment = :eqpmt_key + GROUP by mvt.key + ; + !table=$module.table + !op = $input_ops + :eqpmt_key = $_GET.key + }} + {{:assign var="present.%s"|args:$mvt_key value=$present}} + {{/select}} +{{/if}} + +{{:assign + select_debut=" + ($$.date || '_' || substr('000000' || id, -6, 6)) AS 'Date'; + CASE $$.direction WHEN 'input' THEN 'Entrée' WHEN 'output' THEN 'Sortie' END AS 'Mouvement'; + $$.operation AS 'Opération'; + $$.amount AS 'Quantité';" +}} +{{:assign + select_prop="'' AS 'Stock'; + '' AS 'Sorti'; + '' AS 'Disponible';" +}} +{{:assign + select_depositaire="CASE WHEN $$.user NOT NULL + THEN (SELECT %s AS nom FROM users WHERE id = $$.user) + ELSE '' + END AS 'Dépositaire'; + "|args:$config.user_fields.name_sql +}} +{{:assign + select_non_prop="'' as 'Temporaire';" +}} +{{:assign select_final=" + CASE WHEN $$.storage NOT NULL + THEN (SELECT $$.name FROM @TABLE as storage WHERE storage.key = @TABLE.$$.storage) + ELSE '' + END AS 'Stockage'; + '' AS 'Documents'; + $$.transactions AS 'Écritures' + " +}} + +{{if $selected_prop == null}} + {{:assign select_clause=$select_debut|cat:$select_prop|cat:$select_non_prop|cat:$select_depositaire|cat:$select_final}} +{{elseif $selected_prop}} + {{:assign select_clause=$select_debut|cat:$select_prop|cat:$select_depositaire|cat:$select_final}} +{{else}} + {{:assign select_clause=$select_debut|cat:$select_non_prop|cat:$select_final}} +{{/if}} + +{{:assign var="prop_options." value="" label="Tous les matériels" href="?key=%s&prop=-1"|args:$_GET.key}} +{{:assign var="prop_options." value="1" label="Matériels propriété de l'association" href="?key=%s&prop=1"|args:$_GET.key}} +{{:assign var="prop_options." value="0" label="Matériels NON propriété de l'association" href="?key=%s&prop=0"|args:$_GET.key}} + +{{if $dispo_final > 0 && $selected_prop == null || $selected_prop}} + {{:assign sortie="sortie"}} +{{/if}} +{{:include file="./_nav.html" current=$current subcurrent="mouvements" eqpmt=$equipment.name category=$category.name sortie=$sortie key=$_GET.key}} + +{{if $_GET.ok}} + {{if $_GET.msg == "modification"}} +

Modification enregistrée

+ {{elseif $_GET.msg == "copie"}} +

Mouvement copié

+ {{elseif $_GET.msg == "retour"}} +

Retour enregistré

+ {{elseif $_GET.msg == "suppression"}} +

Mouvement supprimé

+ {{else}} +

Mouvement enregistré

+ {{/if}} +{{elseif $_GET.err}} + {{if $_GET.msg == "suppression"}} +

Ce mouvement ne peut être supprimé

+ {{/if}} +{{/if}} + +
+ Filtrer par appartenance + {{:dropdown + title="Filtrer par appartenance" + options=$prop_options + value="%s"|args:$selected_prop + }} +
+ +{{* lister les mouvements du matériel passé en paramètre *}} +{{#list + type="movement" + select="%s"|args:$select_clause + where="%s"|args:$prop_condition + equipment=$equipment_key + order=1 + desc=true +}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$direction:$operation}} + {{:assign var="op_label" from="config.%s_nature.%s.label"|args:$direction:$operation}} + + {{:assign var="stock" from="quantites.%s.stock"|args:$id}} + {{:assign var="exterieur" from="quantites.%s.exterieur"|args:$id}} + {{:assign var="dispo" from="quantites.%s.dispo"|args:$id}} + {{:assign var="tempo" from="quantites.%s.nonproprio"|args:$id}} + + {{:assign file_path="%s/%s/"|args:$module.storage_root:$key}} + {{:assign file_path=$file_path|cat:"%"}} + {{#select count(*) AS nb FROM files WHERE path LIKE :file_path ; :file_path=$file_path}} + {{:assign nb_files=$nb}} + {{/select}} + + {{if $selected_prop == null}} + {{:assign user_details=$col9}} + {{:assign storage=$col10}} + {{elseif $selected_prop}} + {{:assign user_details=$col8}} + {{:assign storage=$col9}} + {{else}} + {{:assign user_details=$col6}} + {{:assign storage=$col6}} + {{/if}} + + + {{$date|date_short}} + {{$col2}} + {{$op_label}} + {{$amount}} + {{if $selected_prop == null || $selected_prop}} + {{$stock}} + {{$exterieur}} + {{$dispo}} + {{/if}} + {{if $selected_prop == null || ! $selected_prop}} + {{$tempo}} + {{/if}} + {{if $selected_prop == null || $selected_prop}} + {{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$user_details}} + {{/if}} + {{$storage}} + {{if $nb_files > 0}}{{$nb_files}}{{/if}} + {{if $transactions|count > 0}}{{"Oui"}}{{/if}} + + {{if $current != "archives"}} + {{if $direction == "output" && $type_mvt == "retour"}} + {{:assign prop = 0}} + {{elseif $direction == "input" && $type_mvt == "temporaire"}} + {{:assign prop = 0}} + {{else}} + {{:assign prop = 1}} + {{/if}} + {{if $direction == "output" && $type_mvt == "temporaire"}} + {{:assign var="temp_ext" from="reste.%s"|args:$key}} + {{if $temp_ext != null && $temp_ext > 0}} + {{:linkbutton + label="Retour" + href="movements/output_return.html?key=%s&prop=%s"|args:$key:$prop + shape="reset" + target="_dialog"}} + {{/if}} + {{/if}} + {{if $direction == "input" && $type_mvt == "temporaire"}} + {{:assign var="temp_in" from="present.%s"|args:$key}} + {{if $temp_in != null && $temp_in > 0}} + {{:linkbutton + label="Retour" + href="movements/input_return.html?key=%s&prop=%s"|args:$key:$prop + shape="reset" + target="_dialog"}} + {{/if}} + {{/if}} + {{:linkbutton + label="Détails" + href="movements/movement_details.html?key=%s&prop=%s&from=eh"|args:$key:$prop + shape="eye" + }} + {{/if}} + + +{{else}} +

Aucun matériel.

+{{/list}} + +{{* Charge les images du matériel et insère les dans un champ images de l'équipment pour les lire depuis le site web + A DEPLACER DANS MODIFY EQUIPMENT*}} +{{:assign var="i" value="0"}} +{{#files path="public/image-%s"|args:$equipment_key recursive=true}} + {{if $image==1}} + {{:assign var="img_names.%s"|args:$i value=$name}} + {{:assign var="i" value="%s+1"|math:$i}} + {{/if}} +{{/files}} +{{*:debug img_names=$img_names*}} +{{if $img_names !== null}} + {{:save key=$equipment_key images=$img_names}} +{{/if}} +{{:admin_footer}} + + + \ No newline at end of file diff --git a/global_history.html b/global_history.html new file mode 100644 index 0000000..9518b3b --- /dev/null +++ b/global_history.html @@ -0,0 +1,193 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Afficher l'historique de tous les mouvements +*}} + +{{:admin_header title="Historique des mouvements" custom_css="./style.css" current="module_%s"|args:$module.name}} + +{{:include file="./_nav.html" current="historique"}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="./_get_config.html" keep="config"}} + +{{* filtrer selon la catégorie *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.cat_key == null}} + {{:assign selected_category=$user_filters.hist_cat_key}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} + {{:assign var="user_filters.hist_cat_key" value=$selected_category}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="(SELECT key + FROM @TABLE AS cat + WHERE cat.key = (SELECT $$.category + FROM @TABLE AS mat + WHERE mat.key = @TABLE.$$.equipment)) = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition=1}} +{{/if}} + +{{* filtrer selon appartenance *}} +{{if $_GET.prop == null}} + {{:assign selected_prop=$user_filters.hist_prop}} +{{else}} + {{if $_GET.prop == -1}} + {{:assign selected_prop=null}} + {{elseif $_GET.prop == 1 || $_GET.prop == 0}} + {{:assign selected_prop=$_GET.prop}} + {{else}} + {{:assign selected_prop=$user_filters.hist_prop}} + {{/if}} + {{:assign var="user_filters.hist_prop" value=$selected_prop}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* déterminer les types de mouvements selon l'appartenance du matériel *}} +{{#foreach from=$config.input_nature key="key"}} + {{if $selected_prop == null}} + {{* les deux sortes de matériel *}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{elseif $selected_prop == 1}} + {{* matériel propriété de l'asso *}} + {{if $type != 'temporaire'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{/if}} + {{else}} + {{* matériel non propriété de l'asso *}} + {{if $type == 'temporaire'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{/if}} + {{/if}} +{{/foreach}} + +{{#foreach from=$config.output_nature key="key"}} + {{if $selected_prop == null}} + {{* les deux sortes de matériel *}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{elseif $selected_prop == 1}} + {{* matériel propriété de l'asso *}} + {{if $type != 'retour'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{/if}} + {{else}} + {{* matériel non propriété de l'asso *}} + {{if $type == 'retour'}} + {{:assign var="mvt_keys." value=$key|quote_sql}} + {{/if}} + {{/if}} +{{/foreach}} +{{:assign key_cond=$mvt_keys|implode:","}} +{{:assign key_cond="("|cat:$key_cond|cat:")"}} + +{{if $selected_prop == null}} + {{:assign prop_condition="1"}} +{{else}} + {{:assign prop_condition="$$.operation in %s"|args:$key_cond}} +{{/if}} + +{{* sélecteurs de catégorie et d'appartenance *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?cat_key=-1"}} +{{#load type="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$key value=$name}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?cat_key=%s"|args:$key + }} +{{/load}} + +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +{{:assign var="prop_options." value="" label="Tous les matériels" href="?prop=-1"}} +{{:assign var="prop_options." value="1" label="Matériels propriété de l'association" href="?prop=1"}} +{{:assign var="prop_options." value="0" label="Matériels NON propriété de l'association" href="?prop=0"}} + +
+ Filtrer par appartenance + {{:dropdown + title="Filtrer par appartenance" + options=$prop_options + value="%s"|args:$selected_prop + }} +
+ +
+

Historique de tous les mouvements de matériel

+
+ +{{* lister les mouvements *}} +{{#list + type="movement" + select="($$.date || '_' || substr('000000' || id, -6, 6)) AS 'Date'; + CASE $$.direction WHEN 'input' THEN 'Entrée' WHEN 'output' THEN 'Sortie' END AS 'Mouvement'; + $$.operation AS 'Opération'; + (SELECT $$.name + FROM @TABLE AS mat + WHERE mat.key = @TABLE.$$.equipment) AS 'Matériel' ; + $$.amount AS 'Quantité'; + CASE WHEN $$.user NOT NULL + THEN (SELECT %s AS nom FROM users WHERE id = $$.user) + ELSE '' + END as 'Dépositaire'; + CASE WHEN $$.storage NOT NULL + THEN (SELECT $$.name FROM @TABLE as storage WHERE storage.key = @TABLE.$$.storage) + ELSE '' + END as 'Stockage'; + $$.comment AS 'Remarque' + "|args:$config.user_fields.name_sql + where="%s AND %s"|args:$cat_condition:$prop_condition + order=1 + max=50 + desc=true +}} + {{:assign var="op_label" from="config.%s_nature.%s.label"|args:$direction:$operation}} + + {{$date|date_short}} + {{$col2}} + {{$op_label}} + {{$col4}} + {{$amount}} + {{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$col6}} + {{$col7}} + {{$comment}} + + +{{else}} +

Aucun mouvement.

+{{/list}} + +{{:admin_footer}} + + + \ No newline at end of file diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..550cb3b --- /dev/null +++ b/icon.svg @@ -0,0 +1,1108 @@ + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..432d987 --- /dev/null +++ b/index.html @@ -0,0 +1,67 @@ +{{* -*- brindille -*- *}} + +{{#restrict section="accounting" level="write"}} + {{:assign is_admin=true}} +{{else}} + {{:assign is_admin=false}} +{{/restrict}} + +{{:admin_header title="Gestion des matériels" custom_css="./style.css" current="module_%s"|args:$module.name}} + +{{if ! $is_admin}} +{{* MEMBER PART *}} + {{:assign var="user.id" value=$logged_user.id}} + {{:include file="snippets/my_details.html"}} + {{* Reservations *}} + {{if $module.config.resa_active == true}} + {{if !$_GET.fonc}} + {{:include file="./_inventory.html"}} + {{elseif $_GET.fonc=="voir"}} + {{:include file="./_web_calendar.html" title=$page.title|remove_leading_number}} + {{:include file="./_web_view.html" parent=$page.path}} + {{elseif $_GET.fonc=="resa"}} + {{:include file="./_web_resa.html" parent=$page.path}} + {{elseif $_GET.fonc=="confirm_resa"}} + {{if $_GET.ok}} + {{:include file="./_web_contract.html" parent=$page.path}} + {{/if}} + {{elseif $_GET.fonc=="save_resa"}} + {{:include file="./_web_saved_resa.html" parent=$page.path}} + {{else}} + {{:include file="./_inventory.html" parent=$page.path keep="cat_key,prop"}} + {{/if}} + {{/if}} +{{else}} + {{* ADMIN PART *}} + {{#restrict block=true section="accounting" level="write"}}{{/restrict}} + + {{#load type="category" count=true limit=1 assign="result"}}{{/load}} + {{:include file="_nav.html" current="inventaire" cat="%d"|args:$result.count}} + + {{if $_GET.ok}} + {{if $_GET.msg == "ajout" }} +

Ajout effectué

+ {{elseif $_GET.msg == "modification" }} +

Modification effectuée

+ {{elseif $_GET.msg == "suppression" }} +

Suppression effectuée

+ {{elseif $_GET.msg == "supprmvtmat" }} +

Mouvement supprimé - Matériel supprimé

+ {{/if}} + {{elseif $_GET.err}} +

Modification refusée

+ {{/if}} + + {{if $result.count == 0}} +

Il n'y a aucune catégorie : vous devez en ajouter.

+ {{else}} + {{* Reservations *}} + {{if $module.config.resa_active == true}} + {{:include file="./_resa_inventory.html" keep="_GET.prop"}} + {{else}} + {{:include file="./_inventory.html"}} + {{/if}} + {{/if}} + + {{:admin_footer}} +{{/if}} \ No newline at end of file diff --git a/loan_history.html b/loan_history.html new file mode 100644 index 0000000..be4c7e0 --- /dev/null +++ b/loan_history.html @@ -0,0 +1,199 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{if $_GET.output_type == "loan"}} + {{:assign label="prêt"}} +{{elseif $_GET.output_type == "rent"}} + {{:assign label="location"}} +{{else}} + {{:error message="Cette page n'existe pas !"}} +{{/if}} + +{{:admin_header title="%ss en cours"|args:$label|ucfirst custom_css="../style.css" current="module_%s"|args:$module.name}} +{{:include file="./_nav.html" current="%s"|args:$label subcurrent="encours"}} + +{{* + vérifier l'existence de la table du module + eh oui, il se peut qu'elle ne soit pas encore créée si aucune donnée n'a été ajoutée dedans +*}} +{{#load limit="1"}} + {{:assign table_presente=true}} +{{else}} + {{:assign table_presente=false}} +{{/load}} + +{{if $table_presente}} +{{if $_GET.ok}} + {{if $_GET.msg == "modification"}} +

Modification enregistrée

+ {{elseif $_GET.msg == "copie"}} +

Mouvement copié

+ {{elseif $_GET.msg == "suppression"}} +

Mouvement supprimé

+ {{/if}} +{{elseif $_GET.err}} + {{if $_GET.msg == "suppression"}} +

Ce mouvement ne peut être supprimé

+ {{/if}} +{{/if}} + +{{* lecture config *}} +{{:include file="./_get_config.html" keep="config"}} + +{{* filtrer selon la catégorie *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.cat_key == null}} + {{:assign var="selected_category" from="user_filters.%s_hist_cat_key"|args:$_GET.output_type}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} + {{:assign var="user_filters.%s_hist_cat_key"|args:$_GET.output_type value=$selected_category}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="mat.$$.category = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition=1}} +{{/if}} + +{{#foreach from=$config.output_nature key="key"}} + {{if $type != 'temporaire'}} + {{:continue}} + {{/if}} + {{if $_GET.output_type == "loan" && $fee != 'payant'}} + {{:assign var="out_keys." value=$key|quote_sql}} + {{elseif $_GET.output_type == "rent" && $fee == 'payant'}} + {{:assign var="out_keys." value=$key|quote_sql}} + {{/if}} +{{/foreach}} +{{:assign out_keys=$out_keys|implode:","}} +{{:assign out_keys="("|cat:$out_keys|cat:")"}} + +{{* sélecteur de catégorie *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?output_type=%s&cat_key=-1"|args:$_GET.output_type}} +{{#load type="category" order="$$.name"}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?output_type=%s&cat_key=%s"|args:$_GET.output_type:$key + }} +{{/load}} + +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +{{:assign premier=true}} +{{#select + users.nom AS nom, + users.id AS user, + mvt.key AS mvt_key, + mat.$$.name AS mat_name, + mvt.$$.date AS out_date, + mvt.$$.amount AS out_amount, + mvt.$$.return_date AS return_date, + mvt.$$.amount - IFNULL(SUM(retour.$$.amount), 0) AS remain + FROM !table AS mvt + LEFT JOIN users ON mvt.$$.user = users.id + LEFT JOIN !table AS links ON mvt.key = links.$$.temp_key + LEFT JOIN !table AS retour ON retour.key = links.$$.return + INNER JOIN !table AS mat ON mat.key = mvt.$$.equipment + WHERE mvt.$$.type = 'movement' + AND mvt.$$.operation IN !op + AND !cat_condition + GROUP BY mvt.key + HAVING remain != 0 + ORDER BY out_date DESC, nom + ; + !table=$module.table + !op = $out_keys + !cat_condition=$cat_condition +}} + {{if $premier}} + + + + + + + + + + + + + + + {{:assign premier=false}} + {{/if}} + {{* Calcul du nb de jours sortis restant *}} + {{if $return_date != null}} + {{:assign ts_retour=$return_date|strtotime}} + {{:assign nb_jours="floor((%d-%d)/(60*60*24))"|math:$now:$ts_retour}} + {{/if}} + + + + + + + + + + +{{else}} +

Aucun mouvement.

+{{/select}} + +
MatérielDate prêtQuantitéMembreDate retourReste à rendreRemarque
{{$mat_name}}{{$out_date|date_short}}{{$out_amount}}{{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$nom}}{{$return_date|date_short}}{{$remain}} + {{if $return_date != null}} + {{:assign jour="jour"}} + {{if $nb_jours > 0}} + {{if $nb_jours > 1}}{{:assign jour="jours"}}{{/if}} + {{:tag color="darkred" label="Retard %s %s"|args:$nb_jours:$jour}} + {{elseif $nb_jours < 0}} + {{:assign delai="abs(%d)"|math:$nb_jours}} + {{if $nb_jours < -1}}{{:assign jour="jours"}}{{/if}} + {{"Reste %s %s"|args:$delai:$jour}} + {{else}} + {{:tag color="darkgreen" label="À rendre aujourd'hui"}} + {{/if}} + {{/if}} + + {{:linkbutton + label="Retour" + href="movements/output_return.html?key=%s&prop=1"|args:$mvt_key + shape="reset" + target="_dialog"}} + {{if $_GET.output_type == "loan"}} + {{:assign from="lh"}} + {{elseif $_GET.output_type == "rent"}} + {{:assign from="rh"}} + {{/if}} + {{:linkbutton + label="Détails" + href="movements/movement_details.html?key=%s&prop=1&from=%s"|args:$mvt_key:$from + shape="eye" + }} +
+{{else}} +

Aucun mouvement.

+{{/if}} + +{{:admin_footer}} diff --git a/loan_movements.html b/loan_movements.html new file mode 100644 index 0000000..9858aaa --- /dev/null +++ b/loan_movements.html @@ -0,0 +1,230 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Afficher l'historique des prêts ou locations +*}} + +{{if $_GET.output_type == "loan"}} + {{:assign label="prêt"}} +{{elseif $_GET.output_type == "rent"}} + {{:assign label="location"}} +{{else}} + {{:error message="Cette page n'existe pas !"}} +{{/if}} + +{{:admin_header title="Historique des %ss"|args:$label custom_css="./style.css" current="module_%s"|args:$module.name}} +{{:include file="./_nav.html" current="%s"|args:$label subcurrent="historique"}} + +{{* + vérifier l'existence de la table du module + eh oui, il se peut qu'elle ne soit pas encore créée si aucune donnée n'a été ajoutée dedans +*}} +{{#load limit="1"}} + {{:assign table_presente=true}} +{{else}} + {{:assign table_presente=false}} +{{/load}} + +{{if $table_presente}} +{{if $_GET.ok}} + {{if $_GET.msg == "modification"}} +

Modification enregistrée

+ {{elseif $_GET.msg == "copie"}} +

Mouvement copié

+ {{elseif $_GET.msg == "suppression"}} +

Mouvement supprimé

+ {{/if}} +{{elseif $_GET.err}} + {{if $_GET.msg == "suppression"}} +

Ce mouvement ne peut être supprimé

+ {{/if}} +{{/if}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="./_get_config.html" keep="config"}} + +{{* filtrer selon la catégorie *}} +{{:assign saved_filters=$module.config.filters}} +{{:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id}} + +{{if $_GET.cat_key == null}} + {{:assign var="selected_category" from="user_filters.%s_cat_key"|args:$_GET.output_type}} +{{else}} + {{if $_GET.cat_key == -1}} + {{:assign selected_category=null}} + {{else}} + {{:assign selected_category=$_GET.cat_key}} + {{/if}} + {{:assign var="user_filters.%s_cat_key"|args:$_GET.output_type value=$selected_category}} + {{:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters}} + {{:save key="config" filters=$saved_filters}} +{{/if}} + +{{* condition de filtrage *}} +{{if $selected_category != null}} + {{:assign cat_key=$selected_category|quote_sql}} + {{:assign cat_condition="category = %s"|args:$cat_key}} +{{else}} + {{:assign cat_condition=1}} +{{/if}} + +{{* déterminer les types de mouvements *}} +{{#foreach from=$config.output_nature key="key"}} + {{if $type != 'temporaire'}} + {{:continue}} + {{/if}} + {{if $_GET.output_type == "loan" && $fee != 'payant'}} + {{:assign var="out_keys." value=$key|quote_sql}} + {{elseif $_GET.output_type == "rent" && $fee == 'payant'}} + {{:assign var="out_keys." value=$key|quote_sql}} + {{/if}} +{{/foreach}} +{{:assign out_keys=$out_keys|implode:","}} +{{:assign out_keys="("|cat:$out_keys|cat:")"}} + +{{* sélecteur de catégorie *}} +{{:assign var="cat_options." value="" label="Toutes les catégories" href="?output_type=%s&cat_key=-1"|args:$_GET.output_type}} +{{#load type="category" order="$$.name"}} + {{:assign + var="cat_options." + value=$key + label=$name + href="?output_type=%s&cat_key=%s"|args:$_GET.output_type:$key + }} +{{/load}} + +
+ Filtrer par catégorie + {{:dropdown + title="Filtrer par catégorie" + options=$cat_options + value="%s"|args:$selected_category + }} +
+ +{{* lister les mouvements *}} +{{:assign premier=true}} +{{#select * FROM + (WITH + sorties AS + (SELECT + mvt.id, + mvt.key, + mvt.$$.date AS date, + mvt.$$.direction AS direction, + mvt.$$.operation AS operation, + mat.$$.name AS materiel, + mat.$$.category AS category, + mvt.$$.amount AS amount, + users.id AS user_id, + users.nom AS user, + storage.$$.name AS stockage, + mvt.$$.transactions AS transactions, + mvt.$$.comment AS comment, + mvt.$$.return_date AS return_date + FROM !table AS mvt + INNER JOIN !table AS mat ON mat.key = mvt.$$.equipment + LEFT JOIN users ON users.id = mvt.$$.user + LEFT JOIN !table AS storage ON storage.key = mvt.$$.storage + WHERE mvt.$$.type = 'movement' + AND mvt.$$.operation IN !op + AND !cat_condition + ), + entrees AS + (SELECT + mvt.id, + mvt.key, + mvt.$$.date AS date, + mvt.$$.direction AS direction, + mvt.$$.operation AS operation, + mat.$$.name AS materiel, + mat.$$.category AS category, + mvt.$$.amount AS amount, + users.id AS user_id, + users.nom AS user, + storage.$$.name AS stockage, + mvt.$$.transactions AS transactions, + mvt.$$.comment AS comment, + mvt.$$.return_date AS return_date + FROM !table AS mvt + INNER JOIN !table AS mat ON mat.key = mvt.$$.equipment + LEFT JOIN users ON users.id = mvt.$$.user + LEFT JOIN !table AS storage ON storage.key = mvt.$$.storage + INNER JOIN ( + SELECT links.$$.return AS return_key + FROM !table AS links + INNER JOIN sorties ON links.$$.temp_key = sorties.key + ) AS filtered_links ON filtered_links.return_key = mvt.key + WHERE !cat_condition + ) + SELECT * FROM sorties UNION SELECT * FROM entrees + ) + ORDER BY id DESC, user + ; + !table=$module.table + !op = $out_keys + !cat_condition=$cat_condition +}} + {{:assign var="op_label" from="config.%s_nature.%s.label"|args:$direction:$operation}} + {{:assign file_path="%s/%s/"|args:$module.storage_root:$key}} + {{:assign file_path=$file_path|cat:"%"}} + {{#select count(*) AS nb FROM files WHERE path LIKE :file_path ; :file_path=$file_path}} + {{:assign nb_files=$nb}} + {{/select}} + + {{if $premier}} + + + + + + + + + + + + + + + + + + {{:assign premier=false}} + {{/if}} + + + + + + + + + + + + + + +{{else}} +

Aucun mouvement.

+{{/select}} + +
DateMouvementOpérationMatérielQuantitéDépositaireStockageDocumentsÉcrituresRemarque
{{$date|date_short}}{{if $direction == "input"}}Entrée{{else}}Sortie{{/if}}{{$op_label}}{{$materiel}}{{$amount}}{{:link href="/admin/users/details.php?id=%s"|args:$user_id label="%s"|args:$user}}{{$stockage}}{{if $nb_files > 0}}{{$nb_files}}{{/if}}{{if $transactions != null}}{{"Oui"}}{{/if}}{{$comment}} + {{if $_GET.output_type == "loan"}} + {{:assign from="lm"}} + {{elseif $_GET.output_type == "rent"}} + {{:assign from="rm"}} + {{/if}} + {{:linkbutton + label="Détails" + href="movements/movement_details.html?key=%s&prop=1&from=%s"|args:$key:$from + shape="eye" + }} +
+{{else}} +

Aucun mouvement.

+{{/if}} +{{:admin_footer}} diff --git a/member_history.html b/member_history.html new file mode 100644 index 0000000..f5c676b --- /dev/null +++ b/member_history.html @@ -0,0 +1,129 @@ +{{* -*- brindille -*- *}} + +{{* + Afficher l'historique des mouvements d'un matériel pour un membre + paramètres + - key : clé du matériel + - id : id du membre +*}} + +{{if $_GET.id|intval !== $logged_user.id}} + {{#restrict section="users" level="read" block=true}}{{/restrict}} +{{/if}} + +{{:admin_header title="Historique membre" custom_css="./style.css" current="module_%s"|args:$module.name}} + +{{* lecture config (défaut ou enregistrée) *}} +{{:include file="./_get_config.html" keep="config, directions"}} + +{{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key=key}} + {{:assign var="types.%s.%s."|args:$direction:$type value=$key|quote_sql}} + {{/foreach}} + {{:assign var="io_types" from="types.%s"|args:$direction}} + {{#foreach from=$io_types key=key}} + {{:assign var=elem from="io_types.%s"|args:$key}} + {{:assign elem=$elem|implode:","}} + {{:assign elem="("|cat:$elem|cat:")"}} + {{:assign var="%s_types.%s"|args:$direction:$key value=$elem}} + {{/foreach}} +{{/foreach}} + +{{#users id=$_GET.id}} + {{:assign user_name=$nom}} +{{else}} + {{:error message="Il n'existe aucun membre avec l'identifiant %s !"|args:$_GET.id}} +{{/users}} + +{{#load key=$_GET.key|trim}} + {{:assign eqpmt_name=$name}} +{{else}} + {{:error message="Il n'existe aucun matériel avec la clé %s !"|args:$_GET.key|trim}} +{{/load}} + +

Historique des mouvements de « {{$eqpmt_name}} » du membre « {{$user_name}} »

+ +{{:assign otk=null}} +{{#select + mvt.key AS mvt_key, + mvt.$$.direction as direction, + mvt.$$.operation as operation, + mvt.$$.date as date, + mvt.$$.amount as amount, + COALESCE((SELECT + links.$$.temp_key + FROM !table AS links + WHERE links.$$.temp_key = mvt.key + OR links.$$.return = mvt.key), mvt.key) + AS out_temp_key + FROM !table AS mvt + INNER JOIN users ON mvt.$$.user = users.id + INNER JOIN !table AS eqpmt + ON mvt.$$.equipment = eqpmt.key + WHERE users.id = :user + AND eqpmt.key = :eqpmt_key + AND (mvt.$$.operation IN !output_types + OR mvt.$$.operation IN !input_types) + ORDER BY out_temp_key, date + ; + !table=$module.table + :user = $_GET.id + :eqpmt_key = $_GET.key|trim + !output_types=$output_types.temporaire + !input_types=$input_types.retour +}} + + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$direction:$operation}} + {{:assign var="op_label" from="config.%s_nature.%s.label"|args:$direction:$operation}} + {{:assign var="total" from="reste.%s"|args:$out_temp_key}} + {{if $total == null}} + {{:assign total=0}} + {{/if}} + + {{if $otk != null && $otk != $out_temp_key}} + + + {{/if}} + {{if $otk == null || $otk != $out_temp_key}} + + + + + + + + + + + + {{:assign otk=$out_temp_key}} + {{/if}} + + {{if $direction == 'input' && $type_mvt == 'retour'}} + {{:assign var="reste.%s"|args:$out_temp_key value="%d-%d"|math:$total:$amount}} + {{elseif $direction == 'output' && $type_mvt == 'temporaire'}} + {{:assign var="reste.%s"|args:$out_temp_key value="%d+%d"|math:$total:$amount}} + {{/if}} + {{:assign var="total" from="reste.%s"|args:$out_temp_key}} + + + + + + + + +{{/select}} + +
DateOpérationQuantitéTotal
{{$date|date_short}}{{$op_label}}{{$amount}}{{$total}} + {{#restrict section="accounting" level="write"}} + {{if $direction == "output" && $type_mvt == "temporaire"}} + {{:linkbutton + label="Retour" + href="%smovements/output_return.html?key=%s&prop=0&user=%s"|args:$module.url:$mvt_key:$_GET.id + shape="history" + target="_dialog"}} + {{/if}} + {{/restrict}} +
diff --git a/member_loan.html b/member_loan.html new file mode 100644 index 0000000..120eda0 --- /dev/null +++ b/member_loan.html @@ -0,0 +1,105 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres : + - id : id membre +*}} + +{{if $_GET.output_type == "loan"}} + {{:assign label="prêt"}} +{{elseif $_GET.output_type == "rent"}} + {{:assign label="location"}} +{{else}} + {{:error message="Cette page n'existe pas !"}} +{{/if}} + +{{:admin_header title="%ss aux membres"|args:$label|ucfirst custom_css="./style.css" current="module_%s"|args:$module.name}} +{{:include file="./_nav.html" current="%s"|args:$label subcurrent="membres"}} + +{{* vérifier l'existence de la table du module *}} +{{#load limit="1"}} + {{:assign table_presente=true}} +{{else}} + {{:assign table_presente=false}} +{{/load}} + +{{if $table_presente}} +{{:include file="./_get_config.html" keep="config"}} + +{{* déterminer les types de mouvements *}} +{{#foreach from=$config.output_nature key="key"}} + {{if $type != 'temporaire'}} + {{:continue}} + {{/if}} + {{if $_GET.output_type == "loan" && $fee != 'payant'}} + {{:assign var="out_keys." value=$key|quote_sql}} + {{elseif $_GET.output_type == "rent" && $fee == 'payant'}} + {{:assign var="out_keys." value=$key|quote_sql}} + {{/if}} +{{/foreach}} +{{:assign out_keys=$out_keys|implode:","}} +{{:assign out_keys="("|cat:$out_keys|cat:")"}} + +{{:assign premier=true}} +{{#select + nom, user, GROUP_CONCAT(mat_name, ", ") AS materiel, SUM(remain) AS quantite + FROM + (SELECT users.nom AS nom, + users.id AS user, + mat.$$.name AS mat_name, + mvt.$$.amount - IFNULL(SUM(retour.$$.amount), 0) AS remain + FROM !table AS mvt + INNER JOIN users ON mvt.$$.user = users.id + LEFT JOIN !table AS links ON mvt.key = links.$$.temp_key + LEFT JOIN !table AS retour ON retour.key = links.$$.return + INNER JOIN !table AS mat ON mat.key = mvt.$$.equipment + WHERE mvt.$$.type = 'movement' + AND mvt.$$.operation IN !op + GROUP BY mvt.key + HAVING remain != 0 + ) + GROUP BY user + ORDER BY nom + ; + !table=$module.table + !op = $out_keys + }} + + {{if $premier}} + + + + + + + + + + {{:assign premier=false}} + {{/if}} + + + + + + +{{else}} + {{if $label == "prêt"}} +

Aucun {{$label}} en cours.

+ {{elseif $label == "location"}} +

Aucune {{$label}} en cours.

+ {{/if}} +{{/select}} + +
MembreQuantitéMatériels
{{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$nom}}{{$quantite}}{{$materiel}}
+{{else}} + {{if $label == "prêt"}} +

Aucun {{$label}} en cours.

+ {{elseif $label == "location"}} +

Aucune {{$label}} en cours.

+ {{/if}} +{{/if}} + +{{:admin_footer}} diff --git a/modify_equipment.html b/modify_equipment.html new file mode 100644 index 0000000..6c03fa8 --- /dev/null +++ b/modify_equipment.html @@ -0,0 +1,234 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Paramètres : + - key : clé du matériel à modifier + - prop : =1 si matériel propriété de l'association, 0 sinon +*}} + +{{:assign equipment_key=$_GET.key|trim}} +{{#load key=$_GET.key assign="equipment"}} +{{else}} + {{:error message="Pas de matériel avec la clé %s"|args:$equipment_key}} +{{/load}} +{{:assign default_category=$equipment.category}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + + {{if $_POST.archive == 1}} + {{* vérifier les quantités *}} + {{if $_GET.prop == 1 && $equipment.stock != 0}} + {{:error message="L'archivage n'est possible que si le stock est nul !"}} + {{elseif $_GET.prop == 0 && $equipment.notowned != 0}} + {{:error message="L'archivage n'est possible que s'il n'y a plus de matériel présent temporairement"}} + {{/if}} + {{* archiver le matériel *}} + {{:save + key=$equipment_key + status="archived" + }} + {{else}} + + {{* récupérer les infos de la catégorie *}} + {{#load type="category" key=$_POST.category assign="category"}}{{/load}} + + {{* vérifier la validité des changements demandés *}} + {{:assign chgt_ok=true}} + {{if $_POST.category != $default_category}} + + {{* catégorie change : vérifier le nom *}} + {{#load key=$equipment_key}} + {{if $name|trim|tolower != $_POST.name|trim|tolower}} + {{* le nom change => vérifier l'existence d'un matériel du même nom *}} + {{#load type="equipment" where="$$.name = :name COLLATE U_NOCASE" :name=$_POST.name|trim limit=1}} + {{:assign chgt_ok=false}} + {{/load}} + {{else}} + {{* le nom ne change pas : ok *}} + {{/if}} + {{/load}} + + {{else}} + {{* catégorie ne change pas => vérifier le nom *}} + {{#load type="equipment" where="$$.name = :name COLLATE U_NOCASE" :name=$_POST.name|trim limit=1}} + {{*:assign chgt_ok=false*}} + {{:assign var="_err_msg" value="Erreur : il existe déjà un matériel avec cette désignation"}} + {{/load}} + {{* N° de série & quantités *}} + {{if $_POST.serialno && $_POST.amount > 1 }} + {{:assign chgt_ok=false}} + {{:assign var="_err_msg" value="Si un n° de série est défini, la quantité doit être égale à 1"}} + {{/if}} + {{/if}} + + {{if $chgt_ok==false}} + {{:error message=$_err_msg}} + {{/if}} + + {{* stock ou temporaire ? *}} + {{:assign var="type_mvt" value=$_POST.operation}} + {{if $type_mvt == 'définitif'}} + {{:assign _stock=$_POST.amount|intval}} + {{:assign _notowned=0}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign _notowned=$_POST.amount|intval}} + {{:assign _stock=0}} + {{else}} + {{:debug conf=$config.input_nature type=$type_mvt post=$_POST.operation}} + {{:error message="break"}} + {{/if}} + + {{* Enregistrer membre *}} + {{if $_POST.user|count > 1}} + {{:error message="Un membre au plus peut être associé à un équipement !"}} + {{else}} + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + {{/if}} + + {{* Champs personnalisés *}} + {{#foreach from=$module.config.fields key="i" item="field"}} + {{if $field.assignedto == 'M'}} + {{:assign var="value" from="_POST.fields.%d"|args:$i}} + {{:assign var="fields" append=$i value=$value label=$field.label}} + {{if $field.required && $value|trim === ''}} + {{:error message="Le champ '%s' doit être renseigné."|args:$field.label}} + {{/if}} + {{/if}} + {{/foreach}} + + {{* Temp *}} + {{if $_POST.status == "available"}} + {{:assign var="_status" value="disponible"}} + {{else}} + {{:assign var="_status" value=$_POST.status}} + {{/if}} + + {{* enregistrer les modifications *}} + {{:save + key=$equipment_key + validate_schema="./equipment.schema.json" + category=$category.key + name=$_POST.name|trim + status=$_status|trim + stock=$_stock|intval|or:0 + notowned=$_notowned|intval|or:0 + out=$_POST.out|intval|or:0 + state=$_POST.state|intval + serialno=$_POST.serialno|trim|or:null + description=$_POST.description|trim|or:null + member=$user.id|intval|or:null + fields=$fields|arrayval|or:null + }} + {{*:debug}} + {{:error message="break"*}} + {{/if}} + {{:redirect force="index.html?ok=1&msg=modification&prop=%s"|args:$_GET.prop}} +{{/form}} + +{{:admin_header title="Modifier matériel" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* lister les types d'entrées +{{#foreach from=$module.config.input_nature key=key}} + {{:assign var="input_labels.%s"|args:$key value=$label}} +{{/foreach}} +{{:debug types=$input_labels}} +*}} + +{{* lister les catégories disponibles *}} +{{#load type="category" assign="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$category.key value=$category.name}} +{{/load}} +{{*:debug types=$categories*}} + +{{* lister les états matériels possibles *}} +{{:assign var="states" value=$module.config.states|explode:","}} +{{*:debug types=$states*}} + +{{* Quantités stock ou temp *}} +{{if $equipment.stock >= 1}} + {{:assign _amount=$equipment.stock|intval}} + {{:assign _operation="définitif"}} +{{elseif $equipment.notowned >= 1}} + {{:assign _amount=$equipment.notowned|intval}} + {{:assign _operation="temporaire"}} +{{else}} + {{:assign _amount=$equipment.notowned|intval}} + {{:assign _operation="temporaire"}} +{{/if}} + +{{* Récupère le membre si présent +{{if $equipment.member >= 1}} + {{#select id, !name as nom FROM users WHERE id=:id; !name=$config.user_fields.name_sql :id=$equipment.member}} + {{:assign var="user.%s"|args:$id value=$nom}} + {{/select}} +{{/if}} +*}} +{{* Récupère le membre si présent *}} +{{if $equipment.member >= 1}} + {{#users id=$equipment.member}} + {{:assign var="user.%s"|args:$id value=$_name}} + {{/users}} +{{/if}} + +{{* N° de série *}} +{{if !$equipment.serialno }} + {{:assign var="_max" value="999"}} +{{else}} + {{:assign var="_max" value="1"}} +{{/if}} + +
+
+ Modifier un matériel +
+ {{:input type="select" name="category" label="Catégorie" default=$default_category required=true options=$categories}} + {{:input type="text" name="name" label="Désignation" default=$equipment.name required=true}} + {{:input type="textarea" cols=40 rows=3 name="description" label="Description complète" default=$equipment.description required=false}} + {{:input type="text" name="serialno" label="N° de suivi" default=$equipment.serialno required=false help="Exemples: numéro de série, code-barre, référence d'immobilisation, immatriculation, etc."}} + {{:input type="number" name="amount" label="Quantité (%s)"|args:$_operation min=1 max=$_max required=true default=$_amount help="Ne pas dépasser 1 si un N° de série est renseigné."}} + {{:input type="hidden" name="operation" default=$_operation }} + {{:input type="hidden" name="out" default=$equipment.out }} + {{:input type="hidden" name="status" default=$equipment.status }} + {{:input type="select" name="state" label="État du matériel" default_empty="— Aucun —" default=$equipment.state options=$states required=true}} + {{:input type="list" name="user" label="Donateur/Loueur" target="!users/selector.php" default=$user multiple=false can_delete=true help="Donateur ou Loueur (membres uniquement)"}} + {{:input type="checkbox" value=1 name="archive" label="Archiver" help="cocher pour archiver le matériel ; possible uniquement si la quantité en stock est nulle"}} +
+ Champs Personnalisés +
+ {{#foreach from=$module.config.fields key="i" item="field"}} + {{if $field.assignedto == 'M'}} + {{*:debug types=$equipment.fields*}} + {{:assign var="champ" from="equipment.fields.%d"|args:$i}} + {{*:debug i=$i label=$champ.label valeur=$champ.value*}} + {{if $field.type == 'checkbox'}} + {{:assign retval="Oui"}} + {{else}} + {{:assign var="retval" value=""}} + {{if $champ.value !== null}} + {{:assign var="retval" value=$champ.value}} + {{/if}} + {{*:debug i=$i val=$retval*}} + {{/if}} + {{if $field.type == 'monetary'}} + {{:input name="fields[%s]"|args:$i label=$field.label type="number" help=$field.help required=$field.required default=$retval value=$retval min="0" step="any"}} + {{else}} + {{:input name="fields[%s]"|args:$i label=$field.label type=$field.type help=$field.help required=$field.required default=$retval value=$retval}} + {{/if}} + {{/if}} + {{/foreach}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{* View and Add Public files *}} +{{:assign var="path" value="public/image-%s"|args:$equipment_key}} +{{:admin_files path=$path upload=true edit=true use_trash=false}} diff --git a/module.ini b/module.ini new file mode 100644 index 0000000..b787509 --- /dev/null +++ b/module.ini @@ -0,0 +1,10 @@ +name="Réservations de matériel" +description="Permet de gérer un inventaire de matériels, ainsi que de suivre les prêts.\nversion 0.71.7\n\nGestion des réservations de matériel via page web ou page membre.\nversion 1.0.0" +author="Jean-Christophe Engel(matériels)/Frédéric Boudaud(réservations)" +author_url="https://git.kaz.bzh/bountz/materiel_reservation" +home_button=true +menu=true +restrict_section="connect" +restrict_level="read" +restrict_details="Les membres connectés peuvent consulter l'historique de leurs prêts ; les membres ayant accès en lecture aux membres peuvent consulter l'historique des prêts des autres membres ; seuls les membres ayant accès en écriture à la comptabilité peuvent utiliser l'ensemble des fonctionnalités du module." +allow_user_restrict=false diff --git a/movements/_validate_modification.html b/movements/_validate_modification.html new file mode 100644 index 0000000..52b1253 --- /dev/null +++ b/movements/_validate_modification.html @@ -0,0 +1,44 @@ +{{* -*- brindille -*- + + Vérifier la cohérence des E/S d'un matériel + - paramètres : + - movements : liste de mouvements d'un matériel +*}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{:assign erreur=false}} +{{:assign stock=0}} +{{:assign exterieur=0}} +{{:assign nonprop=0}} + +{{#foreach from=$movements item="mvt"}} + {{* déterminer le type de mouvement *}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt.direction:$mvt.operation}} + + {{if $mvt.direction == 'input'}} + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d+%d"|math:$stock:$mvt.amount}} + {{elseif $type_mvt == 'retour'}} + {{:assign exterieur="%d-%d"|math:$exterieur:$mvt.amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign nonprop="%d+%d"|math:$nonprop:$mvt.amount}} + {{/if}} + {{elseif $mvt.direction == 'output'}} + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d-%d"|math:$stock:$mvt.amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign exterieur="%d+%d"|math:$exterieur:$mvt.amount}} + {{elseif $type_mvt == 'retour'}} + {{:assign nonprop="%d-%d"|math:$nonprop:$mvt.amount}} + {{/if}} + {{/if}} + + {{:assign dispo="%d-%d"|math:$stock:$exterieur}} + {{if $dispo < 0 || $stock < 0 || $exterieur < 0 || $nonprop < 0}} + {{:assign erreur=true}} + {{:assign var="pb.mvt" value=$mvt}} + {{:break}} + {{/if}} +{{/foreach}} diff --git a/movements/add_new_equipment.html b/movements/add_new_equipment.html new file mode 100644 index 0000000..1daf6f9 --- /dev/null +++ b/movements/add_new_equipment.html @@ -0,0 +1,234 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{* types d'entrées *}} +{{#foreach from=$config.input_nature key=key}} + {{if $type != 'retour'}} + {{:assign var="input_labels.%s"|args:$key value=$label}} + {{/if}} +{{/foreach}} + +{{* lister les catégories *}} +{{#load type="category" assign="category" order="$$.name"}} + {{:assign var="categories.%s"|args:$category.key value=$category.name}} +{{/load}} +{{* lister les états matériels possibles *}} +{{:assign var="states" value=$module.config.states|explode:","}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + + {{* vérifier la quantité saisie *}} + {{if $_POST.amount <= 0}} + {{:error message="La quantité (%s) doit être strictement positive !!"|args:$_POST.amount}} + {{/if}} + + {{* vérifier la date saisie *}} + {{:assign mvt_date=$_POST.date|parse_date}} + {{if $mvt_date == null || $mvt_date === false}} + {{:error message="La date saisie est vide ou incorrecte (%s)"|args:$_POST.date}} + {{/if}} + {{if $mvt_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + + {{* vérifier l'existence d'un matériel de même nom *}} + {{#load type="equipment" where="$$.name = :name COLLATE U_NOCASE" :name=$_POST.name|trim limit=1 assign="equipment"}} + {{:assign present=true}} + {{/load}} + {{:assign var=nom_cat from="categories.%s"|args:$equipment.category}} + {{:assign var=post_cat from="categories.%s"|args:$_POST.category}} + {{:assign post_mat=$_POST.name|trim}} + {{:assign var="type_mvt" from="config.input_nature.%s.type"|args:$_POST.operation}} + + {{if $present}} + {{* voir si le matériel existe dans une autre catégorie *}} + {{if $nom_cat != $post_cat}} + {{:error message="Le matériel « %s » est déjà présent dans la catégorie « %s » ..."|args:$post_mat:$nom_cat}} + {{/if}} + {{* calculer la nouvelle quantité du matériel *}} + {{if $type_mvt == 'définitif'}} + {{:assign var="equipment.stock" value="%d+%d"|math:$equipment.stock:$_POST.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="equipment.notowned" value="%d+%d"|math:$equipment.notowned:$_POST.amount|intval}} + {{/if}} + {{:assign equipment_key=$equipment.key}} + {{:save + key=$equipment_key + validate_schema="../equipment.schema.json" + type="equipment" + category=$_POST.category + name=$post_mat + status="disponible" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + state=$equipment.state + serialno=$equipment.serialno + description=$equipment.descriptio + member=$equipment.member + fields=$equipment.fields + }} + {{else}} + {{* enregistrer un nouveau matériel *}} + {{:assign equipment_key=""|uuid}} + {{if $type_mvt == 'définitif'}} + {{:assign stock=$_POST.amount|intval}} + {{:assign notowned=null}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign notowned=$_POST.amount|intval}} + {{:assign stock=null}} + {{/if}} + {{* Enregistrer membre *}} + {{if $_POST.user|count > 1}} + {{:error message="Un membre au plus peut être associé à un équipement !"}} + {{else}} + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + {{/if}} + {{* Champs personnalisés *}} + {{#foreach from=$module.config.fields key="i" item="field"}} + {{if $field.assignedto == 'M'}} + {{:assign var="value" from="_POST.fields.%d"|args:$i}} + {{:assign var="fields" append=$i value=$value label=$field.label}} + {{if $field.required && $value|trim === ''}} + {{:error message="Le champ '%s' doit être renseigné."|args:$field.label}} + {{/if}} + {{/if}} + {{/foreach}} + {{*:debug post=$_POST*}} + {{:save + key=$equipment_key + validate_schema="../equipment.schema.json" + type="equipment" + category=$_POST.category + name=$post_mat + status="disponible" + stock=$stock|intval|or:0 + out=0 + notowned=$notowned|intval|or:0 + state=$_POST.state|intval + serialno=$_POST.serialno|trim|or:null + description=$_POST.description|trim|or:null + member=$user.id|intval|or:null + fields=$fields|arrayval|or:null + }} + {{/if}} + + {{* documents liés *}} + {{#foreach from=$_POST.transactions item="value"}} + {{:assign var="transactions." value=$value|intval}} + {{/foreach}} + + {{* Enregistrer le mouvement *}} + {{:assign mvt_key=""|uuid}} + {{:assign var="operation" from="input_labels.%d"|args:$_POST.type_operation}} + + {{:save + key=$mvt_key + validate_schema="./movement.schema.json" + type="movement" + direction="input" + operation=$_POST.operation + amount=$_POST.amount|intval + equipment=$equipment_key + date=$mvt_date + comment=$_POST.remarques|trim + storage=$_POST.storage + transactions=$transactions + }} + + {{if $type_mvt == "temporaire"}} + {{:assign prop=0}} + {{else}} + {{:assign prop=1}} + {{/if}} + {{:redirect force="../index.html?prop=%s&ok=1&msg=ajout"|args:$prop}} +{{/form}} + +{{:admin_header title="Entrée de matériel" current="module_%s"|args:$module.name}} +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="entrees"}} +{{/if}} +{{:form_errors}} + +{{if $categories != null}} + {{#load type="storage" order="$$.name"}} + {{:assign var="storage.%s"|args:$key value=$name}} + {{/load}} + + {{* formulaire ajout matériel *}} +
+
+ Informations obligatoires +
+ {{:input type="date" name="date" label="Date" required=true default=$now|date_short}} + {{:input type="text" name="name" label="Désignation" required=true}} + {{:input type="textarea" cols=40 rows=3 name="description" label="Description complète" required=false}} + {{:input type="text" name="serialno" label="N° de suivi" required=false help="Exemples: numéro de série, code-barre, référence d'immobilisation, immatriculation, etc."}} + {{:input type="number" name="amount" label="Quantité" min=1 required=true default=1 help="Ne pas dépasser 1 si un N° de série est renseigné."}} + {{if $input_labels|count == 1}} + {{:input type="select" name="operation" label="Type" required=true options=$input_labels}} + {{else}} + {{:input type="select" name="operation" label="Type" required=true default_empty="— Aucun —" options=$input_labels|sort}} + {{/if}} + {{if $categories|count == 1}} + {{:input type="select" name="category" label="Catégorie" options=$categories required=true}} + {{else}} + {{:input type="select" name="category" label="Catégorie" default_empty="— Aucune —" options=$categories required=true}} + {{/if}} + {{:input type="select" name="state" label="État du matériel" default_empty="— Aucun —" options=$states required=true}} +
+
+
+ Autres informations +
+ {{if $storage != null}} + {{:input type="select" name="storage" label="Lieu de stockage" default_empty="— Aucun —" options=$storage required=false}} + {{/if}} + {{:input type="list" name="transactions" label="Écritures liées" target="!acc/transactions/selector.php" multiple=true help="par exemple écriture avec facture"}} + {{:input type="list" name="user" label="Donateur/Loueur" target="!users/selector.php" multiple=false can_delete=true help="Donateur ou Loueur (membres uniquement)"}} + {{*:input type="textarea" name="remarques" label="Remarques" cols="40", rows="3" required=false*}} +
+
+
+ Champs Personnalisés +
+ {{#foreach from=$module.config.fields key="i" item="field"}} + {{if $field.assignedto == 'M'}} + {{*:assign var="value" from="item.fields.%d"|args:$i}} + {{:assign var="_value" from="entry.fields.%d.value"|args:$i*}} + {{* aa:{{$i}} {{$field.label}} / {{$value.label}} / {{$value.value}} != {{$_value}} *}} + {{if $field.type == 'checkbox'}} + {{:assign retval="Oui"}} + {{else}} + {{*:assign var="retval" from='parentitem.0.fields.%d.value'|args:$i*}} + {{* bb: {{$retval}}*}} + {{*if $_value !== null}} + {{:assign var="retval" value=$_value}} + {{/if*}} + {{/if}} + {{if $field.type == 'monetary'}} + {{:input name="fields[%s]"|args:$i label=$field.label type="number" help=$field.help required=$field.required default=$retval value=$retval min="0" step="any"}} + {{else}} + {{:input name="fields[%s]"|args:$i label=$field.label type=$field.type help=$field.help required=$field.required default=$retval value=$retval}} + {{/if}} + {{/if}} + {{/foreach}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{else}} +

Il n'y a aucune catégorie, il faut en créer au moins une

+{{/if}} +{{:admin_footer}} \ No newline at end of file diff --git a/movements/copy_movement.html b/movements/copy_movement.html new file mode 100644 index 0000000..2a4ca38 --- /dev/null +++ b/movements/copy_movement.html @@ -0,0 +1,362 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Dupliquer un mouvement + paramètres : + - key : clé du mouvement à dupliquer + - prop = 1 si matériel appartient à l'asso, 0 sinon +*}} + +{{if $_GET.prop == null || $_GET.prop|intval != 0 && $_GET.prop|intval != 1}} + {{:error message="Opération interdite"}} +{{/if}} + +{{* récupérer les infos du mouvement à dupliquer *}} +{{#load key=$_GET.key assign="mvt_new"}} +{{else}} + {{:error message="Aucun mouvement avec la clé %s"|args:$_GET.key}} +{{/load}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config, directions"}} +{{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$mvt_new.operation}} + +{{* interdire de dupliquer un retour => utiliser le bouton « Retour » *}} +{{if $type_mvt == "retour"}} + {{:error message="Opération interdite !"}} +{{/if}} + +{{if $mvt_new.direction == "input"}} + {{if $type_mvt == "temporaire"}} + {{:assign prop=0}} + {{else}} + {{:assign prop=1}} + {{/if}} +{{else}} + {{:assign prop=1}} +{{/if}} + +{{* infos pour affichage *}} +{{:assign amount_init=$mvt_new.amount}} +{{:assign date_init=$mvt_new.date|date_short}} +{{:assign eqpmt_key=$mvt_new.equipment}} + +{{* récupérer les infos du matériel associé *}} +{{#load key=$eqpmt_key assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$eqpmt_key}} +{{/load}} + +{{* limiter les opérations possibles *}} +{{if $mvt_new.direction == "input"}} + {{* types d'entrées *}} + {{#foreach from=$config.input_nature key=key}} + {{if $_GET.prop|intval == 1 && $type == "définitif" || + $_GET.prop|intval == 0 && $type == "temporaire" + }} + {{:assign var="input_labels.%s"|args:$key value=$label}} + {{/if}} + {{/foreach}} +{{else}} + {{* types de sorties *}} + {{#foreach from=$config.output_nature key=key}} + {{if $_GET.prop|intval == 1 && $type != "retour"}} + {{:assign var="output_labels.%s"|args:$key value=$label}} + {{/if}} + {{/foreach}} +{{/if}} + +{{* + -------------------- Traiter la saisie -------------------- +*}} +{{#form on="save"}} + {{* vérifier la validité de la saisie *}} + {{if $_POST.amount <= 0}} + {{:error message="La quantité (%s) doit être strictement positive !!"|args:$_POST.amount}} + {{/if}} + + {{* vérifier les dates saisies *}} + {{:assign new_date=$_POST.date|parse_date}} + {{if $new_date == null || $new_date === false}} + {{:error message="La date saisie est vide ou incorrecte (%s)"|args:$_POST.date}} + {{/if}} + {{if $new_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + {{:assign return_date=$_POST.return_date|parse_date}} + {{if $return_date === false}} + {{:error message="La date de retour est incorrecte (%s)"|args:$_POST.return_date}} + {{/if}} + {{if $return_date != null && $return_date < $new_date}} + {{:error message="La date de retour doit être postérieure à la date de sortie !"}} + {{/if}} + + {{if $mvt_new.direction == "input" && $_POST.user != null}} + {{:error message="Un membre ne peut être associé qu'à une sortie"}} + {{/if}} + + {{if $_POST.user|count > 1}} + {{:error message="Un membre au plus peut être associé à une sortie"}} + {{/if}} + + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + + {{* préparer le mouvement copié *}} + {{:assign var="mvt_new.operation" value=$_POST.operation}} + {{:assign var="mvt_new.amount" value=$_POST.amount}} + {{:assign var="mvt_new.date" value=$new_date}} + {{:assign var="mvt_new.comment" value=$_POST.comment}} + + {{* + lister les mouvements + - insérer le mvt copié à sa place par date croissante + *}} + {{:assign insere=false}} + {{#load + where=" + $$.type = 'movement' + AND + $$.equipment = :eqpmt_key" + :eqpmt_key=$eqpmt_key + order="$$.date" + assign="movement" + }} + {{if ! $insere}} + {{if $mvt_new.date < $date}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.date == $date}} + {{if $mvt_new.direction == "input" && $type_mvt != "retour"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.direction == "output" && $type_mvt == "temporaire"}} + {{if $movement.direction == "input"}} + {{:assign var="type_mvt_crt" from="config.input_nature.%s.type"|args::$movement.operation}} + {{if $type_mvt_crt == "retour"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{/if}} + {{/if}} + {{/if}} + {{/if}} + {{/if}} + {{:assign var="movements_new." from=movement}} + {{/load}} + {{if ! $insere}} + {{:assign var="movements_new." from=mvt_new}} + {{/if}} + + {{* Vérifier la cohérence des mouvements du matériel *}} + {{:include + file="./_validate_modification.html" + keep="erreur" + movements=$movements_new + }} + {{if $erreur}} + {{:assign var="mvt_label" from="%s_labels.%s"|args:$mvt_new.direction:$mvt_new.operation}} + {{:assign new_date=$mvt_new.date|date_short}} + {{:error message="Impossible d'enregistrer ce mouvement : « %s de %s (qté : %s) à la date du %s »"|args:$mvt_label:$equipment.name:$mvt_new.amount:$new_date}} + {{/if}} + + {{* calculer la nouvelle quantité du matériel *}} + {{if $mvt_new.direction == "input"}} + {{:assign var="type_mvt" from="config.input_nature.%s.type"|args:$_POST.operation}} + {{if $type_mvt == 'définitif'}} + {{:assign var="equipment.stock" value="%d+%d"|math:$equipment.stock:$_POST.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="equipment.notowned" value="%d+%d"|math:$equipment.notowned:$_POST.amount|intval}} + {{elseif $type_mvt == 'retour'}} + {{:assign var="equipment.out" value="%d-%d"|math:$equipment.out:$_POST.amount|intval}} + {{/if}} + {{else}} + {{:assign var="type_mvt" from="config.output_nature.%s.type"|args:$_POST.operation}} + {{if $type_mvt == 'définitif'}} + {{:assign var="equipment.stock" value="%d-%d"|math:$equipment.stock:$_POST.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="equipment.out" value="%d+%d"|math:$equipment.out:$_POST.amount|intval}} + {{elseif $type_mvt == 'retour'}} + {{:assign var="equipment.notowned" value="%d-%d"|math:$equipment.notowned:$_POST.amount|intval}} + {{/if}} + {{/if}} + + {{:save + key=$equipment.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$equipment.category + name=$equipment.name + status="available" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + }} + + {{* documents liés *}} + {{#foreach from=$_POST.transactions item="value"}} + {{:assign var="transactions." value=$value|intval}} + {{/foreach}} + + {{* enregistrer le nouveau mouvement *}} + {{:assign mvt_key=""|uuid}} + {{:save + key=$mvt_key + validate_schema="movement.schema.json" + type="movement" + direction=$mvt_new.direction + operation=$_POST.operation + amount=$mvt_new.amount|intval + equipment=$eqpmt_key + date=$mvt_new.date + comment=$mvt_new.comment + user=$user.id + storage=$_POST.storage + transactions=$transactions + return_date=$return_date + }} + + {{if $_GET.from|substr:0:1 == "l"}} + {{:assign output_type="loan"}} + {{elseif $_GET.from|substr:0:1 == "r"}} + {{:assign output_type="rent"}} + {{/if}} + {{if $_GET.from|substr:1:1 == "h"}} + {{:assign suffix="history"}} + {{elseif $_GET.from|substr:1:1 == "m"}} + {{:assign suffix="movements"}} + {{/if}} + + {{if $_GET.from == "eh"}} + {{:redirect force="../equipment_history.html?ok=1&key=%s&prop=%s&msg=copie"|args:$eqpmt_key:$prop}} + {{elseif $suffix == null}} + {{:redirect force="../index.html"}} + {{else}} + {{:redirect force="../loan_%s.html?output_type=%s&ok=1&key=%s&prop=%s&msg=copie"|args:$suffix:$output_type:$eqpmt_key:$prop}} + {{/if}} +{{/form}} + +{{if $mvt_new.direction == "input"}} + {{:assign mvt_label="entrée"}} +{{else}} + {{:assign mvt_label="sortie"}} +{{/if}} +{{:admin_header title="Dupliquer une %s"|args:$mvt_label custom_css="./../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* + -------------------- Préparer la saisie -------------------- +*}} + +{{#load key=$equipment.category assign="category"}}{{/load}} +{{:assign var="op_label" from="config.%s_nature.%s.label"|args:$mvt_new.direction:$mvt_new.operation}} + +{{if $mvt_new.user != null}} + {{#select id, !name as nom FROM users WHERE id=:id; !name=$config.user_fields.name_sql :id=$mvt_new.user}} + {{:assign var="user.%s"|args:$id value=$nom}} + {{/select}} +{{/if}} + +{{#load type="storage" order="$$.name"}} + {{:assign var="storage.%s"|args:$key value=$name}} +{{/load}} + +{{* formulaire de copie du mouvement *}} +
+
+ Matériel +
+
Désignation
+
{{$equipment.name}}
+
Catégorie
+
{{$category.name}}
+
+
+
+ Informations obligatoires +
+ {{:input type="date" name="date" label="Date" required=true default=$mvt_new.date}} + {{:input type="number" name="amount" label="Quantité" min=1 required=true default=$mvt_new.amount}} + {{if $mvt_new.direction == "input"}} + {{:input type="select" name="operation" label="Type" required=true options=$input_labels|sort default=$mvt_new.operation}} + {{else}} + {{:input type="select" name="operation" label="Type" required=true options=$output_labels|sort default=$mvt_new.operation}} + {{/if}} +
+
+ +
+ Autres informations +
+ {{if $prop == 1 && $mvt_new.direction == "output"}} + {{:input + type="list" + name="user" + label="Membre destinataire" + default=$user + target="!users/selector.php" + multiple=true + max=1 + }} + {{/if}} + {{if $mvt_new.direction == "input" && $storage != null}} + {{:input type="select" name="storage" label="Lieu de stockage" default=$mvt_new.storage default_empty="— Aucun —" options=$storage required=false}} + {{/if}} + {{if $type_mvt != "retour"}} + {{:input type="list" name="transactions" label="Écritures liées" target="!acc/transactions/selector.php" multiple=true help="par exemple écriture avec facture"}} + {{/if}} + {{:input type="textarea" name="comment" label="Remarques" cols="40" rows="3" required=false default=$mvt_new.comment}} + {{if $mvt_new.direction == "output"}} + {{if $mvt_new.return_date != null}} + {{:assign return_date=$mvt_new.return_date}} + {{else}} + {{if $module.config.loan_duration != null && $module.config.loan_duration > 0}} + {{:assign ts_sortie=$mvt_new.date|strtotime}} + {{:assign ts_retour="%d+%d*(60*60*24)"|math:$ts_sortie:$module.config.loan_duration}} + {{:assign return_date=$ts_retour|date_short}} + {{/if}} + {{/if}} +
+ {{:input type="date" name="return_date" label="Date de retour" default=$return_date}} + +
+ {{/if}} +
+
+ +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+ +
+ +{{:admin_footer}} + + + + diff --git a/movements/delete_movement.html b/movements/delete_movement.html new file mode 100644 index 0000000..19971ab --- /dev/null +++ b/movements/delete_movement.html @@ -0,0 +1,192 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres GET : + - key : clé du mouvement à supprimer + - prop : = 1 si matériel propriété de l'asso +*}} + +{{#load key=$_GET.key assign="mvt_suppr"}} +{{else}} + {{:error message="Aucun mouvement avec la clé « %s »"|args:$_GET.key}} +{{/load}} + +{{* trouver le matériel concerné par ce mouvement *}} +{{#load type="equipment" where="key = :key" :key=$mvt_suppr.equipment assign="curr_eqpmt"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$mvt_suppr.equipment}} +{{/load}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{#form on="delete"}} + {{if $_GET.from|substr:0:1 == "l"}} + {{:assign output_type="loan"}} + {{elseif $_GET.from|substr:0:1 == "r"}} + {{:assign output_type="rent"}} + {{/if}} + {{if $_GET.from|substr:1:1 == "h"}} + {{:assign suffix="history"}} + {{elseif $_GET.from|substr:1:1 == "m"}} + {{:assign suffix="movements"}} + {{/if}} + {{if $_GET.from == "eh"}} + {{:assign from="../equipment_history.html"}} + {{elseif $suffix == null}} + {{:assign from="../index.html"}} + {{else}} + {{:assign from="../loan_%s.html"|args:$suffix}} + {{:assign param="&output_type=%s"|args:$output_type}} + {{/if}} + + {{* vérifier s'il est possible de supprimer le mouvement *}} + {{if $mvt_suppr.direction == 'input'}} + {{:assign var="type_operation" from="config.input_nature.%s.type"|args:$mvt_suppr.operation}} + {{if $type_operation == 'temporaire'}} + {{#load type="link" where="$$.temp_key = :key" :key=$_GET.key}} + {{:assign link_key=$key}} + {{/load}} + {{if $link_key != null}} + {{:redirect force="%s?key=%s&prop=%s&err=1&msg=suppression%s"|args:$from:$mvt_suppr.equipment:$_GET.prop:$param}} + {{/if}} + {{else}} + {{:assign dispo=0}} + {{:assign nonprop=0}} + + {{#load + type="movement" + where="$$.equipment = :key" :key=$mvt_suppr.equipment + assign="mvt" + order="$$.date"}} + + {{* déterminer le type de mouvement *}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt.direction:$mvt.operation}} + + {{if $key != $_GET.key}} + {{* ce n'est pas le mouvement à supprimer : cumuler les entrées/sorties *}} + {{if $mvt.direction == 'input'}} + {{if $type_mvt == 'temporaire'}} + {{:assign nonprop="%d+%d"|math:$nonprop:$mvt.amount}} + {{else}} + {{:assign dispo="%d+%d"|math:$dispo:$mvt.amount}} + {{/if}} + {{elseif $mvt.direction == 'output'}} + {{if $type_mvt == 'retour'}} + {{:assign nonprop="%d-%d"|math:$nonprop:$mvt.amount}} + {{else}} + {{:assign dispo="%d-%d"|math:$dispo:$mvt.amount}} + {{/if}} + {{/if}} + + {{* problème ? *}} + {{if $dispo < 0 || $nonprop < 0}} + {{:redirect force="%s?key=%s&prop=%s&err=1&msg=suppression%s"|args:$from:$mvt_suppr.equipment:$_GET.prop:$param}} + {{/if}} + {{/if}} + {{/load}} + + {{* suppression possible *}} + {{if $type_operation == 'retour'}} + {{#load type="link" where="$$.return = :key" :key=$_GET.key}} + {{:assign link_key=$key}} + {{/load}} + {{/if}} + {{/if}} + {{else}} + {{* sortie *}} + {{:assign var="type_operation" from="config.output_nature.%s.type"|args:$mvt_suppr.operation}} + + {{if $type_operation == 'temporaire'}} + {{#load type="link" where="$$.temp_key = :key OR $$.return = :key" :key=$_GET.key}} + {{:assign link_key=$key}} + {{/load}} + {{if $link_key != null}} + {{:redirect force="%s?key=%s&prop=%s&err=1&msg=suppression%s"|args:$from:$mvt_suppr.equipment:$_GET.prop:$param}} + {{/if}} + {{elseif $type_operation == 'retour'}} + {{#load type="link" where="$$.return = :key" :key=$_GET.key}} + {{:assign link_key=$key}} + {{/load}} + {{/if}} + {{/if}} + + {{* vérification réussie : supprimer le mouvement *}} + {{:delete key=$_GET.key}} + {{if $link_key != null}} + {{:delete key=$link_key}} + {{/if}} + + {{* voir s'il reste des mouvements pour le matériel concerné par le mouvement supprimé *}} + {{#foreach from=$config.input_nature key=key}} + {{if $type == 'définitif'}} + {{:assign var="input_types." value=$key}} + {{/if}} + {{/foreach}} + {{#load type="movement" where="$$.equipment = :eqpmt_key" :eqpmt_key=$curr_eqpmt.key}} + {{:assign mvt_ok=true}} + {{if $operation|in:$input_types}} + {{:assign entree_def=true}} + {{:break}} + {{/if}} + {{/load}} + + {{if $mvt_ok}} + {{* calculer et mettre à jour la nouvelle quantité du matériel *}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt_suppr.direction:$mvt_suppr.operation}} + {{if $mvt_suppr.direction == 'input'}} + {{if $type_mvt == 'définitif'}} + {{:assign var="curr_eqpmt.stock" value="%d-%d"|math:$curr_eqpmt.stock:$mvt_suppr.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="curr_eqpmt.notowned" value="%d-%d"|math:$curr_eqpmt.notowned:$mvt_suppr.amount|intval}} + {{elseif $type_mvt == 'retour'}} + {{:assign var="curr_eqpmt.out" value="%d+%d"|math:$curr_eqpmt.out:$mvt_suppr.amount|intval}} + {{/if}} + {{else}} + {{if $type_mvt == 'définitif'}} + {{:assign var="curr_eqpmt.stock" value="%d+%d"|math:$curr_eqpmt.stock:$mvt_suppr.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="curr_eqpmt.out" value="%d-%d"|math:$curr_eqpmt.out:$mvt_suppr.amount|intval}} + {{elseif $type_mvt == 'retour'}} + {{:assign var="curr_eqpmt.notowned" value="%d+%d"|math:$curr_eqpmt.notowned:$mvt_suppr.amount|intval}} + {{/if}} + {{/if}} + + {{if $curr_eqpmt.stock == 0 && ! $entree_def}} + {{:assign var="curr_eqpmt.stock" value=null}} + {{/if}} + + {{:save + key=$curr_eqpmt.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$curr_eqpmt.category + name=$curr_eqpmt.name + status="available" + stock=$curr_eqpmt.stock + out=$curr_eqpmt.out + notowned=$curr_eqpmt.notowned + }} + {{:redirect force="%s?ok=1&key=%s&prop=%s&msg=suppression%s"|args:$from:$mvt_suppr.equipment:$_GET.prop:$param}} + {{else}} + {{* supprimer le matériel *}} + {{:delete key=$curr_eqpmt.key}} + {{:redirect force="../index.html?ok=1&msg=supprmvtmat"|args}} + {{/if}} +{{/form}} + +{{:admin_header title="Supprimer un mouvement" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{:assign var="date_suppr" value="%s"|args:$mvt_suppr.date|date_short}} +{{:assign var="mvt_label" from="config.%s_nature.%s.label"|args:$mvt_suppr.direction:$mvt_suppr.operation}} + +{{:delete_form + legend="Supprimer ?" + warning="Supprimer le mouvement « %s de %s (quantité : %d) en date du %s » ?"|args:$mvt_label:$curr_eqpmt.name:$mvt_suppr.amount:$date_suppr +}} + + +{{:admin_footer}} diff --git a/movements/input_equipment.html b/movements/input_equipment.html new file mode 100644 index 0000000..e351981 --- /dev/null +++ b/movements/input_equipment.html @@ -0,0 +1,139 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Enregistrer une entrée de matériel + paramètres : + - key : clé du matériel à ajouter +*}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{* types d'entrées *}} +{{#foreach from=$config.input_nature key=key}} + {{if $type != 'retour'}} + {{:assign var="input_labels.%s"|args:$key value=$label}} + {{/if}} +{{/foreach}} + +{{* récupérer les informations du matériel et de sa catégorie *}} +{{#load key=$_GET.key assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$_GET.key}} +{{/load}} +{{#load where="key = :key" :key=$equipment.category assign="category"}} +{{/load}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + {{* vérifier la quantité saisie *}} + {{if $_POST.amount <= 0}} + {{:error message="La quantité (%s) doit être strictement positive !!"|args:$_POST.amount}} + {{/if}} + + {{* vérifier la date saisie *}} + {{:assign mvt_date=$_POST.date|parse_date}} + {{if $mvt_date == null || $mvt_date === false}} + {{:error message="La date saisie est vide ou incorrecte (%s)"|args:$_POST.date}} + {{/if}} + {{if $mvt_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + + {{* calculer la nouvelle quantité du matériel *}} + {{:assign var="type_mvt" from="config.input_nature.%s.type"|args:$_POST.operation}} + {{if $type_mvt == 'définitif'}} + {{:assign var="equipment.stock" value="%d+%d"|math:$equipment.stock:$_POST.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="equipment.notowned" value="%d+%d"|math:$equipment.notowned:$_POST.amount|intval}} + {{/if}} + + {{* écritures liées *}} + {{#foreach from=$_POST.transactions item="value"}} + {{:assign var="transactions." value=$value|intval}} + {{/foreach}} + + {{:save + key=$equipment.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$equipment.category + name=$equipment.name + status="available" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + }} + + {{* Enregistrer le mouvement *}} + {{:assign mvt_key=""|uuid}} + {{:save + key=$mvt_key + validate_schema="./movement.schema.json" + type="movement" + direction="input" + operation=$_POST.operation + amount=$_POST.amount|intval + equipment=$equipment.key + date=$mvt_date + comment=$_POST.remarques|trim + storage=$_POST.storage + transactions=$transactions + }} + {{:assign var=type_entree from="config.input_nature.%s.type"|args:$_POST.operation}} + {{if $type_entree == "temporaire"}} + {{:assign prop=0}} + {{else}} + {{:assign prop=1}} + {{/if}} + {{:redirect force="../equipment_history.html?key=%s&ok=1&msg=entrée&prop=%s"|args:$equipment.key:$prop}} +{{/form}} + +{{:admin_header title="Entrée de matériel" custom_css="./../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* formulaire de saisie d'une entrée de matériel *}} +{{#load type="storage" order="$$.name"}} + {{:assign var="storage.%s"|args:$key value=$name}} +{{/load}} + +
+
+ Matériel +
+
Désignation
+
{{$equipment.name}}
+
Catégorie
+
{{$category.name}}
+
+
+
+ Informations obligatoires +
+ {{:input type="date" name="date" label="Date" required=true default=$now|date_short}} + {{:input type="number" name="amount" label="Quantité" required=true min=1 default=1}} + {{if $input_labels|count == 1}} + {{:input type="select" name="operation" label="Type d'entrée" required=true options=$input_labels}} + {{else}} + {{:input type="select" name="operation" label="Type d'entrée" required=true default_empty="— Aucun —" options=$input_labels|sort}} + {{/if}} +
+
+
+ Autres informations +
+ {{if $storage != null}} + {{:input type="select" name="storage" label="Lieu de stockage" default_empty="— Aucun —" options=$storage required=false}} + {{/if}} + {{:input type="list" name="transactions" label="Écritures liées" target="!acc/transactions/selector.php" multiple=true help="par exemple écriture avec facture"}} + {{:input type="textarea" name="remarques" label="Remarques" cols="40" rows="3" required=false}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+ +{{:admin_footer}} \ No newline at end of file diff --git a/movements/input_return.html b/movements/input_return.html new file mode 100644 index 0000000..f425477 --- /dev/null +++ b/movements/input_return.html @@ -0,0 +1,239 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Enregistrer un retour d'entrée temporaire (l'asso rend le matériel loué) + paramètres : + - key : clé de l'entrée temporaire + - reskey : clé de la réservation associée (optionnelle) +*}} + +{{* infos du mouvement *}} +{{#load key=$_GET.key assign="mvt_new"}} +{{else}} + {{:error message="Aucun mouvement avec la clé %s"|args:$_GET.key}} +{{/load}} + +{{* infos du matériel associé *}} +{{#load key=$mvt_new.equipment assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$key}} +{{/load}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{* calculer la quantité entrée temporairement *}} +{{#foreach from=$config.input_nature key=key}} + {{if $type == "temporaire"}} + {{:assign var="temp_inputs." value=$key|quote_sql}} + {{/if}} +{{/foreach}} +{{:assign operations=$temp_inputs|implode:","}} +{{:assign operations="("|cat:$operations|cat:")"}} + +{{#select + mvt.$$.amount - IFNULL(SUM(mvt2.$$.amount), 0) AS present + FROM !table AS mvt + LEFT JOIN !table AS link ON mvt.key = link.$$.temp_key + LEFT JOIN !table AS mvt2 ON mvt2.key = link.$$.return + WHERE + mvt.$$.operation IN !op + AND mvt.key = :mvt_key + GROUP by mvt.key + ; + !table=$module.table + !op = $operations + :mvt_key = $_GET.key + }} + {{:assign present=$present}} +{{/select}} + +{{* + -------------------- Traiter la saisie -------------------- +*}} +{{#form on="save"}} + {{* vérifier validité des données *}} + {{if $_POST.amount <= 0}} + {{:error message="La quantité (%s) doit être strictement positive !!"|args:$_POST.amount}} + {{/if}} + + {{if $_POST.amount > $present}} + {{:error message="La quantité (%s) doit être inférieure à la quantité présente (%s) !!"|args:$_POST.amount:$present}} + {{/if}} + + {{if $_POST.date|parse_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + + {{* préparer le nouveau mouvement *}} + {{:assign var="mvt_new.key" value=""|uuid}} + {{:assign var="mvt_new.direction" value="output"}} + {{:assign var="mvt_new.date" value=$_POST.date|parse_date}} + {{:assign var="mvt_new.operation" value=$_POST.operation}} + {{:assign var="mvt_new.amount" value=$_POST.amount}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$mvt_new.operation}} + + {{* + lister les mouvements + - insérer le nouveau mvt à sa place par date croissante + *}} + {{:assign insere=false}} + {{#load + where=" + $$.type = 'movement' + AND + $$.equipment = :eqpmt_key" + :eqpmt_key=$equipment.key + order="$$.date" + assign="movement" + }} + {{if ! $insere}} + {{if $mvt_new.date < $date}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.date == $date}} + {{if $mvt_new.direction == "input" && $type_mvt != "retour"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.direction == "output" && $type_mvt == "temporaire"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{/if}} + {{/if}} + {{/if}} + {{:assign var="movements_new." from=movement}} + {{/load}} + {{if ! $insere}} + {{:assign var="movements_new." from=mvt_new}} + {{/if}} + + {{* Vérifier la cohérence des mouvements du matériel *}} + {{:include + file="./_validate_modification.html" + keep="erreur, pb" + movements=$movements_new + }} + + {{if $erreur}} + {{:assign message="Impossible d'enregistrer ce mouvement."}} + {{if $pb.mvt.key != $mvt_new.key}} + {{:assign var="err_mvt_label" from="config.output_nature.%s.label"|args:$pb.mvt.operation}} + {{:assign date_pb=$pb.mvt.date|date_short}} + {{:assign var=message2 value=" Mouvement incompatible avec « %s » : « %s (qté : %s) en date du %s »."|args:$err_mvt_label:$equipment.name:$pb.mvt.amount:$date_pb}} + {{:assign message=$message|cat:$message2}} + {{/if}} + {{:error message=$message}} + {{/if}} + + {{* calculer la nouvelle quantité du matériel *}} + {{:assign var="type_mvt" from="config.output_nature.%s.type"|args:$_POST.operation}} + {{:assign var="equipment.notowned" value="%d-%d"|math:$equipment.notowned:$_POST.amount|intval}} + + {{:save + key=$equipment.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$equipment.category + name=$equipment.name + status="available" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + }} + + {{* vérification réussie : enregistrer le mouvement modifié *}} + {{:assign mvt_key=""|uuid}} + {{:save + key=$mvt_key + validate_schema="movement.schema.json" + type="movement" + direction="output" + operation=$_POST.operation + amount=$_POST.amount|intval + equipment=$equipment.key + date=$_POST.date|parse_date + comment=$_POST.comment|trim + }} + {{* enregistrer la liaison entre le retour et la sortie temporaire *}} + {{:save + key=""|uuid + validate_schema="link.schema.json" + type="link" + direction="input" + temp_key=$_GET.key + return=$mvt_key + }} + {{* Enregistrer le retour (status passe à "archivée") dans la réservation *}} + {{if $_POST.resa_key}} + {{:save + key=$_POST.resa_key + validate_schema="../reservation.schema.json" + type="reservation" + comment=$_POST.comment|trim + return_date=$_POST.date + status="archivée" + mvt_key=$mvt_key + }} + {{/if}} + + {{:redirect force="../equipment_history.html?ok=1&key=%s&prop=0&msg=retour"|args:$mvt_new.equipment}} +{{/form}} + +{{:admin_header title="Retour de matériel" custom_css="../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="entrees"}} +{{/if}} + +{{* + -------------------- Préparer la saisie -------------------- +*}} + +{{#foreach from=$config.output_nature key=key}} + {{if $type == "retour"}} + {{:assign var="return_label.%s"|args:$key value=$label}} + {{:break}} + {{/if}} +{{/foreach}} + +{{* infos de la catégorie *}} +{{#load key=$equipment.category assign="category"}}{{/load}} + +{{* Charge la réservation si présente *}} +{{if $_GET.reskey}} + {{#load key=$_GET.reskey assign="resa"}}{{/load}} +{{/if}} + +
+
+ Matériel +
+
Désignation
+
{{$equipment.name}}
+
Catégorie
+
{{$category.name}}
+
Quantité disponible
+
{{$present}}
+
+
+
+ Retour de matériel +
+ {{:input type="date" name="date" label="Date" required=true default=$now|date_short}} + {{:input type="number" name="amount" label="Quantité" min=1 max=$present required=true default=1}} + {{:input type="select" name="operation" label="Type de mouvement" required=true options=$return_label}} + {{:input type="textarea" name="comment" label="Remarques" cols="40" rows="3" required=false}} + +
+
+ +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+ +{{:admin_footer}} diff --git a/movements/link.schema.json b/movements/link.schema.json new file mode 100644 index 0000000..57c6846 --- /dev/null +++ b/movements/link.schema.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["link"] + }, + "direction" : { + "type" : "string", + "enum" : ["input", "output"] + }, + "temp_key" : { + "description": "clé d'une entrée ou sortie temporaire", + "type": "string" + }, + "return": { + "description": "clé du retour associé", + "type": "string" + } + }, + "required": ["type", "direction", "temp_key", "return"] +} diff --git a/movements/modify_movement.html b/movements/modify_movement.html new file mode 100644 index 0000000..a46d626 --- /dev/null +++ b/movements/modify_movement.html @@ -0,0 +1,381 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Modifier un mouvement + paramètres : + - key : clé du mouvement à modifier +*}} + +{{* récupérer les infos du mouvement à modifier *}} +{{#load key=$_GET.key assign="mvt_new"}} +{{else}} + {{:error message="Aucun mouvement avec la clé %s"|args:$_GET.key}} +{{/load}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config, directions"}} + +{{* infos pour affichage *}} +{{:assign var="op_label" from="config.%s_nature.%s.label"|args:$mvt_new.direction:$mvt_new.operation}} +{{:assign amount_init=$mvt_new.amount}} +{{:assign operation_init=$mvt_new.operation}} +{{:assign date_init=$mvt_new.date|date_short}} +{{:assign eqpmt_key=$mvt_new.equipment}} + +{{* récupérer les infos du matériel associé *}} +{{#load key=$eqpmt_key assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$eqpmt_key}} +{{/load}} + +{{* + -------------------- Traiter la saisie -------------------- +*}} +{{#form on="save"}} + {{* vérifier la validité de la saisie *}} + {{if $_POST.amount <= 0}} + {{:error message="La quantité (%s) doit être strictement positive !!"|args:$_POST.amount}} + {{/if}} + + {{* vérifier les dates saisies *}} + {{:assign new_date=$_POST.date|parse_date}} + {{if $new_date == null || $new_date === false}} + {{:error message="La date saisie est vide ou incorrecte (%s)"|args:$_POST.date}} + {{/if}} + {{if $new_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + {{:assign return_date=$_POST.return_date|parse_date}} + {{if $return_date === false}} + {{:error message="La date de retour est incorrecte (%s)"|args:$_POST.return_date}} + {{/if}} + {{if $return_date != null && $return_date < $new_date}} + {{:error message="La date de retour doit être postérieure à la date de sortie !"}} + {{/if}} + + {{if $mvt_new.direction == "input" && $_POST.user != null}} + {{:error message="Un membre ne peut être associé qu'à une sortie"}} + {{/if}} + + {{if $_POST.user|count > 1}} + {{:error message="Un membre au plus peut être associé à une sortie"}} + {{/if}} + + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + + {{* préparer le mouvement modifié *}} + {{:assign var="mvt_new.operation" value=$_POST.operation}} + {{:assign var="mvt_new.amount" value=$_POST.amount}} + {{:assign var="mvt_new.date" value=$new_date}} + {{:assign var="mvt_new.comment" value=$_POST.comment}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$mvt_new.operation}} + + {{* + lister les mouvements + - ignorer le mouvement à modifier + - insérer le mvt modifié à sa place par date croissante + *}} + {{:assign insere=false}} + {{#load + where="$$.type = 'movement' AND $$.equipment = :eqpmt_key" + :eqpmt_key=$eqpmt_key + order="$$.date" + assign="movement" + }} + {{if $key != $_GET.key}} + {{if ! $insere}} + {{if $mvt_new.date < $date}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.date == $date}} + {{if $mvt_new.direction == "input" && $type_mvt != "retour"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.direction == "output" && $type_mvt == "temporaire"}} + {{if $movement.direction == "input"}} + {{:assign var="type_mvt_crt" from="config.input_nature.%s.type"|args::$movement.operation}} + {{if $type_mvt_crt == "retour"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{/if}} + {{/if}} + {{/if}} + {{/if}} + {{/if}} + {{:assign var="movements_new." from=movement}} + {{/if}} + {{/load}} + {{if ! $insere}} + {{:assign var="movements_new." from=mvt_new}} + {{/if}} + + {{* Vérifier la cohérence des mouvements du matériel *}} + {{:include + file="./_validate_modification.html" + keep="erreur" + movements=$movements_new + }} + + {{if $erreur}} + {{:assign var="new_op_label" from="config.%s_nature.%s.label"|args:$mvt_new.direction:$mvt_new.operation}} + {{:assign new_date=$mvt_new.date|date_short}} + {{:error message="Modification impossible : « %s de %s (qté : %s) en date du %s » vers « %s de %s (qté : %s) à la date du %s »"|args:$op_label:$equipment.name:$amount_init:$date_init:$new_op_label:$equipment.name:$mvt_new.amount:$new_date}} + {{/if}} + + {{* calculer la nouvelle quantité du matériel *}} + {{:assign var="type_mvt_init" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$operation_init}} + {{:assign var="type_mvt_final" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$mvt_new.operation}} + + {{if $mvt_new.direction == 'input'}} + {{if $type_mvt_init == 'définitif'}} + {{:assign var="equipment.stock" value="%d-%d"|math:$equipment.stock:$amount_init}} + {{elseif $type_mvt_init == 'temporaire'}} + {{:assign var="equipment.notowned" value="%d-%d"|math:$equipment.notowned:$amount_init}} + {{elseif $type_mvt_init == 'retour'}} + {{:assign var="equipment.out" value="%d+%d"|math:$equipment.out:$amount_init}} + {{/if}} + + {{if $type_mvt_final == 'définitif'}} + {{:assign var="equipment.stock" value="%d+%d"|math:$equipment.stock:$mvt_new.amount|intval}} + {{elseif $type_mvt_final == 'temporaire'}} + {{:assign var="equipment.notowned" value="%d+%d"|math:$equipment.notowned:$mvt_new.amount|intval}} + {{elseif $type_mvt_final == 'retour'}} + {{:assign var="equipment.out" value="%d-%d"|math:$equipment.out:$mvt_new.amount|intval}} + {{/if}} + {{else}} + {{if $type_mvt_init == 'définitif'}} + {{:assign var="equipment.stock" value="%d+%d"|math:$equipment.stock:$amount_init}} + {{elseif $type_mvt_init == 'temporaire'}} + {{:assign var="equipment.out" value="%d-%d"|math:$equipment.out:$amount_init}} + {{elseif $type_mvt_init == 'retour'}} + {{:assign var="equipment.notowned" value="%d+%d"|math:$equipment.notowned:$amount_init}} + {{/if}} + + {{if $type_mvt_final == 'définitif'}} + {{:assign var="equipment.stock" value="%d-%d"|math:$equipment.stock:$mvt_new.amount|intval}} + {{elseif $type_mvt_final == 'temporaire'}} + {{:assign var="equipment.out" value="%d+%d"|math:$equipment.out:$mvt_new.amount|intval}} + {{elseif $type_mvt_final == 'retour'}} + {{:assign var="equipment.notowned" value="%d-%d"|math:$equipment.notowned:$mvt_new.amount|intval}} + {{/if}} + {{/if}} + + {{* documents liés *}} + {{#foreach from=$_POST.transactions item="value"}} + {{:assign var="transactions." value=$value|intval}} + {{/foreach}} + + {{:save + key=$equipment.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$equipment.category + name=$equipment.name + status="available" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + }} + + {{* enregistrer le mouvement modifié *}} + {{if $user == null}} + {{:assign user_id=null}} + {{else}} + {{:assign user_id=$user.id}} + {{/if}} + + {{:save + key=$_GET.key + validate_schema="movement.schema.json" + type="movement" + direction=$mvt_new.direction + operation=$_POST.operation + amount=$mvt_new.amount|intval + equipment=$eqpmt_key + date=$mvt_new.date + comment=$mvt_new.comment + user=$user_id + storage=$_POST.storage + transactions=$transactions + return_date=$return_date + }} + + {{if $_GET.from|substr:0:1 == "l"}} + {{:assign output_type="loan"}} + {{elseif $_GET.from|substr:0:1 == "r"}} + {{:assign output_type="rent"}} + {{/if}} + {{if $_GET.from|substr:1:1 == "h"}} + {{:assign suffix="history"}} + {{elseif $_GET.from|substr:1:1 == "m"}} + {{:assign suffix="movements"}} + {{/if}} + + {{if $mvt_new.direction == "input"}} + {{if $type_mvt == "temporaire"}} + {{:assign prop=0}} + {{else}} + {{:assign prop=1}} + {{/if}} + {{else}} + {{if $type_mvt == "retour"}} + {{:assign prop=0}} + {{else}} + {{:assign prop=1}} + {{/if}} + {{/if}} + + {{if $_GET.from == "eh"}} + {{:redirect force="../equipment_history.html?ok=1&key=%s&prop=%s&msg=modification"|args:$eqpmt_key:$prop}} + {{elseif $suffix == null}} + {{:redirect force="../index.html"}} + {{else}} + {{:redirect force="../loan_%s.html?output_type=%s&ok=1&key=%s&prop=%s&msg=modification"|args:$suffix:$output_type:$eqpmt_key:$prop}} + {{/if}} +{{/form}} + +{{if $mvt_new.direction == "input"}} + {{:assign mvt_label="entrée"}} +{{else}} + {{:assign mvt_label="sortie"}} +{{/if}} +{{:admin_header title="Modifier une %s"|args:$mvt_label custom_css="./../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* + -------------------- Préparer la saisie -------------------- +*}} + +{{#load key=$equipment.category assign="category"}}{{/load}} + +{{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$mvt_new.operation}} +{{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key="key"}} + {{if $type_mvt != "retour" && $type != "retour" || + $type_mvt == "retour" && $type == "retour"}} + {{:assign var="%s_labels.%s"|args:$direction:$key value=$label}} + {{/if}} + {{/foreach}} +{{/foreach}} + + +{{if $mvt_new.user != null}} + {{#select id, !name as nom FROM users WHERE id=:id; !name=$config.user_fields.name_sql :id=$mvt_new.user}} + {{:assign var="user.%s"|args:$id value=$nom}} + {{/select}} +{{/if}} + +{{#load type="storage" order="$$.name"}} + {{:assign var="storage.%s"|args:$key value=$name}} +{{/load}} + +{{* formulaire de modification du mouvement *}} +
+
+ Matériel +
+
Désignation
+
{{$equipment.name}}
+
Catégorie
+
{{$category.name}}
+ {{if $mvt_new.transactions != null}} +
Écritures liées
+
+ {{#foreach from=$mvt_new.transactions item="trans"}} + {{:link class="num" href="!acc/transactions/details.php?id=%d"|args:$trans label=$trans}} + {{/foreach}} +
+ {{/if}} +
+
+
+ Informations obligatoires +
+ {{:input type="date" name="date" label="Date" required=true default=$mvt_new.date}} + {{:input type="number" name="amount" label="Quantité" min=1 required=true default=$mvt_new.amount}} + {{if $mvt_new.direction == "input"}} + {{:input type="select" name="operation" label="Type" required=true options=$input_labels|sort default=$mvt_new.operation}} + {{else}} + {{:input type="select" name="operation" label="Type" required=true options=$output_labels|sort default=$mvt_new.operation}} + {{/if}} +
+
+ +
+ Autres informations +
+ {{if $mvt_new.direction == "output" && $type_mvt != "retour"}} + {{:input + type="list" + name="user" + label="Membre destinataire" + default=$user + target="!users/selector.php" + multiple=true + max=1 + }} + {{/if}} + {{if $mvt_new.direction == "input" && $storage != null}} + {{:input type="select" name="storage" label="Lieu de stockage" default=$mvt_new.storage default_empty="— Aucun —" options=$storage required=false}} + {{/if}} + {{if $type_mvt != "retour"}} + {{:input type="list" name="transactions" label="Écritures liées" default=$mvt_new.transactions target="!acc/transactions/selector.php" multiple=true help="par exemple écriture avec facture"}} + {{/if}} + {{:input type="textarea" name="comment" label="Remarques" cols="40" rows="3" required=false default=$mvt_new.comment}} + {{if $mvt_new.direction == "output"}} + {{if $mvt_new.return_date != null}} + {{:assign return_date=$mvt_new.return_date}} + {{else}} + {{if $module.config.loan_duration != null && $module.config.loan_duration > 0}} + {{:assign ts_sortie=$mvt_new.date|strtotime}} + {{:assign ts_retour="%d+%d*(60*60*24)"|math:$ts_sortie:$module.config.loan_duration}} + {{:assign return_date=$ts_retour|date_short}} + {{/if}} + {{/if}} +
+ {{:input type="date" name="return_date" label="Date de retour" default=$return_date}} + +
+ {{/if}} +
+
+ +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+ +
+ +{{:admin_footer}} + + + + diff --git a/movements/movement.schema.json b/movements/movement.schema.json new file mode 100644 index 0000000..eaebdb3 --- /dev/null +++ b/movements/movement.schema.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["movement"] + }, + "direction" : { + "description": "Entrée ou sortie", + "type": "string", + "enum": ["input", "output"] + }, + "operation": { + "description": "clé de l'opération", + "type": "string" + }, + "amount": { + "description": "Quantité ajoutée ou retirée", + "type": "integer", + "minimum": 1 + }, + "equipment": { + "description": "Clé du matériel", + "type": "string" + }, + "date" : { + "description": "Date de l'opération", + "type": "string", + "format": "date" + }, + "comment": { + "description": "Commentaire additionnel", + "type": ["null", "string"] + }, + "user": { + "description": "identifiant membre dépositaire", + "type": ["integer", "null"] + }, + "storage": { + "description": "clé du lieu de stockage", + "type": ["string", "null"] + }, + "transactions": { + "type": ["array", "null"], + "items": { + "type": "integer" + } + }, + "return_date" : { + "description": "Date de retour du matériel", + "type" : ["null", "string"], + "format" : "date" + } + }, + "required": ["type", "direction", "operation", "amount", "equipment", "date", "comment"] +} diff --git a/movements/movement_details.html b/movements/movement_details.html new file mode 100644 index 0000000..faf37ac --- /dev/null +++ b/movements/movement_details.html @@ -0,0 +1,119 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Afficher les détails d'un mouvement et donner la possibilité : + - d'associer des fichiers + - de modifier, supprimer ou dupliquer le mouvement + paramètres : + - key : clé du mouvement + - prop = 1 si matériel appartient à l'asso + - from = page d'appel +*}} + +{{:admin_header title="Détails du mouvement" custom_css="../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* récupérer les infos du mouvement *}} +{{#load key=$_GET.key assign="mvt"}} +{{else}} + {{:error message="Aucun mouvement avec la clé %s"|args:$_GET.key}} +{{/load}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config, directions"}} +{{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt.direction:$mvt.operation}} + +{{* récupérer les infos du matériel associé *}} +{{#load key=$mvt.equipment assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$mvt.equipment}} +{{/load}} + +{{* + -------------------- Afficher les informations du mouvement -------------------- +*}} + +{{:assign var="op_label" from="config.%s_nature.%s.label"|args:$mvt.direction:$mvt.operation}} +{{#load key=$equipment.category assign="category"}}{{/load}} +{{#load key=$mvt.storage assign="storage"}}{{/load}} +{{#select !name as nom FROM users WHERE id=:id; !name=$config.user_fields.name_sql :id=$mvt.user}} + {{:assign user_name=$nom}} +{{/select}} + + + +
+
Opération
+
{{$op_label}}
+
Matériel
+
{{:link href="../equipment_history.html?key=%s&prop=%s"|args:$equipment.key:$_GET.prop label=$equipment.name}}
+
Catégorie
+
{{:link href="../index.html?cat_key=%s&prop=%s"|args:$category.key:$_GET.prop label=$category.name}}
+
Date
+
{{$mvt.date|date_short}}
+
Quantité
+
{{$mvt.amount}}
+ {{if $mvt.direction == "output" && $type_mvt != "retour"}} +
Membre destinataire
+
+ {{if $mvt.user != null}} + {{:link href="/admin/users/details.php?id=%s"|args:$mvt.user label=$user_name}} + {{else}}— + {{/if}} +
+ {{/if}} + {{if $mvt.direction == "input"}} +
Lieu de stockage
+
+ {{if $storage != null}} + {{$storage.name}} + {{else}}— + {{/if}} +
+ {{/if}} +
Écritures liées
+
+ {{#foreach from=$mvt.transactions item="trans"}} + {{:link class="num" href="!acc/transactions/details.php?id=%d"|args:$trans label=$trans}} + {{else}}— + {{/foreach}} +
+ {{if $mvt.direction == "output" && $type_mvt != "retour"}} +
Date de retour
+
+ {{if $mvt.return_date != null}} + {{$mvt.return_date|date_short}} + {{else}}— + {{/if}} +
+ {{/if}} +
Remarques
+
{{if $mvt.comment != null}} + {{$mvt.comment}} + {{else}}— + {{/if}} +
+
+ +{{:admin_files path=$mvt.key upload=true edit=true use_trash=false}} +{{:admin_footer}} diff --git a/movements/output_equipment.html b/movements/output_equipment.html new file mode 100644 index 0000000..31e3af7 --- /dev/null +++ b/movements/output_equipment.html @@ -0,0 +1,338 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres : + - key : clé du matériel à sortir + - output_type : (OBSOLÈTE ?) loan (prêt), rent (location), rien (cas général) + - reskey : clé de la réservation (optionnel) +*}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{* types de sorties *}} +{{#foreach from=$config.output_nature key=key}} + {{if $type == 'retour'}} + {{:continue}} + {{/if}} + {{if $type == 'temporaire' && $fee == 'payant'}} + {{:assign var="paid_keys." value=$key}} + {{/if}} + {{if $_GET.output_type == null}} + {{:assign var="output_labels.%s"|args:$key value=$label}} + {{elseif $type == 'temporaire' && $_GET.output_type == "loan" && $fee != 'payant'}} + {{:assign var="output_labels.%s"|args:$key value=$label}} + {{elseif $type == 'temporaire' && $_GET.output_type == "rent" && $fee == 'payant'}} + {{:assign var="output_labels.%s"|args:$key value=$label}} + {{else}} + {{:error message="Opération interdite"}} + {{/if}} +{{/foreach}} + +{{* récupérer les infos du matériel *}} +{{#load key=$_GET.key assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé %s"|args:$_GET.key}} +{{/load}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + {{* vérifier la validité de la saisie *}} + + {{* vérifier les dates saisies *}} + {{:assign mvt_date=$_POST.date|parse_date}} + {{if $mvt_date == null || $mvt_date === false}} + {{:error message="La date saisie est vide ou incorrecte (%s)"|args:$_POST.date}} + {{/if}} + {{if $mvt_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + {{:assign return_date=$_POST.return_date|parse_date}} + {{if $return_date === false}} + {{:error message="La date de retour est incorrecte (%s)"|args:$_POST.return_date}} + {{/if}} + {{if $return_date != null && $return_date < $mvt_date}} + {{:error message="La date de retour doit être postérieure à la date de sortie !"}} + {{/if}} + + {{if $_POST.operation == ""}} + {{:error message="Vous devez choisir un type de sortie"}} + {{/if}} + + {{:assign var="type_mvt" from="config.output_nature.%s.type"|args:$_POST.operation}} + {{if $type_mvt != "temporaire" && $_POST.return_date != null}} + {{:error message="On ne peut associer une date de retour qu'à une sortie temporaire"}} + {{/if}} + + {{if $_POST.user|count > 1}} + {{:error message="Un membre au plus peut être associé à une sortie"}} + {{/if}} + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + + {{:assign stock=0}} + {{:assign exterieur=0}} + {{:assign nonproprio=0}} + {{:assign insere=false}} + + {{* lister tous les mouvements du matériel *}} + {{#load type="movement" where="$$.equipment = :eqpmt_key" :eqpmt_key=$_GET.key assign="mvt" order="$$.date ASC"}} + {{* traiter le nouveau mouvement *}} + {{if ! $insere && $mvt.date > $mvt_date}} + {{:assign insere=true}} + {{:assign dispo_old="%d-%d"|math:$stock:$exterieur}} + + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d-%d"|math:$stock:$_POST.amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign exterieur="%d+%d"|math:$exterieur:$_POST.amount}} + {{/if}} + + {{:assign dispo="%d-%d"|math:$stock:$exterieur}} + {{if $dispo < 0 || $stock < 0 || $exterieur < 0}} + {{:error message="Erreur : la quantité indiquée (%s) est supérieure à celle disponible (%d) à la date du %s"|args:$_POST.amount:$dispo_old:$_POST.date}} + {{/if}} + {{/if}} + + {{* traiter le mouvement courant *}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt.direction:$mvt.operation}} + + {{if $mvt.direction === 'input'}} + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d+%d"|math:$stock:$mvt.amount}} + {{elseif $type_mvt == 'retour'}} + {{:assign exterieur="%d-%d"|math:$exterieur:$mvt.amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign nonproprio="%d+%d"|math:$nonproprio:$mvt.amount}} + {{/if}} + {{elseif $mvt.direction === 'output'}} + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d-%d"|math:$stock:$mvt.amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign exterieur="%d+%d"|math:$exterieur:$mvt.amount}} + {{elseif $type_mvt == 'retour'}} + {{:assign nonproprio="%d-%d"|math:$nonproprio:$mvt.amount}} + {{/if}} + {{/if}} + + {{:assign dispo="%d-%d"|math:$stock:$exterieur}} + + {{if $dispo < 0 || $stock < 0 || $exterieur < 0 || $nonproprio < 0}} + {{:assign date_err=$mvt.date|date:"d/m/Y"}} + {{:error message="Erreur : la quantité indiquée (%s) est incompatible avec la sortie de %s unités à la date du %s"|args:$_POST.amount:$mvt.amount:$date_err}} + {{/if}} + {{/load}} + {{if ! $insere}} + {{:assign dispo_old="%d-%d"|math:$stock:$exterieur}} + {{:assign var="type_mvt" from="config.output_nature.%s.type"|args:$_POST.operation}} + + {{if $type_mvt == 'définitif'}} + {{:assign stock="%d-%d"|math:$stock:$_POST.amount}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign exterieur="%d+%d"|math:$exterieur:$_POST.amount}} + {{/if}} + + {{:assign dispo="%d-%d"|math:$stock:$exterieur}} + {{if $dispo < 0 || $stock < 0 || $exterieur < 0}} + {{:error message="Erreur : la quantité indiquée (%s) est supérieure à celle disponible (%d) à la date du %s"|args:$_POST.amount:$dispo_old:$_POST.date}} + {{/if}} + {{/if}} + + {{* calculer la nouvelle quantité du matériel *}} + {{:assign var="type_mvt" from="config.output_nature.%s.type"|args:$_POST.operation}} + {{if $type_mvt == 'définitif'}} + {{:assign var="equipment.stock" value="%d-%d"|math:$equipment.stock:$_POST.amount|intval}} + {{elseif $type_mvt == 'temporaire'}} + {{:assign var="equipment.out" value="%d+%d"|math:$equipment.out:$_POST.amount|intval}} + {{/if}} + + {{* écritures liées *}} + {{#foreach from=$_POST.transactions item="value"}} + {{:assign var="transactions." value=$value|intval}} + {{/foreach}} + + {{* Enregistrer le stock dans le matériel *}} + {{:save + key=$equipment.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$equipment.category + name=$equipment.name + status="available" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + }} + + {{* Enregistrer le mouvement *}} + {{:assign mvt_key=""|uuid}} + {{:save + key=$mvt_key + validate_schema="./movement.schema.json" + type="movement" + direction="output" + operation=$_POST.operation + amount=$_POST.amount|intval + equipment=$equipment.key + date=$mvt_date + comment=$_POST.remarques|trim + user=$user.id + return_date=$return_date + transactions=$transactions + }} + + {{* Enregistrer le retrait (status passe à "en cours") dans la réservation *}} + {{if $_POST.resa_key}} + {{:save + key=$_POST.resa_key + validate_schema="../reservation.schema.json" + type="reservation" + comment=$_POST.remarques|trim + loan_date=$mvt_date + return_date=$return_date + status="en cours" + mvt_key=$mvt_key + }} + {{/if}} + {{:redirect force="../equipment_history.html?ok=1&key=%s&prop=1&msg=sortie"|args:$_GET.key}} +{{/form}} + +{{:admin_header title="Sortie de matériel" custom_css="./../style.css" current="module_%s"|args:$module.name}} +{{if ! $dialog}} + {{* barre de navigation *}} + {{:include file="../_nav.html" current="sorties"}} +{{/if}} +{{:form_errors}} + +{{* Charge la catégorie *}} +{{#load key=$equipment.category assign="category"}}{{/load}} +{{:assign dispo="%d-%d"|math:$equipment.stock:$equipment.out}} + +{{* Charge la réservation si présente *}} +{{if $_GET.reskey}} + {{#load key=$_GET.reskey assign="resa"}}{{/load}} + {{* gratuit(prêt) ou payant(location) ? *}} + {{#foreach from=$equipment.fields key="key"}} + {{if $label >= "Tarif par jour"}} + {{:assign var="prix" value=$value}} + {{/if}} + {{/foreach}} +{{/if}} +{{*:debug resa=$resa*}} + +{{if $dispo > 0}} + + {{if $resa.return_date}} + {{:assign date_retour=$resa.return_date|date_short}} + {{:assign _dr=$resa.return_date|parse_date|strtotime}} + {{:assign _dd=$resa.loan_date|parse_date|strtotime}} + {{:assign nbdejours="(%d-%d)/86400"|math:$_dr:$_dd}} + {{elseif $module.config.loan_duration != null && $module.config.loan_duration > 0}} + {{:assign ts_retour="%d+%d*(60*60*24)"|math:$now:$module.config.loan_duration}} + {{:assign date_retour=$ts_retour|date_short}} + {{/if}} + {{*:debug nbdejours=$nbdejours _dr=$_dr _dd=$_dd*}} + {{* formulaire de sortie de matériel *}} +
+
+ Matériel +
+
Matériel
+
{{$equipment.name}}
+
Catégorie
+
{{$category.name}}
+
Quantité disponible
+
{{$dispo}}
+
+
+
+ Informations obligatoires +
+ {{:input type="date" name="date" label="Date de sortie" required=true default=$now|date_short}} + {{if $resa.amount}} + {{:input type="number" name="amount" label="Quantité" required=true default=$resa.amount min=1 max=$dispo}} + {{else}} + {{:input type="number" name="amount" label="Quantité" required=true default=1 min=1 max=$dispo}} + {{/if}} + {{if $prix >= 1}} + {{:assign _help="Choisir 'Location' car le tarif journalier est de %s€."|args:$prix}} + {{else}} + {{:assign _help="Choisir 'Prêt' si gratuit."}} + {{/if}} + {{if $output_labels|count == 1}} + {{:input type="select" name="operation" label="Type de sortie" required=true options=$output_labels help=$_help}} + {{else}} + {{:input type="select" name="operation" label="Type de sortie" required=true default_empty="— Aucun —" options=$output_labels|sort help=$_help}} + {{/if}} + {{if $nbdejours}} + {{:input type="date" name="return_date" label="Date de retour" required=true default=$date_retour}} + + {{else}} +
+ {{:input type="date" id="return_date" name="return_date" label="Date de retour" default=$date_retour}} + +
+ {{/if}} +
+
+
+ Autres informations +
+ {{if $resa.member}} + {{:input type="text" name="user[%d]"|args:$resa.member label="Membre destinataire" default=$resa.name}} + {{else}} + {{:input + type="list" + name="user" + label="Membre destinataire" + target="!users/selector.php" + multiple=true + max=1 + }} + {{/if}} + {{:input type="list" name="transactions" label="Écritures liées" target="!acc/transactions/selector.php" multiple=true help="par exemple écriture avec facture"}} + {{:input type="textarea" name="remarques" label="Remarques" cols="40" rows="3" required=false}} + +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{else}} +

Il n'y a aucune unité de ce matériel disponible à la date du {{$now|date_short}}

+{{/if}} + +{{:admin_footer}} + + + +{{if !$nbdejours}} + +{{/if}} diff --git a/movements/output_return.html b/movements/output_return.html new file mode 100644 index 0000000..f543832 --- /dev/null +++ b/movements/output_return.html @@ -0,0 +1,268 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Enregistrer un retour de sortie temporaire + paramètres : + - key : clé de la sortie temporaire + - reskey : clé de la réservation associée (optionnelle) +*}} + +{{* infos du mouvement *}} +{{#load key=$_GET.key assign="mvt_new"}} +{{else}} + {{:error message="Aucun mouvement avec la clé %s"|args:$_GET.key}} +{{/load}} + +{{* infos du matériel associé *}} +{{#load key=$mvt_new.equipment assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$key}} +{{/load}} + +{{* récupérer la config des entrées/sorties *}} +{{:include file="../_get_config.html" keep="config"}} + +{{* calculer la quantité sortie temporairement *}} +{{#foreach from=$config.output_nature key=key}} + {{if $type == "temporaire"}} + {{:assign var="temp_outputs." value=$key|quote_sql}} + {{/if}} +{{/foreach}} +{{:assign operations=$temp_outputs|implode:","}} +{{:assign operations="("|cat:$operations|cat:")"}} + +{{#select + mvt.$$.amount - IFNULL(SUM(mvt2.$$.amount), 0) AS exterieur + FROM !table AS mvt + LEFT JOIN !table AS link ON mvt.key = link.$$.temp_key + LEFT JOIN !table AS mvt2 ON mvt2.key = link.$$.return + WHERE + mvt.$$.operation IN !op + AND mvt.key = :mvt_key + GROUP by mvt.key + ; + !table=$module.table + !op = $operations + :mvt_key = $_GET.key + }} + {{:assign exterieur=$exterieur}} +{{/select}} + +{{* + -------------------- Traiter la saisie -------------------- +*}} +{{#form on="save"}} + {{* vérifier validité des données *}} + {{if $_POST.amount <= 0}} + {{:error message="La quantité (%s) doit être strictement positive !!"|args:$_POST.amount}} + {{/if}} + + {{if $_POST.amount > $exterieur}} + {{:error message="La quantité (%s) doit être inférieure à la quantité sortie (%s) !!"|args:$_POST.amount:$exterieur}} + {{/if}} + + {{* vérifier le date saisie *}} + {{:assign new_date=$_POST.date|parse_date}} + {{if $new_date == null || $new_date === false}} + {{:error message="La date saisie est vide ou incorrecte (%s)"|args:$_POST.date}} + {{/if}} + {{if $new_date|strtotime > $now}} + {{:error message="Impossible de saisir une date dans le futur (%s)"|args:$_POST.date}} + {{/if}} + + {{* préparer le nouveau mouvement *}} + {{:assign var="mvt_new.key" value=""|uuid}} + {{:assign var="mvt_new.direction" value="input"}} + {{:assign var="mvt_new.date" value=$new_date}} + {{:assign var="mvt_new.operation" value=$_POST.operation}} + {{:assign var="mvt_new.amount" value=$_POST.amount}} + {{:assign var="type_mvt" from="config.%s_nature.%s.type"|args:$mvt_new.direction:$mvt_new.operation}} + + {{* + lister les mouvements + - insérer le nouveau mvt à sa place par date croissante + *}} + {{:assign insere=false}} + {{#load + where=" + $$.type = 'movement' + AND + $$.equipment = :eqpmt_key" + :eqpmt_key=$equipment.key + order="$$.date" + assign="movement" + }} + {{if ! $insere}} + {{if $mvt_new.date < $date}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.date == $date}} + {{if $mvt_new.direction == "input" && $type_mvt != "retour"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{elseif $mvt_new.direction == "output" && $type_mvt == "temporaire"}} + {{:assign var="movements_new." from=mvt_new}} + {{:assign insere=true}} + {{/if}} + {{/if}} + {{/if}} + {{:assign var="movements_new." from=movement}} + {{/load}} + {{if ! $insere}} + {{:assign var="movements_new." from=mvt_new}} + {{/if}} + + {{* Vérifier la cohérence des mouvements du matériel *}} + {{:include + file="./_validate_modification.html" + keep="erreur, pb" + movements=$movements_new + }} + {{if $erreur}} + {{:assign message="Impossible d'enregistrer ce mouvement."}} + {{if $pb.mvt.key != $mvt_new.key}} + {{:assign var="err_mvt_label" from="config.input_nature.%s.label"|args:$pb.mvt.operation}} + {{:assign date_pb=$pb.mvt.date|date_short}} + {{:assign var=message2 value=" Mouvement incompatible avec « %s » : « %s (qté : %s) en date du %s »."|args:$err_mvt_label:$equipment.name:$pb.mvt.amount:$date_pb}} + {{:assign message=$message|cat:$message2}} + {{/if}} + {{:error message=$message}} + {{/if}} + + {{* calculer la nouvelle quantité du matériel *}} + {{:assign var="type_mvt" from="config.input_nature.%s.type"|args:$_POST.operation}} + {{:assign var="equipment.out" value="%d-%d"|math:$equipment.out:$_POST.amount|intval}} + + {{:save + key=$equipment.key + validate_schema="../equipment.schema.json" + type="equipment" + category=$equipment.category + name=$equipment.name + status="available" + stock=$equipment.stock + out=$equipment.out + notowned=$equipment.notowned + }} + + {{* enregistrer le mouvement modifié *}} + {{:assign mvt_key=""|uuid}} + {{:save + key=$mvt_key + validate_schema="movement.schema.json" + type="movement" + direction="input" + operation=$_POST.operation + amount=$_POST.amount|intval + equipment=$equipment.key + date=$new_date + comment=$_POST.comment|trim + user=$mvt_new.user + storage=$_POST.storage + }} + + {{* enregistrer la liaison entre le retour et la sortie temporaire *}} + {{:save + key=""|uuid + validate_schema="link.schema.json" + type="link" + direction="output" + temp_key=$_GET.key + return=$mvt_key + }} + + {{* Enregistrer le retour (status passe à "archivée") dans la réservation *}} + {{if $_POST.resa_key}} + {{:save + key=$_POST.resa_key + validate_schema="../reservation.schema.json" + type="reservation" + comment=$_POST.comment|trim + return_date=$new_date + status="archivée" + mvt_key=$mvt_key + }} + {{/if}} + + {{if $_GET.user == null}} + {{:redirect force="../equipment_history.html?ok=1&key=%s&prop=1&msg=retour"|args:$mvt_new.equipment}} + {{else}} + {{:redirect force="/admin/users/details.php?id=%s"|args:$_GET.user}} + {{/if}} +{{/form}} + +{{:admin_header title="Retour de matériel" custom_css="../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="entrees"}} +{{/if}} + +{{* + -------------------- Préparer la saisie -------------------- +*}} + +{{#foreach from=$config.input_nature key=key}} + {{if $type == "retour"}} + {{:assign var="return_label.%s"|args:$key value=$label}} + {{:break}} + {{/if}} +{{/foreach}} + +{{* infos de la catégorie *}} +{{#load key=$equipment.category assign="category"}}{{/load}} + +{{* infos du lieu de stockage *}} +{{#load type="storage" order="$$.name"}} + {{:assign var="storage.%s"|args:$key value=$name}} +{{/load}} + +{{* Charge la réservation si présente *}} +{{if $_GET.reskey}} + {{#load key=$_GET.reskey assign="resa"}}{{/load}} +{{else}} + {{* Cherche une réservation en cours sur ce matériezl *}} + {{#load type="reservation" equipment=$equipment.key status="en cours" assign="resa"}}{{/load}} + {{:debug resa=$resa}} +{{/if}} + +
+
+ Matériel +
+
Désignation
+
{{$equipment.name}}
+
Catégorie
+
{{$category.name}}
+
Quantité disponible
+
{{$exterieur}}
+
+
+
+ Informations obligatoires +
+ {{:input type="date" name="date" label="Date" required=true default=$now|date_short}} + {{:input type="number" name="amount" label="Quantité" min=1 max=$exterieur required=true default=1}} + {{:input type="select" name="operation" label="Type de mouvement" required=true options=$return_label}} +
+
+
+ Autres informations +
+ {{if $storage != null}} + {{:input type="select" name="storage" label="Lieu de stockage" default_empty="— Aucun —" options=$storage required=false}} + {{/if}} + {{:input type="textarea" name="comment" label="Remarques" cols="40" rows="3" required=false}} + +
+
+ +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+ +{{:admin_footer}} diff --git a/public.html b/public.html new file mode 100644 index 0000000..3dda2b5 --- /dev/null +++ b/public.html @@ -0,0 +1,7 @@ +{{:debug}} +{{:assign var="custom_css." value="./style.css"}} +{{:assign var="custom_css." value="/content.css"}} +{{if !$logged_user}} + {{:assign layout="public"}} +{{/if}} +{{*:admin_header title="Gestion des réservations de matériel" custom_css=$custom_css layout=$layout current="module_%s"|args:$module.name*}} \ No newline at end of file diff --git a/resa_history.html b/resa_history.html new file mode 100644 index 0000000..9476937 --- /dev/null +++ b/resa_history.html @@ -0,0 +1,215 @@ +{{* -*- brindille -*- *}} +{{* + Paramètres : + - $_GET.output_type : "resa" affichage en mode liste ou "resacal" en mode calendrier ou "resadel" en mode suppression (seulement admin) + - $_GET.st_key : filtre par status (-1 tous, 0 en attente, 1 acceptée, 2 refusée, 3 archivée, 4 supprimée) +*}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{if $_GET.output_type == "resa" || $_GET.output_type == "resacal" || $_GET.output_type == "resadel"}} + {{:assign label="réservation"}} +{{else}} + {{:error message="Cette page n'existe pas !"}} +{{/if}} + +{{:admin_header title="%ss en cours"|args:$label|ucfirst custom_css="./style.css" current="module_%s"|args:$module.name}} +{{if $_GET.output_type == "resacal"}} + {{:include file="./_nav.html" current="%s"|args:$label subcurrent="calendrier"}} +{{elseif $_GET.output_type == "resadel"}} + {{:include file="./_nav.html" current="%s"|args:$label subcurrent="suppression"}} + {{*:include file="./reservation/delete_reservation.html" current="%s"|args:$label subcurrent="suppression" keep="_GET.output_type,_GET.st_key"*}} +{{else}} + {{:include file="./_nav.html" current="%s"|args:$label subcurrent="encours"}} +{{/if}} + +{{* lecture config *}} +{{:include file="./_get_config.html" keep="config"}} + +{{* filtrer selon le status de la réservation *}} +{{*:assign saved_filters=$module.config.states*}} +{{:assign saved_filters="en attente,acceptée,refusée,en cours,archivée,supprimée"|explode:","}} +{{*:assign var="user_filters" from="saved_filters.%s"|args:$logged_user.id*}} + +{{if $_GET.st_key == null}} + {{*:assign var="selected_status" from="user_filters.%s_hist_st_key"|args:$_GET.output_type*}} + {{:assign selected_status=null}} +{{else}} + {{if $_GET.st_key == -1}} + {{:assign selected_status=""}} + {{else}} + {{:assign selected_status=$_GET.st_key}} + {{/if}} + {{*:assign var="user_filters.%s_hist_st_key"|args:$_GET.output_type value=$selected_status*}} + {{*:assign var="saved_filters.%s"|args:$logged_user.id value=$user_filters*}} + {{*:save key="config" filters=$saved_filters*}} +{{/if}} + +{{* condition de filtrage WHERE *}} +{{if $selected_status != null}} + {{:assign var=_st_value from="saved_filters.%d"|args:$_GET.st_key}} + {{if $_GET.st_key == 0}} + {{:assign st_condition="WHERE (w_status = '%s' AND e_status IS NULL)"|args:$_st_value}} + {{:assign st_condition_cal="$$.status = '%s'"|args:$_st_value}} + {{elseif $_GET.st_key > 0}} + {{:assign st_condition="WHERE (e_status = '%s')"|args:$_st_value}} + {{:assign st_condition_cal="$$.status = '%s'"|args:$_st_value}} + {{/if}} +{{else}} + {{:assign st_condition="WHERE 1 = 1"}} + {{:assign st_condition_cal="1"}} +{{/if}} + +{{* sélecteur de status *}} +{{:assign var="st_options." value="" label="Tous les status" href="?output_type=%s&st_key=-1"|args:$_GET.output_type}} +{{#foreach from=$saved_filters key="key" item="value"}} + {{:assign var="st_options." value=$key|strval label=$value href="?output_type=%s&st_key=%s"|args:$_GET.output_type:$key}} +{{/foreach}} +{{*:debug st_options=$st_options saved_filters=$saved_filters selected_status=$selected_status st_condition=$st_condition st_condition_cal=$st_condition_cal user_filters=$user_filters logged_user=$logged_user.id _st_value=$_st_value*}} + +
+

Inventaire des réservations effectuées

+
+ +
+ Filtrer par status + {{:dropdown + title="Filtrer par status" + options=$st_options + value="%s"|args:$selected_status|strval + }} +
+ +{{* ------------------ Affichage en mode liste : suppression ----------------- *}} +{{if $_GET.output_type == "resadel" || $_POST.ids}} + {{:include file="./reservation/delete_reservation.html" current="%s"|args:$label subcurrent="suppression"}} +{{/if}} + +{{* ------------------ Affichage en mode liste : traitement ----------------- *}} +{{if $_GET.output_type == "resa"}} +

Légende :
+ {{:icon shape="globe"}} : réservation issue de la page publique
+ {{:icon shape="print"}} : réservation issue de la page membre
+ {{:icon shape="alert"}} : signature du contrat requise lors du retrait du matériel +

+ {{* Liste des réservations *}} + {{:include file="_resa_load.html" keep="_resa_lignes"}} + {{*:debug lignes=$_resa_lignes*}} + + + + + + + + + + + + + + + + + + {{#foreach from=$_resa_lignes}} + + + + + + {{#load key="%s"|args:$equipment}}{{:assign var="equipment.name" value=$name}}{{/load}} + + + + + {{else}} + {{$return_date|date_short}} + {{/if}} + + + + + {{/foreach}} + +
N° de membreNomTéléphoneMatérielQuantité souhaitéeDate souhaitéeRetour prévu/réelCommentaire additionnelStatut de la demande
{{:icon shape="%s"|args:$shape}} {{if !$signed}} {{:icon shape="alert"}}{{/if}}{{$member}}{{$name}}{{$contact}}{{$equipment.name}}{{$amount}}{{* Si acceptée et date de retrait aujourd'hui *}} + {{if $status == "acceptée" && $loan_date|parse_date == $now|date:'Y-m-d'}} + {{$loan_date|date_short}} + {{else}} + {{$loan_date|date_short}} + {{/if}} + {{* Si an cours et date de retour aujourd'hui *}} + {{if $status == "en cours" && $return_date|parse_date == $now|date:'Y-m-d'}} + {{$return_date|date_short}}{{$comment}}{{:include file="./_resa_status_color.html" status='%s'|args:$status|or:null}} + {{if $status == "acceptée" || $status == "refusée"}} + {{* Ne pas permettre d'archiver des réservations au status acceptée/refusée si la date n'est pas passée *}} + {{if $return_date|parse_date < $now|date:'Y-m-d'}} + {{:linkbutton label="Archiver" href="reservation/resa_details.html?key=%s"|args:$wres_key shape="lock"}} + {{else}} + {{:linkbutton label="Détails" href="reservation/resa_details.html?key=%s"|args:$wres_key shape="eye"}} + {{/if}} + {{elseif $status == "en cours"}} + {{:linkbutton label="Détails" href="reservation/resa_details.html?key=%s"|args:$wres_key shape="eye"}} + {{elseif $status == "archivée"}} + {{:linkbutton label="Détails" href="reservation/resa_details.html?key=%s"|args:$wres_key shape="eye"}} + {{elseif $status == null}} + {{else}} + {{:linkbutton label="Traiter" href="reservation/resa_details.html?key=%s"|args:$wres_key shape="edit"}} + {{/if}} +
+{{/if}} + +{{* ------------------ Affichage en mode Calendrier ----------------- *}} +{{if $_GET.output_type == "resacal"}} + {{:include file="./_web_calendar.html"}} + {{* Charge les réservations dans le calendrier *}} + {{:include file="_resa_load.html" keep="_resa_lignes"}} + {{#foreach from=$_resa_lignes}} + {{*#load key="%s"|args:$equipment assign="_equi"}}{{:debug equi=$_equi.name}}{{/load}} + {{:assign var="equipment_resa" value=null*}} + {{#load key="%s"|args:$equipment}}{{:assign var="equipment.name" value=$name}}{{/load}} + {{:include file="_resa_status_color.html" color_only=true keep="_tag_color,_text_color"}} + {{:assign var="_title" value="%s %s (%s)"|args:$equipment.name:$name:$status}} + {{* Voir https://fullcalendar.io/docs/event-parsing + This value is exclusive. For example, if you have an all-day event that has an end of 2018-09-03, + then it will span through 2018-09-02 and end before the start of 2018-09-03 + *}} + {{:assign _return=$return_date|parse_date|strtotime}} + {{:assign _return_timestamp="(%d+86400)"|math:$_return}} + {{:assign _return_date="%s"|args:$_return_timestamp|date:'Y-m-d'}} + {{*:debug _return_timestamp=$_return_timestamp _return_date=$_return_date*}} + {{:assign var="_events" value="%s{title: '%s', start: '%s', end: '%s', backgroundColor:'%s', textColor:'%s', url:'reservation/resa_details.html?key=%s&output_type=%s'},"|args:$_events:$_title:$loan_date:$_return_date:$_tag_color:$_text_color:$wres_key:$_GET.output_type}} + {{/foreach}} + {{*:debug _events=$_events*}} + + +
+ Calendrier des réservations +
+
+{{/if}} + +{{:admin_footer}} \ No newline at end of file diff --git a/reservation.html b/reservation.html new file mode 100644 index 0000000..31e1083 --- /dev/null +++ b/reservation.html @@ -0,0 +1,13 @@ +{{if !$_GET.fonc}} + +{{elseif $_GET.fonc=="voir"}} + {{:include file="./_web_view.html" parent=$page.path}} +{{elseif $_GET.fonc=="resa"}} + {{:include file="./_web_resa.html" parent=$page.path}} +{{elseif $_GET.fonc=="confirm_resa"}} + {{if $_GET.ok}} + {{:include file="./_web_contract.html" parent=$page.path}} + {{/if}} +{{elseif $_GET.fonc=="save_resa"}} + {{:include file="./_web_saved_resa.html" parent=$page.path}} +{{/if}} \ No newline at end of file diff --git a/reservation.schema.json b/reservation.schema.json new file mode 100644 index 0000000..f16ac78 --- /dev/null +++ b/reservation.schema.json @@ -0,0 +1,76 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["reservation"] + }, + "member": { + "description": "N° membre", + "type": ["integer", "null"] + }, + "name": { + "description": "Nom & Prénom", + "type": "string" + }, + "contact": { + "description": "Téléphone", + "type": ["null", "string"] + }, + "email": { + "description": "Courriel", + "type": "string" + }, + "address": { + "description": "Adresse postale", + "type": ["null", "string"] + }, + "equipment" : { + "description": "Clé du matériel", + "type": "string" + }, + "amount" : { + "description": "Quantité souhaitée", + "type": "integer" + }, + "date" : { + "description": "Date de la réservation", + "type": "string", + "format": "date" + }, + "loan_date" : { + "description": "Date souhaitée", + "type": "string", + "format": "date" + }, + "return_date" : { + "description": "Retour prévu/réel", + "type" : "string", + "format" : "date" + }, + "comment": { + "description": "Commentaire additionnel", + "type": ["null", "string"] + }, + "secret": { + "description": "Mot de passe pour modification ou annulation", + "type": ["null", "string"] + }, + "status": { + "description": "Statut de la demande", + "type": ["string"], + "enum": ["en attente", "acceptée", "refusée", "en cours", "archivée"], + "default": "en attente" + }, + "signed": { + "description": "Signature de l'emprunteur", + "type": ["null", "string"] + }, + "mvt_key": { + "description": "Clé du mouvement associé", + "type": ["null", "string"] + } + }, + "required": ["type", "name", "contact", "equipment", "amount", "date", "loan_date", "return_date"] +} \ No newline at end of file diff --git a/reservation/accept_reservation.html b/reservation/accept_reservation.html new file mode 100644 index 0000000..4c085f5 --- /dev/null +++ b/reservation/accept_reservation.html @@ -0,0 +1,91 @@ +{{* -*- brindille -*- *}} +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Accepter une réservation + paramètres : + - key : clé de la réservation à modifier + - eid : id du matériel concerné +*}} +{{if $_GET.ok}} + {{* Redirect vers la page de suppression de la réservation WEB *}} + {{:redirect url="/equipment.html?fonc=resadel&key=%s"|args:$_GET.ok}} + {{*:redirect reload="resa_details.html?key=%s"|args:$resa.key*}} +{{/if}} +{{* récupérer les infos de la réservation à modifier depuis le module equipement (prioritaire) ou depuis le module web *}} +{{#load key=$_GET.key assign="resa"}} +{{else}} + {{#load module=web key=$_GET.key assign="resa"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$_GET.key}} + {{/load}} +{{/load}} + +{{#module name="equipment"}} + {{* Récupère le membre si présent *}} + {{if $resa.member >= 1}} + {{#users id=$resa.member}} + {{:assign var="_rep_name" value=$_name}} + {{/users}} + {{else}} + {{* Récupère la personne non membre *}} + {{:assign var="_rep_name" value=$resa.name}} + {{:assign var="_non_member" value=true}} + {{/if}} +{{else}} + Le module Équipement est désactivé. +{{/module}} +{{:admin_header title="Accepter la réservation" current="module_%s"|args:$module.name}} +{{* + -------------------- Traiter la demande de réservation -------------------- +*}} +{{if $_POST.resa_key}} + {{#form on="save"}} + + {{:save key=$_POST.resa_key + type="reservation" + status="acceptée" + comment=$_POST.comment|trim + equipment=$_POST.equi_key|trim + }} + + {{* + -------------------- Envoyer un mail de confirmation -------------------- + *}} + {{*:assign var="recipients[]" value="recyclarz@free.fr"*}} + {{if $resa.email|check_email}} + {{:assign var="recipients[]" value=$resa.email}} + {{else}} +

L'adresse e-mail indiquée est invalide.

+ {{/if}} + {{:mail to=$recipients subject="[Recycl'arz] Votre réservation de matériel" body="Bonjour %s,\n Votre réservation a été acceptée avec cette consigne: %s\n Cordialement\n L'équipe Recycl'arz"|args:$resa.name:$_POST.comment notification=true}} +

Réservation acceptée : un email a été envoyé automatiquement à : {{$resa.name}} / {{$resa.email}}. Cliquer {{:link href="accept_reservation.html?ok=%s"|args:$resa.key label="ici"}} pour terminer.

+ {{if $_non_member ==true }} +

Veuillez maintenant créer ce membre.

+ {{/if}} + {{:form_errors}} + {{:break}} + {{/form}} +{{else}} + + {{* récupérer les infos du matériel associé *}} + {{#load key=$resa.equipment assign="equipment"}} + {{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$resa.equipment}} + {{/load}} + + {{* -------------------- Formulaire acceptation réservation matériel -------------------- *}} +
+
+ pour ce matériel : {{$equipment.name}} ({{$category.name}}) +
+ {{:input type="textarea" cols=40 rows=2 name="comment" label="Consigne" default="Contacter l'asso pour récupérer le matériel !" required=true}} + {{:input type="hidden" name="resa_key" required=true default=$resa.key readonly=true}} + {{:input type="hidden" name="equi_key" required=true default=$equipment.key readonly=true}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{/if}} \ No newline at end of file diff --git a/reservation/archive_reservation.html b/reservation/archive_reservation.html new file mode 100644 index 0000000..ca09b50 --- /dev/null +++ b/reservation/archive_reservation.html @@ -0,0 +1,38 @@ +{{* -*- brindille -*- *}} +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Accepter une réservation + paramètres : + - key : clé de la réservation à modifier + - eid : id du matériel concerné +*}} +{{if $_GET.ok}} + {{* Redirect vers la page de suppression de la réservation WEB *}} + {{:redirect url="/equipment.html?fonc=resadel&key=%s"|args:$_GET.ok}} + {{*:redirect reload="resa_details.html?key=%s"|args:$resa.key*}} +{{/if}} + +{{* récupérer les infos de la réservation à modifier depuis le module equipement (prioritaire) ou depuis le module web *}} +{{#load key=$_GET.key assign="resa"}} +{{else}} + {{#load module=web key=$_GET.key assign="resa"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$_GET.key}} + {{/load}} +{{/load}} + +{{:admin_header title="Archiver la réservation" current="module_%s"|args:$module.name}} +{{* + -------------------- Archiver la demande de réservation -------------------- +*}} +{{if $resa.key}} + {{:save key=$resa.key + type="reservation" + status="archivée" + equipment_id=$_GET.eid|intval + }} +

La réservation est maintenant archivée. Cliquer {{:link href="archive_reservation.html?ok=%s"|args:$resa.key label="ici"}} pour terminer.

+{{else}} +

Erreur : La réservation n'a pas pu être archivée.

+{{/if}} \ No newline at end of file diff --git a/reservation/decline_reservation.html b/reservation/decline_reservation.html new file mode 100644 index 0000000..ea86c1b --- /dev/null +++ b/reservation/decline_reservation.html @@ -0,0 +1,102 @@ +{{* -*- brindille -*- *}} +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Décliner une réservation + paramètres : + - key : clé de la réservation à modifier + - eid : id du matériel concerné +*}} +{{if $_GET.ok}} + {{* Redirect vers la page de suppression de la réservation WEB *}} + {{:redirect url="/equipment.html?fonc=resadel&key=%s"|args:$_GET.ok}} + {{*:redirect reload="resa_details.html?key=%s"|args:$resa.key*}} +{{/if}} + +{{* récupérer les infos de la réservation à modifier depuis le module equipement (prioritaire) ou depuis le module web *}} +{{#load key=$_GET.key assign="resa"}} +{{else}} + {{#load module=web key=$_GET.key assign="resa"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$_GET.key}} + {{/load}} +{{/load}} + +{{#module name="equipment"}} + {{* Récupère le membre si présent *}} + {{if $resa.member >= 1}} + {{#users id=$resa.member}} + {{:assign var="_rep_name" value=$_name}} + {{/users}} + {{else}} + {{* Récupère la personne non membre *}} + {{:assign var="_rep_name" value=$resa.name}} + {{:assign var="_non_member" value=true}} + {{/if}} +{{else}} + Le module Équipement est désactivé. +{{/module}} +{{:admin_header title="Refuser la réservation" current="module_%s"|args:$module.name}} +{{* + -------------------- Traiter la demande de réservation -------------------- +*}} +{{if $_POST.resa_key}} + {{#form on="save"}} + {{* Refus *}} + {{:save key=$_POST.resa_key + type="reservation" + status="refusée" + comment=$_POST.comment|trim + equipment=$_POST.equi_key|trim + }} + + {{* + -------------------- Envoyer un mail de confirmation -------------------- + *}} + {{*:assign var="recipients[]" value="recyclarz@free.fr"*}} + {{if $resa.email|check_email}} + {{:assign var="recipients[]" value=$resa.email}} + {{else}} +

L'adresse e-mail indiquée est invalide.

+ {{/if}} + {{:mail to=$recipients subject="[Recycl'arz] Votre réservation de matériel" body="Bonjour %s,\n Votre réservation a été refusée pour cette raison : %s\n Cordialement\n L'équipe Recycl'arz"|args:$resa.name:$_POST.comment notification=true}} +

Réservation refusée : un email a été envoyé automatiquement à : {{$resa.name}} / {{$resa.email}}. Cliquer {{:link href="decline_reservation.html?ok=%s"|args:$resa.key label="ici"}} pour terminer.

+ {{if $_non_member ==true }} +

Veuillez maintenant créer ce membre.

+ {{/if}} + {{:form_errors}} + {{:break}} + {{/form}} +{{else}} + + {{* récupérer la config des entrées/sorties + {{:include file="../_get_config.html" keep="config, directions"}} + *}} + {{* infos pour affichage + {{:assign var="op_label" from="config.%s_nature.%s.label"|args:$mvt_new.direction:$mvt_new.operation}} + {{:assign amount_init=$mvt_new.amount}} + {{:assign operation_init=$mvt_new.operation}} + {{:assign date_init=$mvt_new.date|date_short}} + {{:assign eqpmt_key=$mvt_new.equipment}} + *}} + {{* récupérer les infos du matériel associé *}} + {{#load key=$resa.equipment assign="equipment"}} + {{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$resa.equipment}} + {{/load}} + + {{* -------------------- Formulaire refus réservation matériel -------------------- *}} +
+
+ pour ce matériel : {{$equipment.name}} ({{$category.name}}) +
+ {{:input type="textarea" cols=40 rows=2 name="comment" label="Motif du refus" required=true}} + {{:input type="hidden" name="resa_key" required=true default=$resa.key readonly=true}} + {{:input type="hidden" name="equi_key" required=true default=$equipment.key readonly=true}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+{{/if}} \ No newline at end of file diff --git a/reservation/delete_reservation.html b/reservation/delete_reservation.html new file mode 100644 index 0000000..11d618d --- /dev/null +++ b/reservation/delete_reservation.html @@ -0,0 +1,119 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="admin"}}{{/restrict}} + +{{* + Supprime les réservations selectionnées du module EQUIPMENT et WEB (link externe) + paramètres : + - keys : Clefs des réservations à supprimer +*}} +
+

Légende :
+ {{:icon shape="globe"}} : réservation issue de la page publique
+ {{:icon shape="print"}} : réservation issue de la page membre
+

+

{{:icon shape="alert"}} : Il n'y a pas de confirmation lors de la suppression de réservations !

+
+{{* Suppression des résa sélectionnées dans le module EQUIPMENT uniquement *}} +{{*:debug _POST=$_POST*}} +{{if $_POST.ids}} + {{*:admin_header title="Supprimer réservation(s)" current="module_%s"|args:$module.name layout="public"*}} + {{:assign var="keys" value=$_POST.ids|implode:","}} + {{*#form on="delete"*}} + {{*#foreach from=$_POST.ids key="key" item="value"}} + {{$key}} = {{$value}} + {{:delete key=$value}} + {{/foreach*}} + {{*if !$_POST.confirm_delete}} + {{:error message="Merci de cocher la case"}} + {{/if*}} + {{:delete :keys=$keys where="key IN (:keys)"}} + {{:redirect parent="./resa_history.html?output_type=resadel&ok=1"}} + {{*/form}} + {{:form_errors*}} + + {{*:delete_form + legend="Suppression de réservation" + warning="Supprimer la/les réservation(s) n°%s ?"|args:$keys + info="La réservation lié sera également supprimé" + alert="La réservation sera définitivement perdue !" + confirm="Cocher cette case pour confirmer la suppression de la réservation" + *}} + {{*:redirect reload="./resa_history.html?output_type=resadel"*}} + + {{*:debug _POST=$_POST.ids|implode:","*}} + {{*:debug keys=$keys*}} + +{{* Confirmation et suppression de la résa dans le module equipement uniquement +{{elseif $_GET.key || $_POST.key}} + {{:admin_header title="Suppression de réservation" current="module_%s"|args:$module.name}} +

Confirmer la suppression ?

+ {{#form on="save"}} + {{* vérifier la confirmation }} + {{if !$_POST.confirm || $_POST.confirm|intval != 1}} + {{:error message="Merci de confirmer la suppression !"}} + {{elseif $_POST.key}} + {{:delete key=$_POST.key}} + {{else}} + {{:error message="Jamais !"}} + {{/if}} + {{:redirect reload="./delete_reservation.html"}} + {{/form}} + {{:form_errors}} +
+ {{:input type="hidden" name="key" default=$_GET.key}} + {{:input type="radio-btn" name="confirm" value="0" label="Non" default="0" required=true}} + {{:input type="radio-btn" name="confirm" value="1" label="Oui" required=true}} +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+*}} +{{else}} +{{* Liste des réservations *}} + {{:include file="../_resa_load.html" keep="_resa_lignes"}} +
{{*data-disable-progress="1"*}} + + + + + + + + + + + + + + + + + + {{#foreach from=$_resa_lignes}} + + + + + + + + + + + + + + {{/foreach}} +
SourceN° de membreNomTéléphoneMatérielQuantité souhaitéeDate souhaitéeDate retour prévueCommentaire additionnelStatut de la demande
{{if $shape=="print"}} + {{:input name="ids[]" type="checkbox" value='%s'|args:$wres_key}} + {{else}} + {{*:linkbutton href="/equipment.html?fonc=resadel&id=%s"|args:$wres_id label="" target="_dialog" shape="delete"*}} + {{:linkbutton href="/equipment.html?fonc=resadel&key=%s"|args:$wres_key label="" target="_dialog" shape="trash"}} + {{/if}} + {{:icon shape="%s"|args:$shape}}{{$member}}{{$name}}{{$contact}}{{#load key="%s"|args:$equipment}}{{$name}}{{/load}}{{$amount}}{{$loan_date|date_short}}{{$return_date|date_short}}{{$comment}}{{:include file="../_resa_status_color.html" status='%s'|args:$status|or:null}}
+

+ {{:button type="submit" name="delete" label="Supprimer" shape="right" class="main"}} +

+
+{{/if}} \ No newline at end of file diff --git a/reservation/resa_contract.html b/reservation/resa_contract.html new file mode 100644 index 0000000..597f446 --- /dev/null +++ b/reservation/resa_contract.html @@ -0,0 +1,11 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} +{{* Retourne à la page parente en fermant la fenêtre dialog *}} +{{if $_GET.key}} + {{:redirect reload="./resa_details.html?key=%s"|args:$_GET.key}} +{{/if}} +{{* + Afficher le contrat d'une réservation dans le but de le signer et le télécharger +*}} +{{:include file="../_web_contract.html" rid=$_GET.rid}} \ No newline at end of file diff --git a/reservation/resa_details.html b/reservation/resa_details.html new file mode 100644 index 0000000..1d055a5 --- /dev/null +++ b/reservation/resa_details.html @@ -0,0 +1,195 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Afficher les détails d'une réservation et donner la possibilité : + - d'accepter, de refuser ou d'archiver + paramètres : + - key : clé du mouvement + - prop = 1 si matériel appartient à l'asso + - from = page d'appel +*}} + +{{* Traiter l'envoi du formulaire (associer une résa à un membre) *}} +{{#form on="save"}} + + {{* Récupérer les infos de la réservation depuis le module web uniquement *}} + {{#load module=web key=$_POST.key assign="resa"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$_POST.key}} + {{/load}} + {{#foreach from=$_POST.user key="id" item="name"}} + {{:assign var="user.id" value=$id}} + {{:assign var="user.name" value=$name}} + {{/foreach}} + {{* Enregistrer la réservation dans le module equipment *}} + {{:save assign_new_id="rid" + key=$_POST.key + validate_schema="../reservation.schema.json" + type="reservation" + member=$user.id|intval|or:null + name=$resa.name|trim + contact=$resa.contact|trim + email=$resa.email|trim + address=$resa.address|trim|or:null + equipment=$_POST.equipment_key|trim + date=$resa.date|date_short|parse_date + loan_date=$resa.loan_date|parse_date + return_date=$resa.return_date|parse_date + amount=$resa.amount|intval + comment=$resa.comment|trim|or:null + secret=$resa.secret|trim|or:null + status=$resa.status|trim|or:null + }} + {{:redirect force="resa_details.html?ok=1&msg=modification&key=%s"|args:$_POST.key}} +{{/form}} + +{{:admin_header title="Détails d'une réservation" custom_css="../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{:include file="../_nav.html" current="réservation" subcurrent="encours"}} +
+

Détails d'une réservation

+

Légende :
+ {{:icon shape="globe"}} : réservation issue de la page publique
+ {{:icon shape="print"}} : réservation issue de la page membre
+ {{:icon shape="alert"}} : signature du contrat requise lors du retrait du matériel +

+
+ +{{* récupérer les infos de la réservation depuis le module equipement (prioritaire) ou depuis le module web *}} +{{#load key=$_GET.key assign="resa"}} + {{:assign var="resa.source" value="print"}} + {{* Calcul du nb de jours sortis restant *}} + {{if $resa.return_date != null}} + {{:assign ts_retour=$resa.return_date|strtotime}} + {{:assign nb_jours="floor((%d-%d)/(60*60*24))"|math:$now:$ts_retour}} + {{/if}} +{{else}} + {{#load module=web key=$_GET.key assign="resa"}} + {{:assign var="resa.source" value="globe"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$_GET.key}} + {{/load}} +{{/load}} + +{{* récupérer les autres infos (équipement/catégorie) associées à cette réservation *}} +{{#load key=$resa.equipment assign="equipment"}} +{{else}} + {{:error message="Aucun matériel avec la clé « %s »"|args:$resa.equipment}} +{{/load}} +{{#load key=$equipment.category assign="category"}}{{/load}} +{{* récupérer le status de la réservation dans le module equipment *}} +{{#load key=$resa.key assign="equipment_resa"}}{{/load}} +{{*:debug resa=$resa*}} +{{* + -------------------- Afficher les informations de la réservation -------------------- +*}} +{{if !$resa.member}} +
+

{{:icon shape="alert"}} Vous devez sélectionner ou créer un membre avant de pouvoir traiter cette réservation

+
+{{/if}} + + +
+
Source
{{:icon shape="%s"|args:$resa.source}}
+
Status
+ {{:include file="../_resa_status_color.html" status='%s'|args:$equipment_resa.status|or:null}} +
Nom
{{$resa.name}}
+
Contact
{{$resa.contact}}
+
Courriel
{{$resa.email}}
+
Adresse postale
{{$resa.address}}
+
Matériel
{{:link href="../equipment_history.html?key=%s&prop=%s"|args:$equipment.key:$_GET.prop label=$equipment.name}}
+
Catégorie
{{:link href="../index.html?cat_key=%s&prop=1"|args:$category.key label=$category.name}}
+
Date de la demande
{{$resa.date|date_short}}
+
Quantité
{{$resa.amount}}
+
Membre associé
+
{{if $resa.member >= 1}} + {{:link href="/admin/users/details.php?id=%s"|args:$resa.member label="Voir la fiche de %s"|args:$resa.name target="_dialog"}} + {{else}} +
+ {{:input name="key" type="hidden" default=$resa.key}} + {{:input name="equipment_key" type="hidden" default=$equipment.key}} + {{:input type="list" name="user" required=true target="!users/selector.php" multiple=false can_delete=true help="Associer cette réservation à un membre"}} + {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +
+ {{:linkbutton href="!users/new.php" label="Créer un nouveau membre" target="_dialog" shape="plus"}} + {{/if}} +
+
Date souhaitée
+ {{$resa.loan_date|date_short}} + {{if $resa.loan_date|parse_date == $now|date:'Y-m-d'}} + {{:tag color="darkgreen" label="À retirer aujourd'hui"}} + {{/if}} +
+
Retour prévu/réel
+ {{$resa.return_date|date_short}} + {{:assign jour="jour"}} + {{if $equipment_resa.status == "en cours"}} + {{if $nb_jours > 0}} + {{if $nb_jours > 1}}{{:assign jour="jours"}}{{/if}} + {{:tag color="darkred" label="Retard %s %s"|args:$nb_jours:$jour}} + {{elseif $nb_jours < 0}} + {{:assign delai="abs(%d)"|math:$nb_jours}} + {{if $nb_jours < -1}}{{:assign jour="jours"}}{{/if}} + {{:tag color="lightgreen" label="Reste %s %s"|args:$delai:$jour}} + {{else}} + {{:tag color="darkgreen" label="À rendre aujourd'hui"}} + {{/if}} + {{/if}} +
+
Signature contrat
{{if $resa.signed != null}}{{$resa.signed}}{{else}}{{:icon shape="alert"}} À faire au retrait!{{/if}}
+
Remarques
+
{{if $resa.comment != null}}{{$resa.comment}}{{else}}—{{/if}}
+
+{{if $_GET.output_type}} + {{:linkbutton href="../resa_history.html?output_type=%s"|args:$_GET.output_type label="Retour" shape="home"}} +{{else}} + {{:linkbutton href="../resa_history.html?output_type=resa" label="Retour" shape="home"}} +{{/if}} + +{{* Fichiers liés à l'équipement *}} +{{:assign var="path" value="public/image-%s"|args:$equipment.key}} +{{:admin_files path=$path upload=false edit=false use_trash=false}} +{{:admin_footer}} \ No newline at end of file diff --git a/reservation/temp_correction.html b/reservation/temp_correction.html new file mode 100644 index 0000000..bc30ef0 --- /dev/null +++ b/reservation/temp_correction.html @@ -0,0 +1,114 @@ + +{{* Maj une réservation *}} +{{*:save + key="621c0fce-ef51-424d-bd3b-a635ced57594" + type="reservation" + loan_date="2026-10-21" + status="en attente" + mvt_key=null +*}} + +{{* Créer une réservation *}} +{{*:save + type="reservation" + member=24 + name="Francois Daniel" + contact="" + email="bountz+fd@gmail.com" + address=null + equipment="0b8799f3-763d-43c6-9a27-2fc90e29282d" + date="2026-10-16" + loan_date="2026-10-21" + return_date="2026-10-22" + amount=1 + comment="Test de refus" + status="en attente" + mvt_key=null +*}} + +{{*:delete key="633b7d6d-cbaa-4e8d-a1d8-7baf388ea0b2"*}} +{{* -*- brindille -*- *}} +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Accepter une réservation + paramètres : + - key : clé de la réservation à modifier + - eid : id du matériel concerné +*}} +{{if $_GET.ok}} + {{* Redirect vers la page de suppression de la réservation WEB *}} + {{*:redirect url="/equipment.html?fonc=resadel&key=%s"|args:$_GET.ok*}} + {{*:redirect reload="resa_details.html?key=%s"|args:$resa.key*}} +{{/if}} +{{* récupérer les infos de la réservation à modifier depuis le module equipement (prioritaire) ou depuis le module web *}} +{{#load key=$_GET.key assign="resa"}} +{{else}} + {{#load module=web key=$_GET.key assign="resa"}} + {{else}} + {{:error message="Aucune réservation avec la clé %s"|args:$_GET.key}} + {{/load}} +{{/load}} +{{* Charge le matériel *}} +{{#load module="equipment" key=$resa.equipment assign="equipment"}} +{{else}} + {{:error message="Pas de matériel avec la clé %s"|args:$equipment_key}} +{{/load}} + +{{#form on="save"}} + {{if $_POST.titre|trim === ''}} + {{:error message="Le titre est vide."}} + {{/if}} + {{* La ligne suivante ne sera pas exécutée si le titre est vide. *}} + {{*:save title=$_POST.titre|trim*}} +{{else}} + {{:form_errors}} +{{/form}} + +{{* formulaire de réservation de matériel *}} +{{:read file="../reservation.schema.json" assign="baremes"}} +{{:assign baremes=$baremes|json_decode}} +{{*:debug baremes=$baremes.properties*}} + +
+
+ Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}}) +
+ {{#foreach from=$resa key="key" item="value"}} + {{:assign required=false}} +
+ {{*:assign var="_resa_lignes." wres_id=$id wres_key=$key member=$member name=$name contact=$contact equipment=$equipment amount=$amount loan_date=$loan_date return_date=$return_date comment=$comment shape="print" signed=$signed status=$status*}} + {{:assign var="titre" from="baremes.properties.%s.description"|args:$key}} + {{:assign var="_type" from="baremes.properties.%s.type"|args:$key}} + {{:assign var="_format" from="baremes.properties.%s.format"|args:$key}} + {{:assign var="_type" value=$_type|arrayval}} + {{if $_type|has:"string"}} + {{if $_format=="date"}} + {{:assign type="date"}} + {{else}} + {{:assign type="text"}} + {{/if}} + {{elseif $_type|has:"integer"}} + {{:assign type="number"}} + {{elseif $_type|has:"array"}} + {{:assign type="select"}} + {{else}} + {{:assign type="text"}} + {{/if}} + {{:assign var="obligatoires" from="baremes.required"}} + {{if $obligatoires|has:$key}}{{:assign required=true}} {{/if}} + {{:assign var="nochangefields" a="id" b="key" c="type"}} + {{if $key|in:$nochangefields}} + {{$key}} = {{$value}} + {{else}} + {{:input type=$type name=$key label=$titre default=$value required=$required}} + {{/if}} + {{*:debug key=$key val=$value*}} +
+ {{/foreach}} +
+
+

+ {{:button type="submit" name="save" label="Étape suivante" shape="right" class="main"}} +

+
\ No newline at end of file diff --git a/scripts.js b/scripts.js new file mode 100644 index 0000000..c913078 --- /dev/null +++ b/scripts.js @@ -0,0 +1,75 @@ +/** + * désactiver le tri des colonnes ayant la classe nosort dans une liste triable + * @param {Node} liste - liste triable + */ +function disableColumSort(liste) { + + // chercher la première ligne du corps de la table + let columns = liste.querySelectorAll("tbody > tr > td"); + + // chercher la ligne de titres + let titles = liste.querySelectorAll("thead > tr > th"); + + // désactiver le tri + for (let i = 0; i < titles.length; ++i) { + let anchor = titles[i].querySelector("a"); + const classAttr = columns[i].getAttribute("class"); + if (anchor != null && classAttr != null && classAttr.includes("nosort")) { + anchor.removeAttribute("href"); + anchor.removeAttribute("title"); + anchor.removeChild(anchor.firstElementChild); + let headerClass = titles[i].getAttribute("class"); + if (headerClass == null) { headerClass = ""; } + headerClass += "nosort"; + titles[i].setAttribute("class", headerClass); + } + } +} + +/** + * renvoyer la valeur en secondes d'une date au format j/m/a + * @param {string} date + */ +function str2sec(date) { + const jma = date.split('/'); + const dd = new Date(jma[2], jma[1]-1, jma[0]); + return dd.getTime()/1000; +} + +// renvoyer la valeur en secondes d'un champ date +function getDate(idelem) { + return str2sec(document.getElementById(idelem).value); +} + +/** + * modifier la date de retour en fonction de la date de sortie et de la durée du prêt + */ +function setReturnDate(id_date, id_return_date, id_loan_duration) +{ + const loan_duration = document.getElementById(id_loan_duration).value; + if (loan_duration !== undefined && loan_duration > 0) { + let nbsec = getDate(id_date) + loan_duration*24*60*60; + const date_retour = new Date(nbsec * 1000); + document.getElementById(id_return_date).value = date_retour.toLocaleDateString(); + } +} + +/** + * changer la visibilité de la date de retour + */ +function toggleVisibility(id_date, id_type, div, id_return_date) +{ + const key = document.getElementById(id_type).value; + let type_sortie; + if (key !== undefined && key != '') { + type_sortie = output_nature[key].type; + } + const div_date = document.getElementById(div); + if (type_sortie == 'temporaire') { + div_date.style.visibility = "visible"; + document.getElementById(id_date).onchange(); + } else { + div_date.style.visibility = "hidden"; + document.getElementById(id_return_date).value = null; + } +} diff --git a/snippets/_details.html b/snippets/_details.html new file mode 100644 index 0000000..85bf26c --- /dev/null +++ b/snippets/_details.html @@ -0,0 +1,253 @@ +{{* -*- brindille -*- *}} + +{{* lecture config (défaut ou enregistrée) *}} +{{:include file="../_get_config.html" keep="config, directions"}} + +{{#foreach from=$directions key="direction"}} + {{:assign var="nature" from="config.%s_nature"|args:$direction}} + {{#foreach from=$nature key=key}} + {{:assign var="types.%s.%s."|args:$direction:$type value=$key|quote_sql}} + {{/foreach}} + {{:assign var="io_types" from="types.%s"|args:$direction}} + {{#foreach from=$io_types key=key}} + {{:assign var=elem from="io_types.%s"|args:$key}} + {{:assign elem=$elem|implode:","}} + {{:assign elem="("|cat:$elem|cat:")"}} + {{:assign var="%s_types.%s"|args:$direction:$key value=$elem}} + {{/foreach}} +{{/foreach}} + +{{* + vérifier l'existence de la table du module + eh oui, il se peut qu'elle ne soit pas encore créée si aucune donnée n'a été ajoutée dedans +*}} +{{#load limit="1"}} + {{:assign table_presente=true}} +{{else}} + {{:assign table_presente=false}} +{{/load}} + +{{if $table_presente}} + {{* Matériels attribués temporairement *}} + {{* vérifier la présence des types d'entrées et de sorties requis *}} + {{if $output_types|has_key:"temporaire" && $input_types|has_key:"retour"}} + + {{* + Calculer les quantités de matériel en prêt + *}} + {{:assign premier=true}} + {{#select + mvt.$$.direction AS direction, + mvt.$$.date AS date, + eqpmt.key as eqpmt_key, + eqpmt.$$.name AS eqpmt_name, + mvt.$$.amount AS qte, + mvt.$$.return_date AS return_date, + mvt.$$.operation AS operation + FROM !table AS mvt + INNER JOIN users ON mvt.$$.user = users.id + INNER JOIN !table AS eqpmt ON mvt.$$.equipment = eqpmt.key + WHERE + users.id = :user + AND + mvt.$$.type = 'movement' + AND + (mvt.$$.operation IN !output_types + OR + mvt.$$.operation IN !input_types) + ORDER BY eqpmt_name, date + ; + !table=$module.table + :user = $user.id + !output_types=$output_types.temporaire + !input_types=$input_types.retour + }} + {{if $premier}} + {{:assign premier=false}} + {{:assign total=0}} + {{:assign nb_jours=0}} + {{:assign old_eqpmt_key=$eqpmt_key}} + {{:assign var="ligne.date" value=$date}} + {{:assign var="ligne.eqpmt_key" value=$eqpmt_key}} + {{:assign var="ligne.materiel" value=$eqpmt_name}} + {{:assign var="ligne.return_date" value=$return_date}} + {{:assign var="ligne.retard" value="0"}} + {{if $return_date != null}} + {{:assign ts_retour=$return_date|strtotime}} + {{:assign nb_jours="floor((%d-%d)/(60*60*24))"|math:$now:$ts_retour}} + {{:assign var="ligne.retard" value=$nb_jours}} + {{/if}} + {{/if}} + + {{if $eqpmt_key != $old_eqpmt_key}} + {{if $total > 0}} + {{:assign var="ligne.qte" value=$total}} + {{:assign var="lignes." value=$ligne}} + {{/if}} + {{:assign total=0}} + {{:assign nb_jours=0}} + {{:assign old_eqpmt_key=$eqpmt_key}} + {{:assign var="ligne.date" value=$date}} + {{:assign var="ligne.eqpmt_key" value=$eqpmt_key}} + {{:assign var="ligne.materiel" value=$eqpmt_name}} + {{:assign var="ligne.return_date" value=$return_date}} + {{:assign var="ligne.retard" value="0"}} + {{if $return_date != null}} + {{:assign ts_retour=$return_date|strtotime}} + {{:assign nb_jours="floor((%d-%d)/(60*60*24))"|math:$now:$ts_retour}} + {{:assign var="ligne.retard" value=$nb_jours}} + {{/if}} + {{/if}} + + {{if $direction == "output"}} + {{:assign total="%d+%d"|math:$total:$qte}} + {{else}} + {{:assign total="%d-%d"|math:$total:$qte}} + {{/if}} + {{/select}} + + {{if $total > 0}} + {{:assign var="ligne.qte" value=$total}} + {{:assign var="lignes." value=$ligne}} + {{/if}} + + {{if $lignes|count > 0}} +

Matériels attribués temporairement

+ + + + + + + + + + + + {{#foreach from=$lignes}} + + + + + + + + + {{/foreach}} + +
DateMatérielQuantitéDate de retourRemarque +
{{$date|date_short}}{{$materiel}}{{$qte}}{{$return_date|date_short}} + {{if $retard < 0}} + {{:assign delai="abs(%d)"|math:$retard}} + {{"Reste %s jours"|args:$delai}} + {{elseif $retard > 0 }} + {{:tag color="darkred" label="Retard %s jours"|args:$retard}} + {{elseif $return_date != null}} + {{:tag color="darkgreen" label="À rendre aujourdh'ui"}} + {{/if}} + + {{:linkbutton + label="Historique" + href="%smember_history.html?key=%s&id=%s"|args:$module.url:$eqpmt_key:$user.id + shape="table" + target="_dialog" + }} +
+ {{/if}} + {{/if}} + + {{* Matériels attribués définitivement *}} + {{* vérifier la présence des types de sorties requis *}} + {{if $output_types|has_key:"définitif"}} + {{#select + eqpmt.key as eqpmt_key, + eqpmt.$$.name as eqpmt_name, + mvt.$$.direction as direction, + mvt.$$.operation as operation, + MIN(mvt.$$.date) as date, + SUM(mvt.$$.amount) as amount + FROM !table AS mvt + INNER JOIN users ON mvt.$$.user = users.id + INNER JOIN !table AS eqpmt + ON mvt.$$.equipment = eqpmt.key + WHERE users.id = :user + AND mvt.$$.operation IN !output_types + GROUP BY eqpmt_key, operation + ORDER BY eqpmt_name, date + ; + !table=$module.table + :user = $user.id + !output_types=$output_types.définitif + assign="def_mat." + }} + {{/select}} + {{/if}} + + {{if $def_mat|count != 0}} +

Matériels attribués définitivement

+ + + + + + + + + + + {{#foreach from=$def_mat}} + {{:assign var="op_label" from="config.%s_nature.%s.label"|args:$direction:$operation}} + + + + + + + {{/foreach}} + +
DateMatérielOpérationQuantité
{{$date|date_short}}{{$eqpmt_name}}{{$op_label}}{{$amount}}
+ {{/if}} + + + {{* Mes réservations de matériel *}} + {{#load type="reservation" member=$logged_user.id assign="my_reservations."}}{{/load}} + {{*:debug my_reservations=$my_reservations*}} + {{if $my_reservations|count != 0}} +

Mes réservations

+ + + + + + + + + + + + {{#foreach from=$my_reservations}} + + + {{* Charge le matériel *}} + {{#load key=$equipment assign="equipment"}}{{/load}} + + + + {{if $status == "acceptée"}} + {{:assign var="_tag_color" value="--tag-color: lightgreen;"}} + {{elseif $status == "archivée"}} + {{:assign var="_tag_color" value="--tag-color: lightgrey;"}} + {{elseif $status == "en attente"}} + {{:assign var="_tag_color" value="--tag-color: lightblue;"}} + {{elseif $status == "refusée"}} + {{:assign var="_tag_color" value="--tag-color: darksalmon;"}} + {{elseif $status == "refusée"}} + {{:assign var="_tag_color" value="--tag-color: darkorchid;"}} + {{/if}} + + + {{/foreach}} + +
DateMatérielDate de débutDate de retourStatus
{{$date|date_short}}{{$equipment.name}}{{$loan_date|date_short}}{{$return_date|date_short}}{{$status}}
+ {{/if}} +{{/if}} diff --git a/snippets/my_details.html b/snippets/my_details.html new file mode 100644 index 0000000..de06ba9 --- /dev/null +++ b/snippets/my_details.html @@ -0,0 +1,3 @@ +{{* -*- brindille -*- *}} + +{{:include file="./_details.html"}} diff --git a/snippets/my_services.html b/snippets/my_services.html new file mode 100644 index 0000000..54f2b54 --- /dev/null +++ b/snippets/my_services.html @@ -0,0 +1,3 @@ +{{* -*- brindille -*- *}} + +{{:include file="./_details.html"}} \ No newline at end of file diff --git a/snippets/user_details.html b/snippets/user_details.html new file mode 100644 index 0000000..5702542 --- /dev/null +++ b/snippets/user_details.html @@ -0,0 +1,4 @@ +{{* -*- brindille -*- *}} + +{{#restrict section="users" level="read"}}{{/restrict}} +{{:include file="./_details.html"}} diff --git a/storage/add_storage.html b/storage/add_storage.html new file mode 100644 index 0000000..a1fccb2 --- /dev/null +++ b/storage/add_storage.html @@ -0,0 +1,45 @@ +{{* -*- brindille -*- *}} + + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + + {{* vérification *}} + {{if $_POST.name == null}} + {{:error message="Le nom du lieu de stockage est obligatoire"}} + {{/if}} + {{#load type="storage" where="$$.name = :name" :name=$_POST.name|trim limit=1}} + {{:error message="Ce nom est déjà utilisé"}} + {{/load}} + + {{:save + key=""|uuid + validate_schema="storage.schema.json" + type="storage" + name=$_POST.name|trim + location=$_POST.location|trim + }} + {{:redirect force="index.html?ok=1&msg=ajout"}} +{{/form}} + +{{:admin_header title="Lieu de stockage" current="module_%s"|args:$module.name}} +{{* barre de navigation *}} +{{if ! $dialog}} + {{:include file="../_nav.html" current="storage"}} +{{/if}} +{{:form_errors}} + +
+
+ Ajouter un lieu de stockage +
+ {{:input type="text" name="name" label="Nom" required=true}} + {{:input type="textarea" name="location" label="Emplacement" cols="40" rows="3" required=false}} +
+
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
diff --git a/storage/delete_storage.html b/storage/delete_storage.html new file mode 100644 index 0000000..01e4f99 --- /dev/null +++ b/storage/delete_storage.html @@ -0,0 +1,32 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + paramètres : + - key : clé du stockage à supprimer +*}} + +{{#form on="delete"}} + + {{* vérifier s'il est possible de supprimer le lieu de stockage *}} + {{#load type="movement" where="$$.storage = :storage_key" :storage_key=$_GET.key limit=1}} + {{:redirect force="index.html?err=1&msg=suppression"}} + {{/load}} + + {{:delete where="key = :key" :key=$_GET.key}} + {{:redirect force="index.html?ok=1&msg=suppression"}} +{{/form}} + + +{{:admin_header title="Lieux de stockage" custom_css="../style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{#load key=$_GET.key limit="1" assign="store"}} +{{else}} + {{:error message="Ce lieu de stockage n'existe pas !"}} +{{/load}} +{{:delete_form + legend="Supprimer %s ?"|args:$store.name + warning="Confirmer la suppression de « %s »"|args:$store.name +}} diff --git a/storage/index.html b/storage/index.html new file mode 100644 index 0000000..5a6dae4 --- /dev/null +++ b/storage/index.html @@ -0,0 +1,46 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Afficher les lieux de stockage +*}} + +{{:admin_header title="Configuration" current="module_%s"|args:$module.name}} + +{{:include file="../_nav.html" current="config" subcurrent="storage"}} + +{{if $_GET.ok}} + {{if $_GET.msg == "ajout"}} +

Ajout effectué

+ {{elseif $_GET.msg == "suppression"}} +

Suppression effectuée

+ {{/if}} +{{elseif $_GET.err}} + {{if $_GET.msg == "suppression"}} +

Impossible de supprimer ce lieu de stockage car il est utilisé !

+ {{else}} +

Opération refusée

+ {{/if}} +{{/if}} + +{{#list + type="storage" + select=" + $$.name AS 'Nom'; + $$.location AS 'Emplacement' + " + }} + + {{$name}} + {{$location}} + + {{:linkbutton label="Modifier" shape="edit" href="modify_storage.html?key=%s"|args:$key target="_dialog"}} + {{:linkbutton label="Supprimer" shape="delete" href="delete_storage.html?key=%s"|args:$key target="_dialog"}} + + +{{else}} +

Aucun lieu de stockage.

+{{/list}} + +{{:admin_footer}} diff --git a/storage/modify_storage.html b/storage/modify_storage.html new file mode 100644 index 0000000..76d5038 --- /dev/null +++ b/storage/modify_storage.html @@ -0,0 +1,55 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* récupérer les infos du lieu de stockage *}} +{{#load key=$_GET.key assign="storage"}} +{{else}} + {{:error message="Ce lieu de stockage n'existe pas"}} +{{/load}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + {{* voir si le nom a changé *}} + {{if $_POST.name|trim == $storage.name}} + {{* voir si l'emplacement a changé *}} + {{if $_POST.location|trim != $storage.location}} + {{:assign modif=true}} + {{/if}} + {{else}} + {{* voir s'il existe un lieu de stockage de même nom *}} + {{#load type="storage" where="$$.name = :name" :name=$_POST.name|trim limit=1}} + {{:error message="Modification impossible car ce nom (« %s ») est déjà utilisé !"|args:$name|trim}} + {{else}} + {{:assign modif=true}} + {{/load}} + {{/if}} + + {{if $modif}} + {{:save + key=$storage.key + validate_schema="storage.schema.json" + type="storage" + name=$_POST.name|trim + location=$_POST.location|trim + }} + {{/if}} + {{:redirect force="./index.html?ok=1&msg=modification"}} +{{/form}} + +{{:admin_header title="Modifier un lieu de stockage" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{* formulaire de modification d'un lieu de stockage *}} +
+
+ Modifier le lieu de stockage « {{$storage.name}} » +
+ {{:input type="text" name="name" label="Nom" default=$storage.name required=true maxlength="100"}} + {{:input type="textarea" name="location" label="Emplacement" default=$storage.location cols="40" rows="3" required=false}} +
+

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+
+
diff --git a/storage/storage.schema.json b/storage/storage.schema.json new file mode 100644 index 0000000..b68bdd9 --- /dev/null +++ b/storage/storage.schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["storage"] + }, + "name" : { + "description": "Nom du lieu de stockage", + "type": "string" + }, + "location": { + "description": "Emplacement du lieu de stockage", + "type": "string" + } + }, + "required": ["type", "name"] +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..9b112b6 --- /dev/null +++ b/style.css @@ -0,0 +1,30 @@ +.informations { + margin-top : 0.5em; +} + +.informations dt::after { + content: ' :'; +} + +.informations dl.describe { + margin : 0; +} + +.informations dl.describe > dt { + flex: 0 0 10rem; + margin-right: 0; +} + +.informations dl.describe > dd { + margin-top : 0; + margin-left : 0; +} + +/* désactiver rétroaction pour colonnes non triables */ +table.list > thead th[class~=nosort] a:hover { + background-color : rgba(var(--gSecondColor), 0.); +} + +.nombre { + text-align: right !important; +} diff --git a/unarchive_equipment.html b/unarchive_equipment.html new file mode 100644 index 0000000..73b794d --- /dev/null +++ b/unarchive_equipment.html @@ -0,0 +1,53 @@ +{{* -*- brindille -*- *}} + +{{#restrict block=true section="accounting" level="write"}}{{/restrict}} + +{{* + Remettre le matériel en service + Paramètres : + - key : clé du matériel à modifier +*}} + +{{:assign equipment_key=$_GET.key|trim}} +{{#load key=$_GET.key assign="equipment"}} +{{else}} + {{:error message="Pas de matériel avec la clé %s"|args:$equipment_key}} +{{/load}} + +{{* Traiter l'envoi du formulaire *}} +{{#form on="save"}} + {{if $_POST.unarchive != 1}} + {{:save + key=$equipment.key + status="available" + }} + {{:redirect force="archives.html?ok=1&msg=modification"}} + {{/if}} + {{:redirect force="archives.html"}} +{{/form}} + +{{:admin_header title="Modifier matériel" custom_css="./style.css" current="module_%s"|args:$module.name}} +{{:form_errors}} + +{{#load key=$equipment.category}} + {{:assign cat_name=$name}} +{{/load}} + +
+
+ Désarchiver un matériel +
+
Matériel
+
{{$equipment.name}}
+
Catégorie
+
{{$cat_name}}
+
+
+ {{:input type="checkbox" value=1 name="unarchive" label="Archivé" checked="checked" help="décocher pour remettre le matériel en service"}} +
+
+ +

+ {{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}} +

+