Compare commits

...
4 Commits
88 changed files with 11680 additions and 26 deletions

No files matched your search

-24
View File
@@ -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 <https://unlicense.org/>
+62 -2
View File
@@ -1,3 +1,63 @@
# materiel_reservation
# Module de gestion de matériels et de réservations pour Paheko
Le module original permet de gérer les matériels de l'association.\
La source et la documentation se trouve [ici](https://gitea.zaclys.com/lesanges/equipment).\
Merci à l'auteur pour ce superbe module !
Permet de gérer un inventaire de matériels, ainsi que de suivre les prêts, les réservations dans le logiciel Paheko
Ce **module** permet de gérer en plus des réservations.\
Les changements proposés par le module original sont répercutés fréquemment dans cette version.\
Dans la description du module sous Paheko, vous trouverez la version du module original et la version de ce module.\
[Télécharger ici](https://git.kaz.bzh/bountz/equipment_resa)
## Réservations de matériel
Réservation de 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.
## Fonctionnalités
+ Réservation "_anonyme_" depuis le site web (rattachée à un membre par l'admin)
+ Réservation par les membres connectés
+ Convention de prêt/location
+ Gestion des réservations par l'admin (acceptation, refus,...)
+ Calendrier des réservations
+ Ajout de champs personnalisés sur le matériel (ex: tarif de location)
### Roadmap
+ Utiliser le module agenda associatif à la place du JS "fullcalendar"
## Installation
### Module principal
Télécharger le module depuis le GIT et le décompresser dans un répertoire nommé "modules".\
Décompresser le ZIP dans le répertoire "modules" et déplacer le ZIP. \
A ce stade, vous devez avoir une arborescence comme suit : modules --> equipment_resa --> [fichiers] \
Compresser le répertoire "modules" en le nommant equipment_resa.zip par exemple.\
Aller dans l'interface d'admin Paheko, sous Configuration --> Extensions et tout en bas, cliquer sur le bouton **|importer un module|. **\
Une fois le module chargé dans Paheko, activer le, puis aller dans sa configuration et cliquer sur l'onglet [Réservation].\
Activer la réservation en cochant la case : Activer les réservations\
Si vous avez le module d'origine de _Gestion des Matériels_, vous pouvez importer les données : Cliquer sur le bouton **|importer|** en bas.
### Installation des pages de réservation sur le site Web.
Les fichiers suivants sont présents dans le code du module réservation sous le répertoire "_web_exemple" pour information/exemple.\
Cette partie est exclue du support puisqu'elle touche l'implémentation de la fonctionnalité sur votre site.\
Dans le code du module "Site web", importer les fichiers avec les noms suivants :
- equipment.html
- equipment_no_image.png
- equipment_styles.css
- global.js
Modifier ensuite les fichiers existants suivants :
- config.html (complet + modif)
- contact.html (complet + modif)
- _head.html (ne contient que la partie à ajouter)
- _breadcrumbs.html (complet + modif)
### Configuration
Site Web : (Configuration du site web) : Cocher "Accès aux réservations"
## Dépendances
Site Web : (Configuration du site web) : Cocher "Formulaire de contact"
## Droits d'accès
Admin : Le module est accessible uniquement pour les membres ayant au moins le droit d'écriture en gestion des membres.\
Membres connectés : Accès à la liste du matériel, au détail d'un matériel et à sa réservation.\
Visiteurs (Web) : Accès à la liste du matériel, au détail d'un matériel et à sa réservation.
+70
View File
@@ -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"}}
+29
View File
@@ -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}}
+148
View File
@@ -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}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
{{: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"}}
<fieldset class="shortFormRight">
<legend>Filtrer par appartenance</legend>
{{:dropdown
title="Filtrer par appartenance"
options=$prop_options
value="%s"|args:$selected_prop
}}
</fieldset>
<div class="shortFormLeft">
<p class="help">Inventaire des matériels présents dans l'association</p>
</div>
{{#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}}
<tr>
{{if $selected_prop == null}}
{{:assign prop=""}}
{{else}}
{{:assign prop="&prop=%s"|args:$selected_prop}}
{{/if}}
<td>{{:link href="equipment_history.html?key=%s&prop=%s"|args:$key:$selected_prop label=$name}}</td>
<td>{{$cat_name}}</td>
<td class="num">{{$stock}}</td>
<td class="num">{{$col4}}</td>
<td class="num">{{$col5}}
<td class="num">{{$out}}</td>
<td class="num">{{$col7}}</td>
<td class="actions">
{{: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"}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun matériel.</p>
{{/list}}
<script type="text/javascript" src="scripts.js"></script>
<script type="text/javascript">
(function () {
let table = document.querySelector("table[class=list]");
if (table != null) {
disableColumSort(table);
}
})();
</script>
+83
View File
@@ -0,0 +1,83 @@
{{* -*- brindille -*- *}}
<nav class="tabs">
{{if $current == 'inventaire'}}
<aside>
{{if !$subcurrent || $subcurrent != "mouvements"}}
{{if $cat == 0}}
{{:linkbutton label="Ajouter une catégorie" shape="plus" href="categories/add_category.html" target="_dialog"}}
{{else}}
{{:exportmenu right=true}}
{{:linkbutton label="Ajouter un nouveau matériel" shape="plus" href="movements/add_new_equipment.html" target="_dialog"}}
{{/if}}
{{elseif $subcurrent == "mouvements"}}
{{if $sortie != null}}
{{:linkbutton label="Sortie" shape="minus" href="movements/output_equipment.html?key=%s"|args:$key target="_dialog"}}
{{/if}}
{{:linkbutton label="Entrée" shape="plus" href="movements/input_equipment.html?key=%s"|args:$key target="_dialog"}}
{{/if}}
</aside>
{{elseif $current == 'archives'}}
<aside>
{{:exportmenu right=true}}
</aside>
{{elseif $current == 'config'}}
{{if $subcurrent == "categories" || $subcurrent == "storage"}}
<aside>
{{:exportmenu right=true}}
</aside>
{{/if}}
{{/if}}
<ul>
<li {{if $current == 'inventaire'}} class="current"{{/if}}><a href="{{$module.url}}index.html">Inventaire</a></li>
<li {{if $current == 'historique'}} class="current"{{/if}}><a href="{{$module.url}}global_history.html">Historique</a></li>
<li {{if $current == 'prêt'}} class="current"{{/if}}><a href="{{$module.url}}loan_history.html?output_type=loan">Prêts</a></li>
<li {{if $current == 'location'}} class="current"{{/if}}><a href="{{$module.url}}loan_history.html?output_type=rent">Locations</a></li>
{{if $module.config.resa_active == true}}
<li {{if $current == 'réservation'}} class="current"{{/if}}><a href="{{$module.url}}resa_history.html?output_type=resa">Réservations</a></li>
{{/if}}
<li {{if $current == 'archives'}} class="current"{{/if}}><a href="{{$module.url}}archives.html">Archives</a></li>
<li {{if $current == 'config'}} class="current"{{/if}}><a href="{{$module.url}}categories/index.html">Configuration</a></li>
</ul>
{{if $current == 'inventaire'}}
{{if $subcurrent == 'mouvements'}}
<ul class="sub">
<li class="title"><strong>Mouvements — {{$eqpmt}} ({{$category}})</strong></li>
</ul>
{{/if}}
{{elseif $current == 'prêt'}}
<ul class="sub">
<li {{if $subcurrent == 'encours'}} class="current"{{/if}}><a href="{{$module.url}}loan_history.html?output_type=loan">En cours</a></li>
<li {{if $subcurrent == 'historique'}} class="current"{{/if}}><a href="{{$module.url}}loan_movements.html?output_type=loan">Historique</a></li>
<li {{if $subcurrent == 'membres'}} class="current"{{/if}}><a href="{{$module.url}}member_loan.html?output_type=loan">Membres</a></li>
</ul>
{{elseif $current == 'réservation'}}
<ul class="sub">
<li {{if $subcurrent == 'encours'}} class="current"{{/if}}><a href="{{$module.url}}resa_history.html?output_type=resa">Demandes en cours</a></li>
<li {{if $subcurrent == 'calendrier'}} class="current"{{/if}}><a href="{{$module.url}}resa_history.html?output_type=resacal">Calendrier</a></li>
<li {{if $subcurrent == 'suppression'}} class="current"{{/if}}><a href="{{$module.url}}resa_history.html?output_type=resadel">Suppression</a></li>
</ul>
{{elseif $current == 'location'}}
<ul class="sub">
<li {{if $subcurrent == 'encours'}} class="current"{{/if}}><a href="{{$module.url}}loan_history.html?output_type=rent">En cours</a></li>
<li {{if $subcurrent == 'historique'}} class="current"{{/if}}><a href="{{$module.url}}loan_movements.html?output_type=rent">Historique</a></li>
<li {{if $subcurrent == 'membres'}} class="current"{{/if}}><a href="{{$module.url}}member_loan.html?output_type=rent">Membres</a></li>
</ul>
{{elseif $current == 'archives'}}
{{if $subcurrent == 'mouvements'}}
<ul class="sub">
<li class="title"><strong>Mouvements — {{$eqpmt}} ({{$category}})</strong></li>
</ul>
{{/if}}
{{elseif $current == 'config'}}
<ul class="sub">
<li {{if $subcurrent == 'categories'}} class="current"{{/if}}><a href="{{$module.url}}categories/index.html">Catégories</a></li>
<li {{if $subcurrent == 'storage'}} class="current"{{/if}}><a href="{{$module.url}}storage/index.html">Lieux de stockage</a></li>
<li {{if $subcurrent == 'typesES'}} class="current"{{/if}}><a href="{{$module.url}}config.html">Types d'entrées/sorties</a></li>
<li {{if $subcurrent == 'divers'}} class="current"{{/if}}><a href="{{$module.url}}config/misc.html">Divers</a></li>
<li {{if $subcurrent == 'resaconfig'}} class="current"{{/if}}><a href="{{$module.url}}config/reservations.html">Réservations</a></li>
<li {{if $subcurrent == 'custom_fields'}} class="current"{{/if}}><a href="{{$module.url}}config/custom_fields.html">Champs personnalisés</a></li>
</ul>
{{/if}}
</nav>
+30
View File
@@ -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}}
+225
View File
@@ -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}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
{{: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"}}
<fieldset class="shortFormRight">
<legend>Filtrer par appartenance</legend>
{{:dropdown
title="Filtrer par appartenance"
options=$prop_options
value="%s"|args:$selected_prop
}}
</fieldset>
<p class="help">Inventaire des matériels présents dans l'association et réservations</p>
<p class="help">Légende : <br/>
{{:icon shape="check"}} : réservation acceptée<br/>
{{:icon shape="help"}} : réservation en attente de traitement<br/>
{{:icon shape="calendar"}} : réservation non traitée à temps (périmée) ou date de retour dépassée !<br/>
{{:icon shape="import"}} : date de retour échue !<br/>
{{:icon shape="export"}} : réservation en cours
</p>
{{* 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}}
<tr>
{{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}}
<td>
{{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}}
</td>
<td>{{$cat_name}}</td>
<td class="num">{{$stock}}</td>
<td class="num">{{$col4}}</td>
<td class="num">{{$col5}}
<td class="num">{{$out}}</td>
<td class="num">{{$col7}}</td>
{{*:debug _eq_resa_status=$_resa_status*}}
{{if $_resa_count > 0}}
<td class="num">
{{#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}}
</td>
{{else}}
<td class="num">{{$col8}}</td>
{{/if}}
<td class="actions">
{{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}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun matériel.</p>
{{/list}}
<script type="text/javascript" src="scripts.js"></script>
<script type="text/javascript">
(function () {
let table = document.querySelector("table[class=list]");
if (table != null) {
disableColumSort(table);
}
})();
</script>
+21
View File
@@ -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}}
+31
View File
@@ -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"}}
{{*
<dd><span class="tag" style="{{$_tag_color}}">Supprimée</span></dd>
*}}
{{/if}}
{{if !$color_only}}
<dd><span class="tag" style="--tag-color:{{$_tag_color}}; color:{{$_text_color}};">{{$status|or:"Supprimée"}}</span></dd>
{{/if}}
+2
View File
@@ -0,0 +1,2 @@
<script src='https://cdn.jsdelivr.net/npm/fullcalendar/index.global.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.20/locales-all.global.min.js'></script>
+296
View File
@@ -0,0 +1,296 @@
{{* -*- brindille -*- *}}
{{if $_POST.signed && $_POST.rid >= 1}}
{{:save id=$_POST.rid
type="reservation"
signed=$_POST.signed|trim
}}
<p class="block confirm">Réservation effectuée et signée</p>
{{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)
*}}
<link href='https://fonts.googleapis.com/css?family=Allura' rel='stylesheet'>
<style>
{{if !$is_logged}}
body {
font-family: Arial, sans-serif;
margin: 40px;
line-height: 1.6;
color: #222;
}
h1 {
text-align: center;
font-size: 28px;
margin-bottom: 40px;
}
h2 {
margin-top: 35px;
border-bottom: 1px solid #ccc;
padding-bottom: 5px;
font-size: 20px;
}
h3 {
margin-top: 25px;
font-size: 17px;
}
:root {
--gMainColor: 0, 99, 155;
--gSecondColor: 7, 220, 98;
--gBgColor: 255, 255, 255;
--gTextColor: 0, 0, 0;
--gBorderColor: #666;
--gLightBorderColor: #ccc;
--gLightBackgroundColor: #eee;
--gLinkColor: blue;
--gHoverLinkColor: 127, 0, 0;
--gMainColor: 32, 120, 122;
--gSecondColor: 133, 185, 186;
}
{{/if}}
p {
margin: 10px 0;
}
button.icn-btn, b.btn {
cursor: pointer;
color: rgb(var(--gTextColor));
border: 1px solid rgba(var(--gMainColor), 0.5);
background: rgba(var(--gSecondColor), 0.1);
font-size: inherit;
border-radius: .2em;
padding: .2em .4em;
margin: .2em .5em;
}
.field {
border-bottom: 1px dotted #555;
display: inline-block;
min-width: 300px;
height: 20px;
}
.large-field {
border-bottom: 1px dotted #555;
display: inline-block;
width: 100%;
height: 20px;
margin-top: 5px;
}
ul {
margin-top: 10px;
}
.signature-section {
margin-top: 60px;
display: flex;
justify-content: space-between;
gap: 40px;
}
.signature-box {
width: 45%;
}
.signature-space {
margin-top: 80px;
border-top: 1px solid #000;
width: 100%;
}
.signature {
font-family: "Allura", "Lucida Console", "Courier New", monospace;
font-size: 22px;
}
@media print {
body {
margin: 20mm;
}
}
</style>
{{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 *}}
<form method="post" action="">
<fieldset class="">
<legend>Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}})</legend>
<h1>Convention de prêt de matériel</h1>
<h2>Entre les soussignés :</h2>
<p>Nom de l’association : <span class="field">{{$config.org_name}}</span></p>
<p>Adresse du siège : <span class="field">{{$config.org_full_address}}</span></p>
<p>Représentée par : <span class="field">{{$_rep_name}}</span></p>
<p>Fonction : <span class="field">Membre du conseil collégial</span></p>
<p>Ci-après dénommée « l’Association ».</p>
<h2>Emprunteur</h2>
<p>Nom : <span class="field">{{$resa.name}}</span></p>
<p>Adresse : <span class="field">{{$resa.address}}</span></p>
<p>Contact(Tel/email) : <span class="field">{{$resa.contact}} / {{$resa.email}}</span></p>
<p>N° d’adhérent : <span class="field">{{$resa.member}}</span></p>
<p>Ci-après dénommé « l’Emprunteur ».</p>
<h3>Il a été convenu ce qui suit :</h3>
<h2>Article 1 — Objet de la convention</h2>
<p>L’Association met à disposition de l’Emprunteur, à titre gratuit, le matériel suivant :</p>
<p>Désignation : <span class="field">{{$equipment.name}}</span></p>
<p>Description : </p><div class="large-field">{{$equipment.description}}</div>
<p>Numéro de série : <span class="field">{{$equipment.serialno}}</span></p>
<p>État du matériel au moment du prêt : <span class="field">{{$_equip_config_state}}</span></p>
<p>Accessoires fournis : </p>
<div class="large-field"></div>
<h2>Article 2 — Durée du prêt</h2>
<p>Le présent prêt est consenti :</p>
<p>À compter du : <span class="field">{{$now|date_short}}</span></p>{{*$resa.loan_date|date_short*}}
<p>Jusqu’au : <span class="field">{{$resa.return_date|date_short}}</span></p>
<p>
Le matériel devra être restitué au plus tard à cette date, sauf accord préalable de l’Association.
</p>
<h2>Article 3 — Conditions d’utilisation</h2>
<p>
L’emprunteur s’engage à :<br/>
<ul>
<li>Utiliser le matériel conformément à son usage normal et dans le respect des règles de sécurité,</li>
<li>Prendre toutes les précautions nécessaires pour éviter toute dégradation, perte ou vol,</li>
<li>Ne pas prêter ou céder le matériel à un tiers,</li>
<li>Restituer le matériel propre et dans l’état dans lequel il a été remis, hors usure normale,</li>
<li>Remplacer les consommables prêtés avec le matériel,</li>
<li>Signaler immédiatement tout dysfonctionnement ou incident.</li>
</ul>
</p>
<h2>Article 4 — Assurance responsabilité civile</h2>
<p>
L’emprunteur certifie être couvert par une assurance responsabilité civile en cours de validité <br/>
couvrant les dommages pouvant être causés aux tiers ainsi que, le cas échéant, les dommages liés <br/>
à l’utilisation du matériel prêté.<br/>
Une attestation d’assurance pourra être demandée par le prêteur avant la remise du matériel.<br/>
À défaut d’assurance valide, le prêteur pourra refuser la mise à disposition du matériel.
</p>
<h2>Article 5 — Responsabilité</h2>
<p>L’emprunteur est responsable du matériel pendant toute la durée du prêt.<br/>
En cas de détérioration, perte ou vol, l’emprunteur s’engage à :<br/>
<ul>
<li>Informer immédiatement l’Association ;</li>
<li>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.</li>
</ul>
</p>
<h2>Article 6 — Restitution</h2>
<p>
La restitution du matériel aura lieu :
<p>Lieu : <span class="field">Ressourcerie / chez le prêteur</span></p>
<p>Date : <span class="field">{{$resa.return_date|date_short}}</span></p>
Un état du matériel pourra être réalisé contradictoirement lors du retour.
</p>
{{* 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}}
<h2>Article 7 — Tarif</h2>
<p>L'emprunteur s'engage a régler à l'association le tarif journalier de {{$prix}}€.</p>
{{else}}
<h2>Article 7 — Gratuité</h2>
<p>Le présent prêt est consenti à titre gratuit et sans contrepartie financière. </p>
{{/if}}
<h2>Article 8 — Litiges</h2>
<p>Les parties s’efforceront de régler à l’amiable tout différend relatif à l’exécution de la présente convention.<br/>
À défaut d’accord amiable, le litige relèvera des juridictions compétentes.</p>
<h2>Signatures</h2>
<p>Fait à : <span class="field">L'île d'Arz</span></p>
<p>Le : <span class="field">{{$resa.date|date_long}}</span></p>
<div class="signature-section">
<div class="signature-box">
<h3>Pour l’Association</h3>
<p>Nom : <span class="field">{{$_rep_name}}</span></p>
<p>Fonction : <span class="field">Membre du conseil collégial</span></p>
<p>Signature</p>
<dl>
{{:input class="signature" type="text" name="assosigned" required=true default=$_rep_name readonly=true}}
{{*:captcha html=true verify=true*}}
</dl>
</div>
<div class="signature-box">
<h3>L’Emprunteur</h3>
<p>Signature</p>
<dl>
{{: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*}}
</dl>
</div>
</div>
</fieldset>
<p class="submit">
{{: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"}}
</p>
</form>
{{/if}}
+20
View File
@@ -0,0 +1,20 @@
{{if !$parent && !$custom}}
{{:error message="Missing parent|custom parameters"}}
{{/if}}
<nav class="breadcrumbs">
<ul>
<li><a href="{{$root_uri}}">Accueil</a></li>
{{if $parent}}
{{#breadcrumbs path=$parent}}
<li><a href="{{$url}}">{{$title|remove_leading_number}}</a></li>
{{/breadcrumbs}}
{{/if}}
{{if $custom}}
{{#foreach from=$custom}}
<li><a href="{{$_url}}">{{$_title|remove_leading_number}}</a></li>
{{/foreach}}
{{/if}}
</ul>
</nav>
+7
View File
@@ -0,0 +1,7 @@
{{* Bloc à positionner dans la partie <head> de la page *}}
{{if $module.config.show_equipment !== false}}
{{* Include JS et CSS pour le calendrier des réservations *}}
{{:include file="/equipment/_web_calendar.html" title=$page.title|remove_leading_number}}
<link rel="stylesheet" type="text/css" href="{{$root_uri}}equipment_styles.css?h={{$version_hash}}" media="all" />
<script type="text/javascript" src="global.js?h={{$version_hash}}"></script>
{{/if}}
+179
View File
@@ -0,0 +1,179 @@
{{:admin_header title="Configuration du site web"}}
{{#form on="save"}}
{{:assign uri=null}}
{{if $_POST.home_sticky_uri|trim}}
{{:assign uri=$_POST.home_sticky_uri|trim|regexp_replace:'!^.*?([a-zA-Z0-9_-]+)$!':"$1"}}
{{#pages uri=$uri}}
{{else}}
{{:error message="Cette page n'existe pas ou est en brouillon : %s"|args:$uri}}
{{/pages}}
{{/if}}
{{:assign var="checkboxes.show_search" value=null}}
{{:assign var="checkboxes.show_hours" value=null}}
{{:assign var="checkboxes.show_bookings" value=null}}
{{:assign var="checkboxes.show_address" value=null}}
{{:assign var="checkboxes.show_email" value=null}}
{{:assign var="checkboxes.show_phone" value=null}}
{{:assign var="checkboxes.show_marker" value=null}}
{{:assign var="checkboxes.contact_form" value=null}}
{{:assign var="checkboxes.show_login" value=null}}
{{:assign var="checkboxes.show_equipment" value=null}}
{{#foreach from=$checkboxes key="name"}}
{{:assign var="present" from="_POST.%s_present"|args:$name}}
{{:assign var="value" from="_POST.%s"|args:$name}}
{{if $present}}
{{:assign var="checkboxes.%s"|args:$name value=$value|boolval}}
{{/if}}
{{/foreach}}
{{:save key="config"
color1=null
color2=null
hue1=$_POST.hue1|intval
hue2=$_POST.hue2|intval
layout=$_POST.layout|trim|or:null
background=$_POST.background|trim|or:null
show_search=$checkboxes.show_search
show_hours=$checkboxes.show_hours
show_bookings=$checkboxes.show_bookings
show_address=$checkboxes.show_address
show_email=$checkboxes.show_email
show_phone=$checkboxes.show_phone
show_marker=$checkboxes.show_marker
contact_form=$checkboxes.contact_form
show_login=$checkboxes.show_login
show_equipment=$checkboxes.show_equipment
home_sticky_uri=$uri|or:null
}}
{{:redirect to="?ok=1"}}
{{/form}}
{{if $_GET.ok}}
<p class="block confirm">Configuration enregistrée.</p>
{{/if}}
{{:form_errors}}
<form method="post" action="">
{{:assign var="layouts"
2col="Classique — 2 colonnes"
1col="Classique — 1 colonne"
wide="Large — 2 colonnes"
}}
{{:assign var="backgrounds"
gradient="Dégradé entre les deux couleurs"
white_gradient="Dégradé couleur primaire — blanc"
white="Blanc et couleur primaire"
gray="Blanc et gris"
all_white="Tout blanc"
dark="Sombre"
}}
<style type="text/css">
#preview {
width: 500px;
height: 400px;
overflow: hidden;
float: right;
margin: 1em;
border: 2px solid #ccc;
}
iframe {
border: none;
transform: scale(0.5);
-ms-transform-origin: 0 0;
-moz-transform-origin: 0 0;
-o-transform-origin: 0 0;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
overflow: hidden;
pointer-events: none;
}
</style>
{{if $config.site_disabled}}
<p class="block alert">Le site est actuellement désactivé.</p>
{{else}}
<div id="preview">
<iframe src="{{$site_url}}?dezoom=1" width="1000" height="800" scrolling="no"></iframe>
</div>
{{/if}}
{{if $module.config.hue1 === null}}
{{:assign color1=$module.config.color1|or:$config.color1|or:"#999999"|css_hex_extract_hsv}}
{{:assign color2=$module.config.color2|or:$config.color2|or:"#333333"|css_hex_extract_hsv}}
{{:assign var="module.config.hue1" from="color1.h"}}
{{:assign var="module.config.hue2" from="color2.h"}}
{{/if}}
<fieldset>
<legend>Configuration du site web</legend>
<dl>
{{:input type="select" name="layout" label="Disposition sur grand écran" required=true default="2col" options=$layouts help="Sur petit écran (mobile), la disposition reste sur une colonne" source=$module.config}}
{{:input type="hue" name="hue1" label="Couleur primaire" required=false source=$module.config}}
{{:input type="hue" name="hue2" label="Couleur secondaire" required=false source=$module.config}}
{{:input type="select" name="background" options=$backgrounds label="Couleur de fond" required=true source=$module.config}}
<dt>Éléments à afficher sur le site</dt>
{{:input type="checkbox" name="show_login" value=1 label="Lien de connexion" source=$module.config default=1 help="Si coché, affiche un lien pour se connecter à la gestion de l'association."}}
{{:input type="checkbox" name="show_equipment" value=1 label="Voir le matériel disponible" source=$module.config default=0}}
{{:input type="checkbox" name="show_search" value=1 label="Formulaire de recherche" source=$module.config default=1}}
{{#module name="openings"}}
{{:input type="checkbox" name="show_hours" value=1 label="Horaires d'ouverture" source=$module.config default=1}}
{{/module}}
{{#module name="bookings"}}
{{:input type="checkbox" name="show_bookings" value=1 label="Accès aux réservations" source=$module.config default=1}}
{{/module}}
{{if $config.org_full_address}}
{{:input type="checkbox" name="show_address" value=1 label="Adresse physique" source=$module.config default=1}}
{{:input type="checkbox" name="show_marker" value=1 label="Lien pour ouvrir l'adresse sur une carte" source=$module.config default=1}}
{{/if}}
{{if $config.org_phone}}
{{:input type="checkbox" name="show_phone" value=1 label="Numéro de téléphone" source=$module.config default=1}}
{{/if}}
{{if $config.org_email}}
{{:input type="checkbox" name="show_email" value=1 label="Adresse e-mail" source=$module.config default=1}}
{{:input type="checkbox" name="contact_form" value=1 label="Formulaire de contact" source=$module.config default=0}}
{{/if}}
{{:input type="text" name="home_sticky_uri" label="Identifiant unique de la page à épingler en haut de la page d'accueil" source=$module.config help="En renseignant ici l'identifiant d'une page du site web, celle-ci restera toujours en premier sur la page d'accueil du site. C'est utile par exemple pour afficher une courte présentation de l'association en permanence."}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
<script type="text/javascript">
g.onload(() => {
function updateColors() {
var color1 = $('#f_hue1').value;
var color2 = $('#f_hue2').value;
var doc = $('#preview iframe')[0].contentWindow.document;
doc.body.style = `--first-color: ${color1}; --second-color: ${color2};`;
}
$('#f_layout').onchange = (e) => {
var layout = e.target.value;
var doc = $('#preview iframe')[0].contentWindow.document;
doc.body.className = doc.body.className.replace(/\s*layout-\w+|$/, ' layout-' + layout);
}
$('#f_background').onchange = (e) => {
var bg = e.target.value;
var doc = $('#preview iframe')[0].contentWindow.document;
doc.body.className = doc.body.className.replace(/\s*bg-\w+|$/, ' bg-' + bg);
}
$('#f_hue1').addEventListener('input', updateColors);
$('#f_hue2').addEventListener('input', updateColors);
});
</script>
</form>
{{:admin_footer}}
+70
View File
@@ -0,0 +1,70 @@
{{if !$module.config.contact_form || !$config.org_email}}
{{:redirect to="./"}}
{{/if}}
{{if $logged_user.id }}
{{:assign user=$logged_user.nom email=$logged_user.email}}
{{/if}}
{{:assign var=sujets a="Question générale" b="Proposition de matériel" c="Problème sur le site" d="Réservation de matériel" e="Vélo" f="Autre"}}
{{* Si demande de réservation de matériel NON propriété de l'association *}}
{{if $_GET.fonc|trim === 'resa'}}
{{:assign var=sujet value="d"}}
{{* Charge le matériel *}}
{{#load module="equipment" key=$_GET.key assign="equipment"}}
{{:assign var=message value="Bonjour, je souhaite me renseigner pour la réservation de %s du __/__/__ au __/__/__ ."|args:$name}}
{{/load}}
{{elseif $_GET.fonc|trim === 'velo'}}
{{:assign var=sujet value="e"}}
{{#select id, modele FROM plugin_stock_velos WHERE id = :id; :id=$_GET.key }}
{{:assign var=message value="Bonjour, je suis intéressé.e par le vélo %s n° %s ."|args:$modele:$id}}
{{/select}}
{{/if}}
{{#form on="send"}}
{{:captcha verify=true}}
{{if $_POST.name|trim === ''}}
{{:error message="Merci de renseigner un nom."}}
{{elseif $_POST.name|regexp_match:'/https?:|www\./'}}
{{:error message="Le nom ne peut pas comporter d'adresse web"}}
{{elseif $_POST.email|regexp_match:'/https?:|www\./'}}
{{:error message="L'adresse e-mail ne peut pas comporter d'adresse web"}}
{{elseif $_POST.message|trim === ''}}
{{:error message="Merci de renseigner un message."}}
{{elseif !$_POST.email|trim === ''}}
{{:error message="Merci d'indiquer votre adresse e-mail."}}
{{elseif !$_POST.email|check_email}}
{{:error message="L'adresse e-mail renseignée est invalide."}}
{{/if}}
{{if $_POST.subject|trim === ''}}
{{:error message="Merci de choisir un sujet."}}
{{else}}
{{:assign var="sujet" from="sujets.%s"|args:$_POST.subject}}
{{/if}}
{{:assign body="Message de :\n%s\n%s\n\n---\n\n%s"|args:$_POST.name:$_POST.email:$_POST.message}}
{{:mail to=$config.org_email subject=$sujet|trim body=$body replyto=$_POST.email|trim}}
{{:redirect to="%s?sent=ok"|args:$request_url}}
{{/form}}
{{:include file="./_head.html" title="Contact"}}
<article class="single">
<h1>Contactez nous</h1>
{{if $_GET.sent}}
<p class="alert">Votre message a bien été transmis !</p>
{{else}}
<form method="post" action="">
<fieldset>
<legend>Renseignez ce formulaire pour nous envoyer un message</legend>
{{:form_errors}}
<dl>
{{:input type="text" name="name" label="Votre nom" default=$user required=true}}
{{:input type="email" name="email" label="Votre adresse e-mail" default=$email required=true}}
{{:input type="select" name="subject" label="Sujet du message" options=$sujets default=$sujet required=true}}
{{:input type="textarea" cols=40 rows=10 name="message" label="Message" default=$message required=true}}
<dd class="captcha">{{:captcha html=true}}</dd>
</dl>
<p class="submit">{{:button type="submit" name="send" label="Envoyer"}}</p>
</fieldset>
</form>
{{/if}}
</article>
{{:include file="./_foot.html"}}
+55
View File
@@ -0,0 +1,55 @@
{{* -*- brindille -*- *}}
{{:assign var="page.title" value="Matériel à disposition"}}
{{:assign var="page.path" value="./equipment.html"}}
{{if $_GET.fonc=="save_resa"}}
{{** No header allowed to download the PDF *}}
{{*:assign var=page.title value="Matériel réservé ! Voici votre convention de prêt/location."*}}
{{else}}
{{:include file="./_head.html" title=$page.title|remove_leading_number}}
{{:assign var="custom." _title="🧰 Matériel" _url=$page.path}}
{{if !$_GET.fonc || $_GET.fonc=="inv2" || $_GET.fonc=="inv3"}}
{{:assign var="page" title="Matériel à disposition" path="./equipment.html"}}
{{elseif $_GET.fonc=="voir"}}
{{:assign var="page" title="Détails du matériel" path="./equipment.html"}}
{{:assign var="custom." _title="🔎 Détails" _url="#"}}
{{elseif $_GET.fonc=="resa" || $_GET.fonc=="confirm_resa"}}
{{:assign var="page" title="Réservation du matériel" path="./equipment.html"}}
{{:assign var="custom." _title="🗓️ Réservation" _url="#"}}
{{/if}}
{{:include file="./_breadcrumbs.html"}} {{* custom au lieu de parent car pas dans la base SQL *}}
{{/if}}
<h1>{{$page.title|remove_leading_number}}</h1>
<p>Le matériel proposé ici provient soit de dons/achats et appartient à l'association soit de prêts ou mis à disposition pour la communauté.<br/>
Dans le cas de matériel mis à disposition, celui-ci n'appartient pas à l'association : cette dernière va simplement vous mettre en relation avec la personne à qui il appartient.
</p>
{{if $_GET.ok}}
{{if $_GET.fonc == "confirm_resa" && !$_GET.rid }}
<p class="block confirm">Réservation effectuée</p>
{{/if}}
{{/if}}
{{if !$_GET.fonc}}
{{:include file="/equipment/_web_inventory.html" parent=$page.path}}
{{*elseif $_GET.fonc=="inv2"}}
{{:include file="/equipment/_web_inventory2.html" parent=$page.path*}}
{{elseif $_GET.fonc=="inv3"}}
{{:include file="/equipment/_web_inventory3.html" parent=$page.path}}
{{elseif $_GET.fonc=="voir"}}
{{:include file="/equipment/_web_view.html" parent=$page.path}}
{{elseif $_GET.fonc=="resa"}}
{{:include file="/equipment/_web_resa.html" parent=$page.path}}
{{elseif $_GET.fonc=="resadel"}}
{{:include file="/equipment/_web_resadel.html" keep="_GET.keys" parent=$page.path}}
{{elseif $_GET.fonc=="confirm_resa"}}
{{if $_GET.ok}}
{{:include file="/equipment/_web_contract.html" parent=$page.path}}
{{/if}}
{{elseif $_GET.fonc=="save_resa"}}
{{:include file="/equipment/_web_saved_resa.html" parent=$page.path}}
{{else}}
{{:include file="/equipment/_web_inventory.html" parent=$page.path keep="cat_key,prop"}}
{{/if}}
{{:include file="./_foot.html"}}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

+377
View File
@@ -0,0 +1,377 @@
:root {
--gMainColor: 0, 99, 155;
--gSecondColor: 7, 220, 98;
--gTextColor: 0, 0, 0;
}
.informations {
margin-top : 0.5em;
}
.informations dt::after {
content: ' :';
}
.informations dl.describe {
border: 0px;
padding: 0.5em;
}
.informations dl.describe > dt {
float: left;
clear: left;
width: 200px;
text-align: left;
font-weight: bold;
color: green;
}
.informations dl.describe > dd {
margin: 0 0 0 110px;
padding: 0 0 0.5em 0;;
}
.nombre {
text-align: right !important;
}
.resaactionbutton {
z-index: 1;
position: absolute;
top: 15%;
right: 05%;
}
/* Image style leboncoin */
figure.leboncoin {
border: thin silver solid;
display: flex;
flex-flow: column;
padding: 5px;
max-width: 170px;
height: 261px;
margin: auto;
}
img.leboncoin {
max-width: 150px;
max-height: 150px;
}
figcaption.leboncoin {
background-color: #dce7dc;
color: white;
font: italic smaller sans-serif;
padding: 3px;
text-align: center;
height: 179px;
}
/** Image vignette */
/* Styles par défaut (mobile first) */
.imagemateriel {
display: block;
object-fit: cover;
width: 100%; /* L'image prendra 100% de la largeur de son conteneur */
height: auto; /* Maintient le ratio */
max-width: 250px;
max-height: 150px;
}
/* Pour les écrans de plus de 768px (tablettes/ordinateurs) */
@media (min-width: 768px) {
.imagemateriel {
display: block;
object-fit: cover;
width: 100%; /* L'image prendra 100% de la largeur de son conteneur */
height: auto; /* Maintient le ratio */
max-width: 670px;
max-height: 150px;
}
}
/* Datepicker */
dialog.datepicker {
user-select: none;
position: absolute;
left: 0;
padding: .3rem;
border: none;
box-shadow: 0 0 5px #000;
border-radius: .5rem;
z-index: 1000;
}
/* Bouton Link */
nav.tabs aside {
float: right;
max-width: 50%;
text-align: right;
clear: right;
margin-top: .5em;
}
.main.icn-btn {
padding: 13px 20px;
display: inline-block;
}
.icn-btn {
appearance: none;
backface-visibility: hidden;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 5px;
border-style: none;
box-shadow: rgb(0, 148, 133) 0 4px 9px;
box-sizing: border-box;
color: #4cb130;
cursor: pointer;
font-family: Inter,-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif;
font-size: 16px;
font-weight: 600;
letter-spacing: normal;
line-height: 1.5;
outline: none;
overflow: hidden;
position: relative;
text-align: center;
text-decoration: none;
transform: translate3d(0, 0, 0);
transition: all .3s;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
vertical-align: top;
white-space: nowrap;
a:visited {
color: black;
}
}
.icn-btn:hover {
background-color: #1e8449;
opacity: 1;
transform: translateY(0);
transition-duration: .35s;
}
.icn-btn:active {
transform: translateY(2px);
transition-duration: .35s;
}
.icn-btn:hover {
color: #dfadad;
box-shadow: rgba(39, 174, 96, .2) 0 6px 12px;
}
/* Datepicker button (.main[data-icon]:after, [data-icon].right:after) */
.datepicker.icn-btn[data-icon]:before {
display: inline-block;
font-family: "paheko", sans-serif;
text-shadow: 1px 1px 1px var(--gLightBorderColor);
font-size: 1.2em;
line-height: .8em;
vertical-align: middle;
content: attr(data-icon);
font-weight: normal;
text-decoration: none;
}
/** Table.list */
.list{width:100%;border-collapse:collapse}
.list td,.list th {padding:12px 15px;border:1px solid #ddd;text-align:center;font-size:16px}
.list th {background-color:rgba(var(--gSecondColor), 0.5); color:rgb(var(--gTextColor));}
.list tbody tr:nth-child(even) {background-color:rgba(var(--gSecondColor), 0.2);}
@media (max-width:768px){
.list thead {display:none}
.list,.list tbody,.list tr, .list td {display:block;width:100%}
.list tr {margin-bottom:15px}
.list td {padding-left:50%;text-align:left; position:relative}
.list td::before{content:attr(data-label); position:absolute;left:0;width:50%;padding-left:15px;font-size:15px;font-weight:bold;text-align:left}
}
/** Table Pagination */
.pagination {
clear: both;
list-style-type: none;
padding: 0.4em 0;
text-align: center;
}
.pagination li {
display: inline-block;
margin: 0 0.3em;
}
.pagination li.current {
font-size: 1.3em;
}
.pagination li a {
color: rgb(var(--gTextColor));
}
.pagination li button {
color: rgb(var(--gTextColor));
background: transparent;
border: none;
padding: 0;
margin: 0;
box-shadow: none;
text-decoration: underline;
}
/** Calendar */
/* Base mobile styles (no media query needed) */
#calendar {
display: none; /* Utiliser !important peut être nécessaire ici */
}
#calendar_light {
display: block;
}
/* Tablet and up */
@media screen and (min-width: 768px) {
#calendar {
display: block;
margin: 0;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
max-width: 800px;
margin: 10px auto;
}
#calendar_light {
display: none;
}
}
/* Desktop and up
@media screen and (min-width: 1024px) {
}*/
/** Dropdown NEW */
/**
* Dropdown, eg. interactive <select>
*/
nav.dropdown {
position: relative;
height: 2.3rem;
width: 20em;
border: 1px solid rgb(var(--gMainColor));
border-radius: .25rem;
z-index: 100;
}
nav.dropdown ul {
background-color: rgb(var(--gBgColor));
top: 0;
left: 0;
right: 0;
position: absolute;
border-radius: .5em;
}
nav.dropdown ul::after {
position: absolute;
right: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
width: 1.5em;
height: 1.5em;
font-size: 1.5em;
content: "↓";
font-family: "paheko";
cursor: pointer;
}
nav.dropdown li {
display: none;
}
html.js nav.dropdown:not(.open) {
cursor: pointer;
}
nav.dropdown li.selected, html.nojs nav.dropdown:hover li, nav.dropdown.open li {
display: block;
}
html.js nav.dropdown:not(.open) li a {
pointer-events: none;
}
nav.dropdown li > a {
display: flex;
align-items: center;
justify-content: flex-end;
padding: .4rem .6rem;
text-decoration: none;
height: 1.5em;
color: unset;
cursor: pointer;
}
nav.dropdown li a strong {
font-weight: normal;
text-align: left;
margin-right: auto;
}
nav.dropdown li a small {
color: var(--gBorderColor);
text-align: right;
white-space: pre;
}
nav.dropdown li.label {
display: none;
}
nav.dropdown.open {
border-color: transparent;
}
nav.dropdown.open li:nth-child(even) a {
background: rgba(var(--gSecondColor), 0.2);
}
nav.dropdown.open ul {
box-shadow: 0 0 5px .2rem rgba(var(--gMainColor), 0.5);
border-radius: .25rem;
}
nav.dropdown.open .selected a {
box-shadow: 0 0 5px .2rem rgba(var(--gMainColor), 0.5);
color: rgb(var(--gHoverLinkColor));
}
nav.dropdown.open li a strong {
font-weight: bold;
}
nav.dropdown.open li a:hover {
background: rgba(var(--gMainColor), 0.2);
}
nav.dropdown li a > span {
width: 2em;
text-align: center;
}
@media handheld, screen and (max-width:981px) {
nav.dropdown.open li.default {
display: block;
}
nav.home ul {
justify-content: center;
}
}
File diff suppressed because it is too large. Load diff
+196
View File
@@ -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 *}}
{{*
<div class="shortFormLeft">
<p class="help">Inventaire des matériels présents dans l'association</p>
</div>
*}}
<fieldset class="shortFormLeft">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
<legend>Filtrer par appartenance</legend>
{{:dropdown
title="Filtrer par appartenance"
options=$prop_options
value="%s"|args:$selected_prop
}}
</fieldset>
<div class="shortFormRight">
{{*: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"}}
</div>
{{*
<nav class="tabs">
<aside>
{{*: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"}}
</aside>
</nav>
*}}
{{*
<div class="topnav" id="myTopnav">
<div class="dropdown">
<button class="dropbtn">Filtrer par catégorie
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
{{#foreach from=$cat_options key="key" item="value"}}
<a href={{$value.href}}>{{$value.label}}</a>
{{/foreach}}
</div>
</div>
<div class="dropdown">
<button class="dropbtn">Filtrer par appartenance
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
{{#foreach from=$prop_options key="key" item="value"}}
<a href={{$value.href}}>{{$value.label}}</a>
{{/foreach}}
</div>
</div>
<a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
</div>
*}}
{{*: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}}
<tr>
{{if $selected_prop == null}}
{{:assign prop=""}}
{{else}}
{{:assign prop="&prop=%s"|args:$selected_prop}}
{{/if}}
<td data-label="Lien">{{:link href="equipment.html?key=%s&fonc=voir"|args:$key label=$name}}</td>
<td data-label="Catégorie">{{$cat_name}}</td>
{{* <td class="num">{{$stock}}</td>
<td class="num">{{$col4}}</td>
<td class="num">{{$col5}}
<td class="num">{{$out}}</td>
<td class="num">{{$col7}}</td>
*}}
<td data-label="Sorti">{{$out}}</td>
<td data-label="Disponible">{{$col4}}</td>
<td class="actions">
{{*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*}}
</td>
</tr>
{{* 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}}
<p class="block alert">Aucun matériel.</p>
{{/list}}
{{*
<script type="text/javascript">
(function () {
let table = document.querySelector("table[class=list]");
if (table != null) {
disableColumSort(table);
}
})();
function myFunction() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive";
} else {
x.className = "topnav";
}
}
</script>
*}}
+150
View File
@@ -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 *}}
<div class="shortFormLeft">
<p class="help">Inventaire des matériels présents dans l'association</p>
</div>
<div class="shortFormRight">
{{:linkbutton class="main" label="Affichage liste" href="equipment.html?prop=%s&cat_key=%s&fonc=inv"|args:$selected_prop:$selected_category shape="list-ul"}}
</div>
{{*
<fieldset class="shortFormRight">
<legend>Filtrer</legend>
<div class="topnav" id="myTopnav">
<div class="dropdown">
<button class="dropbtn">Filtrer par catégorie
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
{{#foreach from=$cat_options key="key" item="value"}}
<a href={{$value.href}}>{{$value.label}}</a>
{{/foreach}}
</div>
</div>
<a href="javascript:void(0);" style="font-size:15px;" class="icon" onclick="myFunction()">&#9776;</a>
</div>
</fieldset>
*}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
{{* 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}}<br/>*}}
{{else}}
{{/select}}
{{if $lignes}}
<fieldset>
<legend>{{$name}}</legend>
<table class="list">
<tr>
{{#foreach from=$lignes}}
{{if $_key!=$wequ_key}}
<td>
{{: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}}
<figure class="leboncoin">
<figcaption class="leboncoin">{{:link href="equipment.html?key=%s&fonc=voir"|args:$_key label=$name}}
<a href="{{$img_src}}" class="leboncoin" target="_dialog"><img class="leboncoin" src={{$thumbnail_src}} alt="{{$description}}"/></a>
</figcaption>
{{* Reservation si stock dispo *}}
{{:assign _dispo="%d-%d"|math:$stock:$out}}
{{if $_dispo >= 1}}
<span>&nbsp;</span>
{{:linkbutton label="Réserver" href="equipment.html?key=%s&fonc=resa"|args:$_key shape="plus"}}
{{else}}
<span>&nbsp;</span>
{{:linkbutton label="Contacter nous!" href="contact.html?key=%s&fonc=resa"|args:$_key shape="plus"}}
{{/if}}
</figure>
</td>
{{/if}}
{{/foreach}}
</tr>
</table>
</fieldset>
{{/if}}
{{/load}}
+133
View File
@@ -0,0 +1,133 @@
{{* -*- brindille -*- *}}
{{*:assign var=page.title value="Notre Matériel"}}
{{:assign var=page.path value="equipment.html"}}
<h1>{{$page.title|remove_leading_number}}</h1>
*}}
{{* 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*}}
<style id="material-hide"></style>
<div class="filters">
<fieldset>
<legend>Filtrer par catégorie</legend>
<dl>{{:input name="cat" type="select" default_empty="Toutes les catégories" options=$cat_options label="Catégorie"}}</dl>
</fieldset>
</div>
<div class="shortFormRight">
{{:linkbutton class="main" label="Affichage liste" href="equipment.html?prop=%s&cat_key=%s&fonc=inv"|args:$selected_prop:$selected_category shape="list-ul"}}
</div>
{{* 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}}
<fieldset class="fieldset" category="{{$name}}">
<legend>{{$name}}</legend>
<div class="bike-list">
{{#foreach from=$lignes}}
{{if $_key!=$wequ_key}}
<div class="container" category="{{$catname}}">
{{: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}}
<div class="image-wrapper">
<a href="{{$img_src}}" target="_dialog"><img class="imagemateriel" src={{$thumbnail_src}} alt="{{$description}}"/></a>
</div>
<span class="label2">{{$stock}}</span>
<div class="properties">
<ul>
{{*#load module="equipment" type="movement" direction="input" limit=1 where="$$.equipment = :key" :key=$_key order="$$.date"}}
<li class="date-entree">entré en stock le {{$date|relative_date}}</li>
{{/load*}}
<li class="date-entree">entré en stock le {{$mvtdate|relative_date}}</li>
<li class="numero-unique">numéro unique : {{$wequ_id}} </li>
<li>{{:link href="equipment.html?key=%s&fonc=voir"|args:$_key label=$name}}</li>
<li>Qt Disponible : {{$stock}}</li>
<li>Qt Sorti : {{$out}}</li>
{{:assign var="_state" from="states.%d"|args:$state}}
<li>État : {{$_state}}</li>
<li class="notes">{{$description|truncate:80:"(...)":false}}</li>
</ul>
{{* Reservation si stock dispo *}}
{{:assign _dispo="%d-%d"|math:$stock:$out}}
{{if $_dispo >= 1}}
<span class="resaactionbutton">{{:linkbutton class="main" label="Réserver" href="equipment.html?key=%s&fonc=resa"|args:$_key shape="plus"}}</span>
{{else}}
<span class="resaactionbutton">{{:linkbutton class="main" label="Contacter nous!" href="contact.html?key=%s&fonc=resa"|args:$_key shape="plus"}}</span>
{{/if}}
</div>
</div>
{{/if}}
{{/foreach}}
</fieldset>
</div>
{{/if}}
{{/load}}
<script type="text/javascript">
function set_toggle_hide(input_id) {
console.log(input_id);
document.getElementById(input_id).addEventListener('change', function() {
v_cat = document.getElementById('f_cat').options[document.getElementById('f_cat').selectedIndex].text
console.log(v_cat);
css = document.getElementById("material-hide")
css.innerHTML = ""
if (v_cat && !(v_cat.startsWith("Tou"))) {
css.innerHTML += `
.container:not([category="${v_cat}"]){
display:none;
}
.fieldset:not([category="${v_cat}"]){
display:none;
}
`;
}
});
}
set_toggle_hide('f_cat')
</script>
+118
View File
@@ -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 *}}
<form method="post" action="">
<fieldset class="entree">
<legend>Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}})</legend>
<dl>
{{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}}
<dd>
{{#foreach from=$_resa_lignes}}
<span>- du {{$loan_date|date_long}} au {{$return_date|date_long}}</span><br>
{{/foreach}}
</dd>
{{: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*}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Étape suivante" shape="right" class="main"}}
</p>
</form>
+42
View File
@@ -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"}}&nbsp;
{{else}}
{{:error message="Pas de réservations trouvées"}}
{{/load}}
{{/if}}
+239
View File
@@ -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)
*}}
<link href='https://fonts.googleapis.com/css?family=Allura' rel='stylesheet'>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
line-height: 1.6;
color: #222;
}
h1 {
text-align: center;
font-size: 28px;
margin-bottom: 40px;
}
h2 {
margin-top: 35px;
border-bottom: 1px solid #ccc;
padding-bottom: 5px;
font-size: 20px;
}
h3 {
margin-top: 25px;
font-size: 17px;
}
p {
margin: 10px 0;
}
.field {
border-bottom: 1px dotted #555;
display: inline-block;
min-width: 300px;
height: 20px;
}
.large-field {
border-bottom: 1px dotted #555;
display: inline-block;
width: 100%;
height: 20px;
margin-top: 5px;
}
ul {
margin-top: 10px;
}
.signature-section {
margin-top: 60px;
display: flex;
justify-content: space-between;
gap: 40px;
}
.signature-box {
width: 45%;
}
.signature-space {
margin-top: 80px;
border-top: 1px solid #000;
width: 100%;
}
.signature {
font-family: "Allura", "Lucida Console", "Courier New", monospace;
font-size: 22px;
}
@media print {
body {
margin: 20mm;
}
}
</style>
{{* Convention *}}
<fieldset class="entree">
<legend>Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}})</legend>
<h1>Convention de prêt de matériel</h1>
<h2>Entre les soussignés :</h2>
<p>Nom de l’association : <span class="field">{{$config.org_name}}</span></p>
<p>Adresse du siège : <span class="field">{{$config.org_full_address}}</span></p>
<p>Représentée par : <span class="field">{{$_rep_name}}</span></p>
<p>Fonction : <span class="field">Membre du conseil collégial</span></p>
<p>Ci-après dénommée « l’Association ».</p>
<h2>Emprunteur</h2>
<p>Nom : <span class="field">{{$resa.name}}</span></p>
<p>Adresse : <span class="field">{{$resa.address}}</span></p>
<p>Contact(Tel/email) : <span class="field">{{$resa.contact}}/{{$resa.email}}</span></p>
<p>N° d’adhérent : <span class="field">{{$resa.member}}</span></p>
<p>Ci-après dénommé « l’Emprunteur ».</p>
<p>Il a été convenu ce qui suit :</p>
<h2>Article 1 — Objet de la convention</h2>
<p>L’Association met à disposition de l’Emprunteur, à titre gratuit, le matériel suivant :</p>
<p>Désignation : <span class="field">{{$equipment.name}}</span></p>
<p>Description : </p><div class="large-field">{{$equipment.description}}</div>
<p>Numéro de série : <span class="field">{{$equipment.serialno}}</span></p>
<p>État du matériel au moment du prêt : <span class="field">{{$_equip_config_state}}</span></p>
<p>Accessoires fournis : </p>
<div class="large-field"></div>
<h2>Article 2 — Durée du prêt</h2>
<p>Le présent prêt est consenti :</p>
<p>À compter du : <span class="field">{{$resa.loan_date|date_short}}</span></p>
<p>Jusqu’au : <span class="field">{{$resa.return_date|date_short}}</span></p>
<p>
Le matériel devra être restitué au plus tard à cette date, sauf accord préalable de l’Association.
</p>
<h2>Article 3 — Conditions d’utilisation</h2>
<p>
L’emprunteur s’engage à :<br/>
<ul>
<li>Utiliser le matériel conformément à son usage normal et dans le respect des règles de sécurité ;</li>
<li>S'engager à restituer et remplacer les consommables prêtés avec le matériel,</li>
<li>Prendre toutes les précautions nécessaires pour éviter toute dégradation, perte ou vol ;</li>
<li>Ne pas prêter ou céder le matériel à un tiers ;</li>
<li>Restituer le matériel propre et dans l’état dans lequel il a été remis, hors usure normale ;</li>
<li>Signaler immédiatement tout dysfonctionnement ou incident.</li>
</ul>
</p>
<h2>Article 4 — Assurance responsabilité civile</h2>
<p>
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é.<br/>
Une attestation d’assurance pourra être demandée par le prêteur avant la remise du matériel.<br/>
À défaut d’assurance valide, le prêteur pourra refuser la mise à disposition du matériel.
</p>
<h2>Article 5 — Responsabilité</h2>
<p>L’emprunteur est responsable du matériel pendant toute la durée du prêt.<br/>
En cas de détérioration, perte ou vol, l’emprunteur s’engage à :<br/>
<ul>
<li>Informer immédiatement l’Association ;</li>
<li>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.</li>
</ul>
</p>
<h2>Article 6 — Restitution</h2>
<p>
La restitution du matériel aura lieu :
<p>Lieu : <span class="field">?????</span></p>
<p>Date : <span class="field">{{$resa.return_date|date_short}}</span></p>
Un état du matériel pourra être réalisé contradictoirement lors du retour.
</p>
{{* 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}}
<h2>Article 7 — Tarif</h2>
<p>L'emprunteur s'engage a régler à l'association le tarif journalier de {{$prix}}€.</p>
{{else}}
<h2>Article 7 — Gratuité</h2>
<p>Le présent prêt est consenti à titre gratuit et sans contrepartie financière. </p>
{{/if}}
<h2>Article 8 — Litiges</h2>
<p>
Les parties s’efforceront de régler à l’amiable tout différend relatif à l’exécution de la présente convention.<br/>
À défaut d’accord amiable, le litige relèvera des juridictions compétentes.
</p>
<h2>Signatures</h2>
<p>Fait à : <span class="field">L'île d'Arz</span></p>
<p>Le : <span class="field">{{$resa.date|date_long}}</span></p>
<div class="signature-section">
<div class="signature-box">
<h3>Pour l’Association</h3>
<p>Nom : <span class="field">{{$_rep_name}}</span></p>
<p>Fonction : <span class="field">Membre du conseil collégial</span></p>
<p>Signature</p>
<dl><span class="signature">{{$_rep_name}}</span>
{{*:input class="signature" type="text" name="assosigned" required=true default=$_rep_name readonly=true*}}
{{*:captcha html=true verify=true*}}
</dl>
</div>
<div class="signature-box">
<h3>L’Emprunteur</h3>
<p>Signature</p>
<dl><span class="signature">{{$resa.name}}</span>
{{*:input class="signature" type="text" name="signed" required=true help="Tapez votre nom pour signer le document"*}}
{{*:captcha html=true verify=true*}}
</dl>
</div>
</div>
</fieldset>
+163
View File
@@ -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<dt>%s</dt> <dd>%s €</dd>"|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<dt>%s</dt> <dd>%s</dd>"|args:$_html:$field.label:$retval}}
{{/if}}
{{/if}}
{{/foreach}}
{{/module}}
<fieldset class="informations">
<legend>Voir un matériel</legend>
<dl class="describe">
<dt>Catégorie</dt> <dd>{{$cat_name}}</dd>
<dt>Désignation</dt> <dd>{{$equipment.name}}</dd>
<dt>Description</dt> <dd>{{$equipment.description}}</dd>
<dt>Statut</dt> <dd>{{$equipment.status}}</dd>
<dt>Quantité ({{$_operation}})</dt> <dd>{{$_amount}}</dd>
<dt>État</dt> <dd>{{$_state}}</dd>
<dt>N° de série</dt> <dd>{{$equipment.serialno}}</dd>
{{$_html|raw}}
</dl>
</fieldset>
{{* View and Add Public files *}}
<fieldset>
<legend>Images associées</legend>
{{*: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}}
<a href="{{$img_src}}" class="internal-image"><img src={{$thumbnail_src}} alt="{{$value}}" /></a>
{{/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}}
<a href="/{{$img_src}}" class="internal-image" target="_dialog"><img src=/{{$thumbnail_src}} alt="{{$img_name}}" /></a>
{{/sql}}
</fieldset>
{{* 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*}}
<fieldset>
<legend>Calendrier des réservations</legend>
<div id='calendar'></div>
<div id='calendar_light'>
{{#foreach from=$_resa_lignes}}
{{:assign var="_events" value="%s{title: 'Réservation', start: '%s', end: '%s'},"|args:$_events:$loan_date:$return_date}}
<p>Réservation du {{$loan_date|date_short}} au {{$return_date|date_short}}</p>
{{/foreach}}
</div>
</fieldset>
<p class="submit">
{{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}}
</p>
<script>
const isSmallScreen = () => {
return window.innerWidth <= 500;
};
if (isSmallScreen()) {
console.log("Small screen detected");
//document.getElementById('calendar_light').innerHTML="{{$_events_light|raw}}";
} else {
document.addEventListener('DOMContentLoaded', function() {
var initialLocaleCode = 'fr'
const calendarEl = document.getElementById('calendar')
const calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,dayGridWeek,dayGridDay,listMonth'
},
aspectRatio: 2,
locale: initialLocaleCode,
buttonIcons: false, // show the prev/next text
weekNumbers: true,
navLinks: true, // can click day/week names to navigate views
editable: false,
dayMaxEvents: true, // allow "more" link when too many events
events: [
{{$_events|raw}}
]
})
calendar.render()
})
}
</script>
+85
View File
@@ -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}}
<p class="block confirm">Matériel remis en service</p>
{{/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}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
<div class="shortFormLeft">
<p class="help">Matériels qui ne sont plus dans l'association</p>
</div>
{{* 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
}}
<tr>
<td>{{:link href="equipment_history.html?key=%s&prop=1&current=archives"|args:$key label=$name}}</td>
<td>{{$col2}}</td>
<td class="actions">
{{:linkbutton
label="Mouvements"
href="equipment_history.html?key=%s&prop=1&current=archives"|args:$key
shape="table"}}
{{:linkbutton
label="Modifier"
href="unarchive_equipment.html?key=%s"|args:$key
shape="edit"
target="_dialog"}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun matériel.</p>
{{/list}}
+45
View File
@@ -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 *}}
<form method="post" action="{{$self_url}}" data-focus="1">
<fieldset class="ajout_categorie">
<legend>Ajouter une catégorie</legend>
<dl>
{{:input type="text" name="name" label="Nom" autofocus=true required=true maxlength="100"}}
</dl>
<p class="submit">
{{:button type="submit" name="save" label="Ajouter" shape="right" class="main"}}
</p>
</fieldset>
</form>
{{:admin_footer}}
+14
View File
@@ -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"]
}
+28
View File
@@ -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"
}}
+50
View File
@@ -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"}}
<p class="block confirm">Modification enregistrée</p>
{{elseif $_GET.msg == "suppression"}}
<p class="block confirm">Catégorie supprimée</p>
{{elseif $_GET.msg == "ajout"}}
<p class="block confirm">Catégorie ajoutée</p>
{{/if}}
{{elseif $_GET.err}}
{{if $_GET.msg == "suppression"}}
<p class="block error">
Cette catégorie ne peut être supprimée car elle contient encore des matériels
</p>
{{/if}}
{{/if}}
{{* afficher les catégories déjà enregistrées *}}
<section class="categories">
{{#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}}
<tr>
<th>{{$name}}</th>
<td class="actions">
{{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"}}
</td>
</tr>
{{else}}
<p class="block alert">Il n'y a aucune catégorie : vous devez en ajouter.</p>
{{/list}}
</section>
{{:admin_footer}}
+40
View File
@@ -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 *}}
<form method="post" action="" data-focus="1">
<fieldset class="modif_categorie">
<legend>Modifier la catégorie « {{$category.name}} »</legend>
<dl>
{{:input type="text" name="name" label="Nom" default=$category.name required=true maxlength="100"}}
</dl>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</fieldset>
</form>
+69
View File
@@ -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}}
<p class="block confirm">Configuration enregistrée.</p>
{{/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}}
<h2 class="ruler">{{$item|ucfirst}}s</h2>
<table class="list">
<thead>
<tr>
<th>Libellé</th>
<th>Type</th>
<th></th>
</tr>
</thead>
<tbody>
{{: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}}
<tr>
<td>{{$label}}</td>
<td>{{$type}}</td>
<td class="actions">
{{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}}
</td>
</tr>
{{/foreach}}
</tbody>
</table>
{{/foreach}}
{{:admin_footer}}
+49
View File
@@ -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"]
}
}
}
}
}
}
+183
View File
@@ -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}}
<form method="post" action="">
<fieldset>
<legend>Type d'entrée</legend>
<dl>
<td>
{{:input type="select"
label="Type d'entrée"
name="input_fields[type]"
options=$input_types
default=$type
required=true
default_empty="— Choisir un type —"}}
</td>
<td>
{{:input
type="text"
label="Libellé de l'entrée"
name="input_fields[label]"
required=true}}
</td>
</dl>
<div class="help block">
<h3>Signification du type d'entrée</h3>
<ul>
<li><b>définitif</b> : l'asso devient propriétaire du matériel (ex : achat, don)</li>
<li><b>temporaire</b> : l'asso ne devient <strong>pas</strong> propriétaire du matériel (ex : location, emprunt)</li>
<li><b>retour</b> : matériel qui revient après une sortie temporaire (ex : retour de location ou de prêt)</li>
</ul>
</div>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{else}}
{{* types de sorties *}}
{{#foreach from=$config_defaut.outputs}}
{{:assign var='output_types.%s'|args:$type value=$type}}
{{/foreach}}
<form method="post" action="">
<fieldset>
<legend>Type de sortie</legend>
<dl>
{{: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}}
<div id="tarif">
{{: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}}
</div>
</dl>
<div class="help block">
<h3>Signification du type de sortie</h3>
<ul>
<li><b>définitif</b> : le matériel n'appartient plus à l'asso (ex : vente, casse, perte, vol, ...)</li>
<li><b>temporaire</b> : 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</li>
<li><b>retour</b> : le matériel <strong>non propriété de l'asso</strong> est rendu à son propriétaire (ex : retour de location ou d'emprunt)</li>
</ul>
</div>
<div class="help block tarif">
<h3>Tarification</h3>
<ul>
<li>Une sortie temporaire gratuite sera classée dans l'onglet Prêt</li>
<li>Une sortie temporaire payante sera classée dans l'onglet Locations</li>
</ul>
</div>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{/if}}
<script type="text/javascript">
// afficher/masquer le choix du tarif
function toggleTarif(event) {
const output_fieldstype = document.getElementById('f_output_fieldstype');
const value = output_fieldstype.value;
if (value == 'temporaire') {
g.toggle('#tarif', true);
g.toggle('div.tarif', true);
} else {
g.toggle('#tarif', false);
g.toggle('div.tarif', false);
}
}
toggleTarif();
(function () {
const output_fieldstype = document.getElementById('f_output_fieldstype');
output_fieldstype.addEventListener("change", toggleTarif);
})();
</script>
+92
View File
@@ -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}}
<p class="block confirm">Configuration enregistrée.</p>
{{/if}}
<form method="post" action="" data-focus=1>
<section class="equipment_loan">
<fieldset>
<p class="help">
À utiliser optionnellement pour associer des informations supplémentaires aux matériels et/ou objets.
</p>
<table class="list fields">
<thead>
<tr>
<td>Type de champ</td>
<td>Nom du champ</td>
<td>Libellé du champ</td>
<td>Texte d'aide en dessous du champ</td>
<td>Champ obligatoire&nbsp;?</td>
<td>Page publique</td>
<td>Associé à</td>
<td></td>
</tr>
</thead>
<tbody>
{{: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"}}
<tr>
<td>{{:input type="select" name="fields[type][]" default=$field.type options=$types}}</td>
<td>{{:input type="text" name="fields[name][]" default=$field.name}}</td>
<td>{{:input type="text" name="fields[label][]" default=$field.label}}</td>
<td>{{:input type="text" name="fields[help][]" default=$field.help}}</td>
<td>{{:input type="select" name="fields[required][]" default=$field.required options=$select required=true}}</td>
<td>{{:input type="select" name="fields[published][]" default=$field.published options=$select2 required=true}}</td>
<td>{{:input type="select" name="fields[assignedto][]" default=$field.assignedto options=$select3 required=true}}</td>
<td class="actions">{{:button shape="minus" label="Enlever cette ligne" onclick="this.parentNode.parentNode.remove();"}}</td>
</tr>
{{else}}
<tr>
<td>{{:input type="select" name="fields[type][]" options=$types default="text"}}</td>
<td>{{:input type="text" name="fields[name][]" default=$field.name}}</td>
<td>{{:input type="text" name="fields[label][]" default=$field.label}}</td>
<td>{{:input type="text" name="fields[help][]" default=$field.help}}</td>
<td>{{:input type="select" name="fields[required][]" default=$field.required options=$select required=true}}</td>
<td>{{:input type="select" name="fields[published][]" default=$field.published options=$select2 required=true}}</td>
<td>{{:input type="select" name="fields[assignedto][]" default=$field.assignedto options=$select3 required=true}}</td>
<td class="actions">{{:button shape="minus" label="Enlever ce champ" onclick="this.parentNode.parentNode.remove();"}}</td>
</tr>
{{/foreach}}
</tbody>
</table>
<p class="actions">
{{: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);"}}
</p>
</fieldset>
<p class="submit">
{{:button type="submit" shape="right" name="save" label="Enregistrer" class="main"}}
</p>
</form>
+63
View File
@@ -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}}
+40
View File
@@ -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}}
<p class="block confirm">Configuration enregistrée.</p>
{{/if}}
{{* lecture config *}}
{{:include file="../_get_config.html" keep="loan_duration"}}
<form method="post" action="" data-focus="1">
<fieldset>
<legend>Autres paramètres</legend>
<dl>
{{: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"}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{:admin_footer}}
+123
View File
@@ -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}}
<form method="post" action="" data-focus="1">
<fieldset>
<legend>Paramètres</legend>
<dl>
{{if $label_mod}}
{{:input type="text" name="name" label="Libellé" default=$default_label required=true maxlength="100"}}
{{/if}}
{{if $sortie_temp}}
<div>
{{: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}}
</div>
{{/if}}
</dl>
{{if $sortie_temp}}
<div class="help block">
<h3>Tarification</h3>
<ul>
<li>Une sortie temporaire gratuite sera classée dans l'onglet Prêt</li>
<li>Une sortie temporaire payante sera classée dans l'onglet Locations</li>
</ul>
</div>
{{/if}}
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</fieldset>
</form>
+96
View File
@@ -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}}
<p class="block confirm">{{$_GET.msg}}</p>
{{/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}}
<form method="post" action="" data-focus="1">
<fieldset>
<legend>Réservations</legend>
<dl>
{{: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}}
</dl>
<dl>
{{: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 !)"}}
</dl>
<dl>
{{: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"}}
</dl>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</fieldset>
<fieldset>
<legend>Import données depuis le module Gestion de Matériel</legend>
<dl>
{{:button type="submit" name="import" label="Importer" shape="right" class="main"}}
</dl>
</fieldset>
</form>
{{*:debug mod=$module.config*}}
{{:admin_footer}}
+44
View File
@@ -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"
}
]
}
+61
View File
@@ -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"]
}
+379
View File
@@ -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"}}
<p class="block confirm">Modification enregistrée</p>
{{elseif $_GET.msg == "copie"}}
<p class="block confirm">Mouvement copié</p>
{{elseif $_GET.msg == "retour"}}
<p class="block confirm">Retour enregistré</p>
{{elseif $_GET.msg == "suppression"}}
<p class="block confirm">Mouvement supprimé</p>
{{else}}
<p class="block confirm">Mouvement enregistré</p>
{{/if}}
{{elseif $_GET.err}}
{{if $_GET.msg == "suppression"}}
<p class="block error">Ce mouvement ne peut être supprimé</p>
{{/if}}
{{/if}}
<fieldset class="shortFormRight">
<legend>Filtrer par appartenance</legend>
{{:dropdown
title="Filtrer par appartenance"
options=$prop_options
value="%s"|args:$selected_prop
}}
</fieldset>
{{* 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}}
<tr>
<td>{{$date|date_short}}</td>
<td>{{$col2}}</td>
<td class="nosort">{{$op_label}}</td>
<td class="num">{{$amount}}</td>
{{if $selected_prop == null || $selected_prop}}
<td class="num nosort">{{$stock}}</td>
<td class="num nosort">{{$exterieur}}</td>
<td class="num nosort">{{$dispo}}</td>
{{/if}}
{{if $selected_prop == null || ! $selected_prop}}
<td class="num nosort">{{$tempo}}</td>
{{/if}}
{{if $selected_prop == null || $selected_prop}}
<td>{{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$user_details}}</td>
{{/if}}
<td>{{$storage}}</td>
<td class="num nosort">{{if $nb_files > 0}}{{$nb_files}}{{/if}}</td>
<td class="num">{{if $transactions|count > 0}}{{"Oui"}}{{/if}}</td>
<td class="actions">
{{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}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun matériel.</p>
{{/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}}
<script type="text/javascript" src="scripts.js"></script>
<script type="text/javascript">
(function () {
let table = document.querySelector("table[class=list]");
if (table != null) {
disableColumSort(table);
}
})();
</script>
+193
View File
@@ -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}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
{{: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"}}
<fieldset class="shortFormRight">
<legend>Filtrer par appartenance</legend>
{{:dropdown
title="Filtrer par appartenance"
options=$prop_options
value="%s"|args:$selected_prop
}}
</fieldset>
<div class="shortFormLeft">
<p class="help">Historique de tous les mouvements de matériel</p>
</div>
{{* 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}}
<tr>
<td>{{$date|date_short}}</td>
<td>{{$col2}}</td>
<td class="nosort">{{$op_label}}</td>
<td>{{$col4}}</td>
<td class="num">{{$amount}}</td>
<td>{{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$col6}}</td>
<td>{{$col7}}</td>
<td>{{$comment}}</td>
<td></td>
</tr>
{{else}}
<p class="block alert">Aucun mouvement.</p>
{{/list}}
{{:admin_footer}}
<script type="text/javascript" src="scripts.js"></script>
<script type="text/javascript">
(function () {
let table = document.querySelector("table[class=list]");
if (table != null) {
disableColumSort(table);
}
})();
</script>
+1108
View File
File diff suppressed because it is too large. Load diff

After

Width:  |  Height:  |  Size: 81 KiB

+67
View File
@@ -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="./_resa_inventory.html" keep="_GET.prop"}}
{{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" }}
<p class="block confirm">Ajout effectué</p>
{{elseif $_GET.msg == "modification" }}
<p class="block confirm">Modification effectuée</p>
{{elseif $_GET.msg == "suppression" }}
<p class="block confirm">Suppression effectuée</p>
{{elseif $_GET.msg == "supprmvtmat" }}
<p class="block confirm">Mouvement supprimé - Matériel supprimé</p>
{{/if}}
{{elseif $_GET.err}}
<p class="block error">Modification refusée</p>
{{/if}}
{{if $result.count == 0}}
<p class="block alert">Il n'y a aucune catégorie : vous devez en ajouter.</p>
{{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}}
+199
View File
@@ -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"}}
<p class="block confirm">Modification enregistrée</p>
{{elseif $_GET.msg == "copie"}}
<p class="block confirm">Mouvement copié</p>
{{elseif $_GET.msg == "suppression"}}
<p class="block confirm">Mouvement supprimé</p>
{{/if}}
{{elseif $_GET.err}}
{{if $_GET.msg == "suppression"}}
<p class="block error">Ce mouvement ne peut être supprimé</p>
{{/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}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
{{: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}}
<table class="list">
<thead>
<tr>
<td>Matériel</td>
<td>Date prêt</td>
<td>Quantité</td>
<td>Membre</td>
<td>Date retour</td>
<td>Reste à rendre</td>
<td>Remarque</td>
<td class="actions"></td>
</tr>
</thead>
<tbody>
{{: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}}
<tr>
<td>{{$mat_name}}</td>
<td>{{$out_date|date_short}}</td>
<td>{{$out_amount}}</td>
<td>{{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$nom}}</td>
<td>{{$return_date|date_short}}</td>
<td>{{$remain}}</td>
<td>
{{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}}
</td>
<td class="actions">
{{: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"
}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun mouvement.</p>
{{/select}}
</tbody>
</table>
{{else}}
<p class="block alert">Aucun mouvement.</p>
{{/if}}
{{:admin_footer}}
+230
View File
@@ -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"}}
<p class="block confirm">Modification enregistrée</p>
{{elseif $_GET.msg == "copie"}}
<p class="block confirm">Mouvement copié</p>
{{elseif $_GET.msg == "suppression"}}
<p class="block confirm">Mouvement supprimé</p>
{{/if}}
{{elseif $_GET.err}}
{{if $_GET.msg == "suppression"}}
<p class="block error">Ce mouvement ne peut être supprimé</p>
{{/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}}
<fieldset class="shortFormRight">
<legend>Filtrer par catégorie</legend>
{{:dropdown
title="Filtrer par catégorie"
options=$cat_options
value="%s"|args:$selected_category
}}
</fieldset>
{{* 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}}
<table class="list">
<thead>
<tr>
<td>Date</td>
<td>Mouvement</td>
<td>Opération</td>
<td>Matériel</td>
<td class="num">Quantité</td>
<td>Dépositaire</td>
<td>Stockage</td>
<td>Documents</td>
<td>Écritures</td>
<td>Remarque</td>
<td class="actions"></td>
</tr>
</thead>
<tbody>
{{:assign premier=false}}
{{/if}}
<tr>
<td>{{$date|date_short}}</td>
<td>{{if $direction == "input"}}Entrée{{else}}Sortie{{/if}}</td>
<td>{{$op_label}}</td>
<td>{{$materiel}}</td>
<td class="num">{{$amount}}</td>
<td>{{:link href="/admin/users/details.php?id=%s"|args:$user_id label="%s"|args:$user}}</td>
<td>{{$stockage}}</td>
<td class="num">{{if $nb_files > 0}}{{$nb_files}}{{/if}}</td>
<td class="num">{{if $transactions != null}}{{"Oui"}}{{/if}}</td>
<td>{{$comment}}</td>
<td class="actions">
{{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"
}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun mouvement.</p>
{{/select}}
</tbody>
</table>
{{else}}
<p class="block alert">Aucun mouvement.</p>
{{/if}}
{{:admin_footer}}
+129
View File
@@ -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}}
<h3>Historique des mouvements de « {{$eqpmt_name}} » du membre « {{$user_name}} »</h3>
{{: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}}
</tbody>
</table>
{{/if}}
{{if $otk == null || $otk != $out_temp_key}}
<table class="list">
<thead>
<tr>
<td>Date</td>
<td>Opération</td>
<td>Quantité</td>
<td>Total</td>
<td class="actions"></td>
</tr>
</thead>
<tbody>
{{: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}}
<tr>
<td>{{$date|date_short}}</td>
<td>{{$op_label}}</td>
<td>{{$amount}}</td>
<td>{{$total}}</td>
<td class="actions">
{{#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}}
</td>
</tr>
{{/select}}
</tbody>
</table>
+105
View File
@@ -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}}
<table class="list">
<thead>
<tr>
<td>Membre</td>
<td class="nombre">Quantité</td>
<td>Matériels</td>
</tr>
</thead>
<tbody>
{{:assign premier=false}}
{{/if}}
<tr>
<td>{{:link href="/admin/users/details.php?id=%s"|args:$user label="%s"|args:$nom}}</td>
<td class="nombre">{{$quantite}}</td>
<td>{{$materiel}}</td>
</tr>
{{else}}
{{if $label == "prêt"}}
<p class="block alert">Aucun {{$label}} en cours.</p>
{{elseif $label == "location"}}
<p class="block alert">Aucune {{$label}} en cours.</p>
{{/if}}
{{/select}}
</tbody>
</table>
{{else}}
{{if $label == "prêt"}}
<p class="block alert">Aucun {{$label}} en cours.</p>
{{elseif $label == "location"}}
<p class="block alert">Aucune {{$label}} en cours.</p>
{{/if}}
{{/if}}
{{:admin_footer}}
+234
View File
@@ -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}}
<form method="post" action="">
<fieldset class="modification">
<legend>Modifier un matériel</legend>
<dl>
{{: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"}}
</dl>
<legend>Champs Personnalisés</legend>
<dl>
{{#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}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{* 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}}
+10
View File
@@ -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
+44
View File
@@ -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}}
+234
View File
@@ -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 *}}
<form method="post" action="">
<fieldset class="entree">
<legend>Informations obligatoires</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<fieldset>
<legend>Autres informations</legend>
<dl>
{{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*}}
</dl>
</fieldset>
<fieldset>
<legend>Champs Personnalisés</legend>
<dl>
{{#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}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{else}}
<p class="block error">Il n'y a aucune catégorie, il faut en créer au moins une</p>
{{/if}}
{{:admin_footer}}
+362
View File
@@ -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 *}}
<form method="post" action="">
<fieldset class="informations">
<legend>Matériel</legend>
<dl class="describe">
<dt>Désignation</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$category.name}}</dd>
</dl>
</fieldset>
<fieldset>
<legend>Informations obligatoires</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<fieldset class="entree">
<legend>Autres informations</legend>
<dl>
{{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}}
<div id="div_return_date">
{{:input type="date" name="return_date" label="Date de retour" default=$return_date}}
<input type="hidden" id="loan_duration" name="loan_duration" value="{{$module.config.loan_duration}}">
</div>
{{/if}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{:admin_footer}}
<script type="text/javascript" src="../scripts.js"></script>
<script type="text/javascript">
let output_nature = {{$config.output_nature|json_encode|raw}};
function changeVisibility(evt,
id_date = 'f_date',
id_type = 'f_operation',
div = 'div_return_date',
id_return_date = 'f_return_date')
{
toggleVisibility(id_date, id_type, div, id_return_date);
}
function changeReturnDate(evt, id_date = 'f_date', id_return_date = 'f_return_date', id_loan_duration='loan_duration')
{
setReturnDate(id_date, id_return_date, id_loan_duration);
}
(function () {
document.getElementById('f_operation').onchange = changeVisibility;
document.getElementById('f_date').onchange = changeReturnDate;
document.getElementById('f_operation').onchange();
})();
</script>
+192
View File
@@ -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}}
+139
View File
@@ -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}}
<form method="post" action="">
<fieldset class="informations">
<legend>Matériel</legend>
<dl class="describe">
<dt>Désignation</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$category.name}}</dd>
</dl>
</fieldset>
<fieldset class="entree">
<legend>Informations obligatoires</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<fieldset class="entree">
<legend>Autres informations</legend>
<dl>
{{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}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{:admin_footer}}
+239
View File
@@ -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}}
<form method="post" action="">
<fieldset class="informations">
<legend>Matériel</legend>
<dl class="describe">
<dt>Désignation</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$category.name}}</dd>
<dt>Quantité disponible</dt>
<dd class="num">{{$present}}</dd>
</dl>
</fieldset>
<fieldset>
<legend>Retour de matériel</legend>
<dl>
{{: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}}
<input type="hidden" id="resa_key" name="resa_key" value="{{$resa.key}}">
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{:admin_footer}}
+23
View File
@@ -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"]
}
+381
View File
@@ -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 *}}
<form method="post" action="">
<fieldset class="informations">
<legend>Matériel</legend>
<dl class="describe">
<dt>Désignation</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$category.name}}</dd>
{{if $mvt_new.transactions != null}}
<dt>Écritures liées</dt>
<dd>
{{#foreach from=$mvt_new.transactions item="trans"}}
{{:link class="num" href="!acc/transactions/details.php?id=%d"|args:$trans label=$trans}}
{{/foreach}}
</dd>
{{/if}}
</dl>
</fieldset>
<fieldset>
<legend>Informations obligatoires</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<fieldset class="entree">
<legend>Autres informations</legend>
<dl>
{{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}}
<div id="div_return_date">
{{:input type="date" name="return_date" label="Date de retour" default=$return_date}}
<input type="hidden" id="loan_duration" name="loan_duration" value="{{$module.config.loan_duration}}">
</div>
{{/if}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{:admin_footer}}
<script type="text/javascript" src="../scripts.js"></script>
<script type="text/javascript">
let output_nature = {{$config.output_nature|json_encode|raw}};
function changeVisibility(evt,
id_date = 'f_date',
id_type = 'f_operation',
div = 'div_return_date',
id_return_date = 'f_return_date')
{
toggleVisibility(id_date, id_type, div, id_return_date);
}
function changeReturnDate(evt, id_date = 'f_date', id_return_date = 'f_return_date', id_loan_duration='loan_duration')
{
setReturnDate(id_date, id_return_date, id_loan_duration);
}
(function () {
document.getElementById('f_operation').onchange = changeVisibility;
document.getElementById('f_date').onchange = changeReturnDate;
document.getElementById('f_operation').onchange();
})();
</script>
+57
View File
@@ -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"]
}
+119
View File
@@ -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}}
<nav class="tabs">
{{:linkbutton
label="Modifier ce mouvement"
href="modify_movement.html?key=%s&from=%s"|args:$_GET.key:$_GET.from
shape="edit"
target="_dialog"}}
{{:linkbutton
label="Supprimer ce mouvement"
href="delete_movement.html?key=%s&prop=%s&from=%s"|args:$_GET.key:$_GET.prop:$_GET.from
shape="delete"
target="_dialog"}}
{{if $type_mvt != "retour"}}
{{:linkbutton
label="Dupliquer ce mouvement"
href="copy_movement.html?key=%s&prop=%s&from=%s"|args:$_GET.key:$_GET.prop:$_GET.from
shape="plus"
target="_dialog"}}
{{/if}}
</nav>
<dl class="describe">
<dt>Opération</dt>
<dd>{{$op_label}}</dd>
<dt>Matériel</dt>
<dd>{{:link href="../equipment_history.html?key=%s&prop=%s"|args:$equipment.key:$_GET.prop label=$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{:link href="../index.html?cat_key=%s&prop=%s"|args:$category.key:$_GET.prop label=$category.name}}</dd>
<dt>Date</dt>
<dd>{{$mvt.date|date_short}}</dd>
<dt>Quantité</dt>
<dd>{{$mvt.amount}}</dd>
{{if $mvt.direction == "output" && $type_mvt != "retour"}}
<dt>Membre destinataire</dt>
<dd>
{{if $mvt.user != null}}
{{:link href="/admin/users/details.php?id=%s"|args:$mvt.user label=$user_name}}
{{else}}—
{{/if}}
</dd>
{{/if}}
{{if $mvt.direction == "input"}}
<dt>Lieu de stockage</dt>
<dd>
{{if $storage != null}}
{{$storage.name}}
{{else}}—
{{/if}}
</dd>
{{/if}}
<dt>Écritures liées</dt>
<dd>
{{#foreach from=$mvt.transactions item="trans"}}
{{:link class="num" href="!acc/transactions/details.php?id=%d"|args:$trans label=$trans}}
{{else}}—
{{/foreach}}
</dd>
{{if $mvt.direction == "output" && $type_mvt != "retour"}}
<dt>Date de retour</dt>
<dd>
{{if $mvt.return_date != null}}
{{$mvt.return_date|date_short}}
{{else}}—
{{/if}}
</dd>
{{/if}}
<dt>Remarques</dt>
<dd>{{if $mvt.comment != null}}
{{$mvt.comment}}
{{else}}—
{{/if}}
</dd>
</dl>
{{:admin_files path=$mvt.key upload=true edit=true use_trash=false}}
{{:admin_footer}}
+338
View File
@@ -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 *}}
<form method="post" action="">
<fieldset class="informations">
<legend>Matériel</legend>
<dl class="describe">
<dt>Matériel</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$category.name}}</dd>
<dt>Quantité disponible</dt>
<dd class="num">{{$dispo}}</dd>
</dl>
</fieldset>
<fieldset class="sortie">
<legend>Informations obligatoires</legend>
<dl>
{{: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}}
<input type="hidden" id="resa_key" name="resa_key" value="{{$resa.key}}">
{{else}}
<div id="div_return_date">
{{:input type="date" id="return_date" name="return_date" label="Date de retour" default=$date_retour}}
<input type="hidden" id="loan_duration" name="loan_duration" value="{{$module.config.loan_duration}}">
</div>
{{/if}}
</dl>
</fieldset>
<fieldset class="entree">
<legend>Autres informations</legend>
<dl>
{{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}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{else}}
<p class="block error">Il n'y a aucune unité de ce matériel disponible à la date du {{$now|date_short}}</p>
{{/if}}
{{:admin_footer}}
<script type="text/javascript" src="../scripts.js"></script>
{{if !$nbdejours}}
<script type="text/javascript">
let output_nature = {{$config.output_nature|json_encode|raw}};
function changeVisibility(evt,
id_date = 'f_date',
id_type = 'f_operation',
div = 'div_return_date',
id_return_date = 'f_return_date')
{
toggleVisibility(id_date, id_type, div, id_return_date);
}
function changeReturnDate(evt, id_date = 'f_date', id_return_date = 'f_return_date', id_loan_duration='loan_duration')
{
setReturnDate(id_date, id_return_date, id_loan_duration);
}
(function () {
document.getElementById('f_operation').onchange = changeVisibility;
document.getElementById('f_date').onchange = changeReturnDate;
document.getElementById('f_operation').onchange();
})();
</script>
{{/if}}
+268
View File
@@ -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}}
<form method="post" action="">
<fieldset class="informations">
<legend>Matériel</legend>
<dl class="describe">
<dt>Désignation</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$category.name}}</dd>
<dt>Quantité disponible</dt>
<dd class="num">{{$exterieur}}</dd>
</dl>
</fieldset>
<fieldset>
<legend>Informations obligatoires</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<fieldset class="entree">
<legend>Autres informations</legend>
<dl>
{{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}}
<input type="hidden" id="resa_key" name="resa_key" value="{{$resa.key}}">
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{:admin_footer}}
+7
View File
@@ -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*}}
+215
View File
@@ -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*}}
<div class="shortFormLeft">
<p class="help">Inventaire des réservations effectuées</p>
</div>
<fieldset class="shortFormRight">
<legend>Filtrer par status</legend>
{{:dropdown
title="Filtrer par status"
options=$st_options
value="%s"|args:$selected_status|strval
}}
</fieldset>
{{* ------------------ 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"}}
<p class="help">Légende : <br/>
{{:icon shape="globe"}} : réservation issue de la page publique<br/>
{{:icon shape="print"}} : réservation issue de la page membre<br/>
{{:icon shape="alert"}} : signature du contrat requise lors du retrait du matériel
</p>
{{* Liste des réservations *}}
{{:include file="_resa_load.html" keep="_resa_lignes"}}
{{*:debug lignes=$_resa_lignes*}}
<table class="list">
<thead class="userOrder">
<tr>
<td></td>
<td class="num">N° de membre</td>
<td>Nom</td>
<td>Téléphone</td>
<td>Matériel</td>
<td>Quantité souhaitée</td>
<td>Date souhaitée</td>
<td>Retour prévu/réel</td>
<td>Commentaire additionnel</td>
<td>Statut de la demande</td>
<td class="actions"></td>
</tr>
</thead>
<tbody>
{{#foreach from=$_resa_lignes}}
<tr>
<td><span class="tag" style="--tag-color:darkblue; color:white; white-space:nowrap;">{{:icon shape="%s"|args:$shape}} {{if !$signed}} {{:icon shape="alert"}}{{/if}}</span></td>
<td>{{$member}}</td>
<td>{{$name}}</td>
<td>{{$contact}}</td>
{{#load key="%s"|args:$equipment}}{{:assign var="equipment.name" value=$name}}{{/load}}
<td>{{$equipment.name}}</td>
<td>{{$amount}}</td>
<td>{{* Si acceptée et date de retrait aujourd'hui *}}
{{if $status == "acceptée" && $loan_date|parse_date == $now|date:'Y-m-d'}}
<span class="tag" style="--tag-color:lightgreen; color:black;">{{$loan_date|date_short}}</span>
{{else}}
{{$loan_date|date_short}}
{{/if}}
</td>
<td>{{* Si an cours et date de retour aujourd'hui *}}
{{if $status == "en cours" && $return_date|parse_date == $now|date:'Y-m-d'}}
<span class="tag" style="--tag-color:lightblue; color:black;">{{$return_date|date_short}}</td></span>
{{else}}
{{$return_date|date_short}}</td>
{{/if}}
<td>{{$comment}}</td>
<td>{{:include file="./_resa_status_color.html" status='%s'|args:$status|or:null}}</td>
<td class="actions">
{{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}}
</td>
</tr>
{{/foreach}}
</tbody>
</table>
{{/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*}}
<script>
document.addEventListener('DOMContentLoaded', function() {
var initialLocaleCode = 'fr'
const calendarEl = document.getElementById('calendar')
const calendar = new FullCalendar.Calendar(calendarEl, {
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,dayGridWeek,dayGridDay,listMonth'
},
aspectRatio: 2,
locale: initialLocaleCode,
buttonIcons: false, // show the prev/next text
weekNumbers: true,
navLinks: true, // can click day/week names to navigate views
editable: false,
dayMaxEvents: true, // allow "more" link when too many events
events: [
{{$_events|raw}}
]
})
calendar.render()
})
</script>
<fieldset>
<legend>Calendrier des réservations</legend>
<div id='calendar'></div>
</fieldset>
{{/if}}
{{:admin_footer}}
+13
View File
@@ -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}}
+76
View File
@@ -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"]
}
+91
View File
@@ -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}}
<p class="alert">L'adresse e-mail indiquée est invalide.</p>
{{/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}}
<p>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.</p>
{{if $_non_member ==true }}
<p>Veuillez maintenant créer ce membre.</p>
{{/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 -------------------- *}}
<form method="post" action="">
<fieldset class="entree">
<legend>pour ce matériel : {{$equipment.name}} ({{$category.name}})</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{/if}}
+38
View File
@@ -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
}}
<p class="info">La réservation est maintenant archivée. Cliquer {{:link href="archive_reservation.html?ok=%s"|args:$resa.key label="ici"}} pour terminer.</p>
{{else}}
<p class="error">Erreur : La réservation n'a pas pu être archivée.</p>
{{/if}}
+102
View File
@@ -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}}
<p class="alert">L'adresse e-mail indiquée est invalide.</p>
{{/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}}
<p>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.</p>
{{if $_non_member ==true }}
<p>Veuillez maintenant créer ce membre.</p>
{{/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 -------------------- *}}
<form method="post" action="">
<fieldset class="entree">
<legend>pour ce matériel : {{$equipment.name}} ({{$category.name}})</legend>
<dl>
{{: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}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
{{/if}}
+119
View File
@@ -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
*}}
<div class="shortFormLeft">
<p class="help">Légende : <br/>
{{:icon shape="globe"}} : réservation issue de la page publique<br/>
{{:icon shape="print"}} : réservation issue de la page membre<br/>
</p>
<p class="alert">{{:icon shape="alert"}} : Il n'y a pas de confirmation lors de la suppression de réservations !</p>
</div>
{{* 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}}
<h3>Confirmer la suppression ?</h3>
{{#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}}
<form method="post" action="">
{{: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}}
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
*}}
{{else}}
{{* Liste des réservations *}}
{{:include file="../_resa_load.html" keep="_resa_lignes"}}
<form method="post"> {{*data-disable-progress="1"*}}
<table class="list">
<thead class="userOrder">
<tr>
<td></td>
<td>Source</td>
<td class="num">N° de membre</td>
<td>Nom</td>
<td>Téléphone</td>
<td>Matériel</td>
<td>Quantité souhaitée</td>
<td>Date souhaitée</td>
<td>Date retour prévue</td>
<td>Commentaire additionnel</td>
<td>Statut de la demande</td>
</tr>
</thead>
<tbody>
{{#foreach from=$_resa_lignes}}
<tr>
<td>{{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}}
</td>
<td>{{:icon shape="%s"|args:$shape}}</td>
<td>{{$member}}</td>
<td>{{$name}}</td>
<td>{{$contact}}</td>
<td>{{#load key="%s"|args:$equipment}}{{$name}}{{/load}}</td>
<td>{{$amount}}</td>
<td>{{$loan_date|date_short}}</td>
<td>{{$return_date|date_short}}</td>
<td>{{$comment}}</td>
<td>{{:include file="../_resa_status_color.html" status='%s'|args:$status|or:null}}</td>
</tr>
{{/foreach}}
</tbody></table>
<p class="submit">
{{:button type="submit" name="delete" label="Supprimer" shape="right" class="main"}}
</p>
</form>
{{/if}}
+11
View File
@@ -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}}
+195
View File
@@ -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"}}
<div class="shortFormLeft">
<p class="help">Détails d'une réservation</p>
<p class="help">Légende : <br/>
{{:icon shape="globe"}} : réservation issue de la page publique<br/>
{{:icon shape="print"}} : réservation issue de la page membre<br/>
{{:icon shape="alert"}} : signature du contrat requise lors du retrait du matériel
</p>
</div>
{{* 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}}
<div class="shortFormLeft">
<p class="alert">{{:icon shape="alert"}} Vous devez sélectionner ou créer un membre avant de pouvoir traiter cette réservation</p>
</div>
{{/if}}
<nav class="tabs">
<aside>
{{if $equipment_resa.status == null }}
{{* réservation non trouvée dans le module equipment*}}
{{:assign var="equipment_resa.status" value="%s"|args:$resa.status}}
{{/if}}
{{if $equipment_resa.status == "acceptée" || $equipment_resa.status == "en cours" || $equipment_resa.status == "refusée"}}
{{* Ne pas permettre d'archiver des réservations au status acceptée/en cours/refusée si la date n'est pas passée et le retour non effectué *}}
{{if $resa.return_date|parse_date < $now|date:'Y-m-d' && !$resa.mvt_key}}
{{:linkbutton label="Archiver cette réservation" href="archive_reservation.html?key=%s&eid=%d"|args:$_GET.key:$equipment.id shape="lock" target="_dialog"}}
{{/if}}
{{if $equipment_resa.status == "acceptée"}}
{{if $resa.signed}}
{{:linkbutton label="Retrait du matériel" href="../movements/output_equipment.html?key=%s&reskey=%s"|args:$equipment.key:$resa.key shape="export" target="_dialog"}}
{{else}}
{{:linkbutton label="Signer le contrat puis retrait du matériel" href="./resa_contract.html?rid=%s"|args:$resa.id shape="export" target="_dialog"}}
{{/if}}
{{elseif $equipment_resa.status == "en cours"}}
{{* TODO : check input_return vs output_return *}}
{{:linkbutton label="Retour du matériel" href="../movements/output_return.html?key=%s&reskey=%s"|args:$resa.mvt_key:$resa.key shape="import" target="_dialog"}}
{{:linkbutton label="Mouvements du matériel" href="../equipment_history.html?key=%s&reskey=%s"|args:$equipment.key:$resa.key shape="table"}}
{{/if}}
{{elseif $equipment_resa.status == "archivée"}}
{{* Ne rien faire dans ce cas *}}
{{else}}
{{* Si la date est périmée, ne permettre que d'archiver cette réservation *}}
{{if $resa.loan_date|parse_date > $now|date:'Y-m-d' }}
{{if $resa.member >= 1}}
{{:linkbutton label="Accepter cette réservation" href="accept_reservation.html?key=%s&eid=%d"|args:$_GET.key:$equipment.id shape="edit" target="_dialog"}}
{{:linkbutton label="Refuser cette réservation" href="decline_reservation.html?key=%s&eid=%d"|args:$_GET.key:$equipment.id shape="delete" target="_dialog"}}
{{*:linkbutton label="Archiver cette réservation" href="archive_reservation.html?key=%s&eid=%d"|args:$_GET.key:$equipment.id shape="lock" target="_dialog"*}}
{{/if}}
{{else}}
{{:assign var="equipment_resa.status" value="périmée"}}
{{:linkbutton label="Archiver cette réservation" href="archive_reservation.html?key=%s&eid=%d"|args:$_GET.key:$equipment.id shape="lock" target="_dialog"}}
{{/if}}
{{/if}}
{{:linkbutton label="Corriger" href="temp_correction.html?key=%s"|args:$_GET.key shape="plus" target="_dialog"}}
</aside>
</nav>
<dl class="describe">
<dt>Source</dt><dd>{{:icon shape="%s"|args:$resa.source}}</dd>
<dt>Status</dt>
{{:include file="../_resa_status_color.html" status='%s'|args:$equipment_resa.status|or:null}}
<dt>Nom</dt><dd>{{$resa.name}}</dd>
<dt>Contact</dt><dd>{{$resa.contact}}</dd>
<dt>Courriel</dt><dd>{{$resa.email}}</dd>
<dt>Adresse postale</dt><dd>{{$resa.address}}</dd>
<dt>Matériel</dt><dd>{{:link href="../equipment_history.html?key=%s&prop=%s"|args:$equipment.key:$_GET.prop label=$equipment.name}}</dd>
<dt>Catégorie</dt><dd>{{:link href="../index.html?cat_key=%s&prop=1"|args:$category.key label=$category.name}}</dd>
<dt>Date de la demande</dt><dd>{{$resa.date|date_short}}</dd>
<dt>Quantité</dt><dd>{{$resa.amount}}</dd>
<dt>Membre associé</dt>
<dd>{{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}}
<form method="post" action="">
{{: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"}}
</form>
{{:linkbutton href="!users/new.php" label="Créer un nouveau membre" target="_dialog" shape="plus"}}
{{/if}}
</dd>
<dt>Date souhaitée</dt><dd>
{{$resa.loan_date|date_short}}
{{if $resa.loan_date|parse_date == $now|date:'Y-m-d'}}
{{:tag color="darkgreen" label="À retirer aujourd'hui"}}
{{/if}}
</dd>
<dt>Retour prévu/réel</dt><dd>
{{$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}}
</dd>
<dt>Signature contrat</dt><dd>{{if $resa.signed != null}}{{$resa.signed}}{{else}}{{:icon shape="alert"}} À faire au retrait!{{/if}}</dd>
<dt>Remarques</dt>
<dd>{{if $resa.comment != null}}{{$resa.comment}}{{else}}—{{/if}}</dd>
</dl>
{{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}}
+114
View File
@@ -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*}}
<form method="post" action="">
<fieldset class="entree">
<legend>Demande de réservation de matériel : {{$equipment.name}} ({{$category.name}})</legend>
<dl>
{{#foreach from=$resa key="key" item="value"}}
{{:assign required=false}}
<dd>
{{*: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*}}
</dd>
{{/foreach}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Étape suivante" shape="right" class="main"}}
</p>
</form>
+75
View File
@@ -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;
}
}
+253
View File
@@ -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}}
<h3 class="ruler">Matériels attribués temporairement</h3>
<table class="list" id="liste_temporaires">
<thead>
<tr>
<th>Date</th>
<th>Matériel</th>
<th>Quantité</th>
<th>Date de retour</th>
<th>Remarque</th>
<th class="actions">
</tr>
</thead>
<tbody>
{{#foreach from=$lignes}}
<tr>
<td>{{$date|date_short}}</td>
<td>{{$materiel}}</td>
<td>{{$qte}}</td>
<td>{{$return_date|date_short}}</td>
<td>
{{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}}
</td>
<td class="actions">
{{:linkbutton
label="Historique"
href="%smember_history.html?key=%s&id=%s"|args:$module.url:$eqpmt_key:$user.id
shape="table"
target="_dialog"
}}
</td>
</tr>
{{/foreach}}
</tbody>
</table>
{{/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}}
<h3 class="ruler">Matériels attribués définitivement</h3>
<table class="list">
<thead>
<tr>
<th>Date</th>
<th>Matériel</th>
<th>Opération</th>
<th>Quantité</th>
</tr>
</thead>
<tbody>
{{#foreach from=$def_mat}}
{{:assign var="op_label" from="config.%s_nature.%s.label"|args:$direction:$operation}}
<tr>
<td>{{$date|date_short}}</td>
<td>{{$eqpmt_name}}</td>
<td>{{$op_label}}</td>
<td>{{$amount}}</td>
</tr>
{{/foreach}}
</tbody>
</table>
{{/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}}
<h3 class="ruler">Mes réservations</h3>
<table class="list">
<thead>
<tr>
<th>Date</th>
<th>Matériel</th>
<th>Date de début</th>
<th>Date de retour</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{{#foreach from=$my_reservations}}
<tr>
<td>{{$date|date_short}}</td>
{{* Charge le matériel *}}
{{#load key=$equipment assign="equipment"}}{{/load}}
<td>{{$equipment.name}}</td>
<td>{{$loan_date|date_short}}</td>
<td>{{$return_date|date_short}}</td>
{{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}}
<td><span class="tag" style="{{$_tag_color}}">{{$status}}</span></td>
</tr>
{{/foreach}}
</tbody>
</table>
{{/if}}
{{/if}}
+3
View File
@@ -0,0 +1,3 @@
{{* -*- brindille -*- *}}
{{:include file="./_details.html"}}
+3
View File
@@ -0,0 +1,3 @@
{{* -*- brindille -*- *}}
{{:include file="./_details.html"}}
+4
View File
@@ -0,0 +1,4 @@
{{* -*- brindille -*- *}}
{{#restrict section="users" level="read"}}{{/restrict}}
{{:include file="./_details.html"}}
+45
View File
@@ -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}}
<form method="post" action="" data-focus="1">
<fieldset class="storage">
<legend>Ajouter un lieu de stockage</legend>
<dl>
{{:input type="text" name="name" label="Nom" required=true}}
{{:input type="textarea" name="location" label="Emplacement" cols="40" rows="3" required=false}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>
+32
View File
@@ -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
}}
+46
View File
@@ -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"}}
<p class="block confirm">Ajout effectué</p>
{{elseif $_GET.msg == "suppression"}}
<p class="block confirm">Suppression effectuée</p>
{{/if}}
{{elseif $_GET.err}}
{{if $_GET.msg == "suppression"}}
<p class="block error">Impossible de supprimer ce lieu de stockage car il est utilisé !</p>
{{else}}
<p class="block error">Opération refusée</p>
{{/if}}
{{/if}}
{{#list
type="storage"
select="
$$.name AS 'Nom';
$$.location AS 'Emplacement'
"
}}
<tr>
<td>{{$name}}</td>
<td>{{$location}}</td>
<td class="actions">
{{: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"}}
</td>
</tr>
{{else}}
<p class="block alert">Aucun lieu de stockage.</p>
{{/list}}
{{:admin_footer}}
+55
View File
@@ -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 *}}
<form method="post" action="" data-focus="1">
<fieldset class="modif_storage">
<legend>Modifier le lieu de stockage « {{$storage.name}} »</legend>
<dl>
{{: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}}
</dl>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</fieldset>
</form>
+19
View File
@@ -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"]
}
+30
View File
@@ -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;
}
+53
View File
@@ -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}}
<form method="post" action="">
<fieldset class="informations">
<legend>Désarchiver un matériel</legend>
<dl class="describe">
<dt>Matériel</dt>
<dd>{{$equipment.name}}</dd>
<dt>Catégorie</dt>
<dd>{{$cat_name}}</dd>
</dl>
<dl>
{{:input type="checkbox" value=1 name="unarchive" label="Archivé" checked="checked" help="décocher pour remettre le matériel en service"}}
</dl>
</fieldset>
<p class="submit">
{{:button type="submit" name="save" label="Enregistrer" shape="right" class="main"}}
</p>
</form>