2026-08-14 18:02:25 +02:00
{% extends "base.html" %}
{% block title %}{{ equipment.name }} — Modifier — GMAO{% endblock %}
{% block content %}
< div class = "container-fluid" >
< div class = "d-flex justify-content-between align-items-center mb-4" >
< div >
< nav aria-label = "breadcrumb" >
< ol class = "breadcrumb mb-1" >
< li class = "breadcrumb-item" > < a href = "{{ url_for('equipments.index') }}" > Équipements< / a > < / li >
< li class = "breadcrumb-item" > < a href = "{{ url_for('equipments.detail', id=equipment.id) }}" > {{ equipment.name }}< / a > < / li >
< li class = "breadcrumb-item active" > Modifier< / li >
< / ol >
< / nav >
< h1 class = "h3 mb-0" > Modifier l'équipement< / h1 >
< / div >
< a href = "{{ url_for('equipments.detail', id=equipment.id) }}" class = "btn btn-outline-secondary" >
< i class = "bi bi-arrow-left me-1" > < / i > Annuler
< / a >
< / div >
< ul class = "nav nav-tabs mb-3" id = "equipmentTabs" role = "tablist" >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link active" id = "info-tab" data-bs-toggle = "tab" data-bs-target = "#info" type = "button" >
< i class = "bi bi-info-circle me-1" > < / i > Informations
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "meters-tab" data-bs-toggle = "tab" data-bs-target = "#meters" type = "button" >
< i class = "bi bi-speedometer2 me-1" > < / i > Compteurs
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "consumables-tab" data-bs-toggle = "tab" data-bs-target = "#consumables" type = "button" >
< i class = "bi bi-box-seam me-1" > < / i > Consommables
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "documents-tab" data-bs-toggle = "tab" data-bs-target = "#documents" type = "button" >
< i class = "bi bi-file-earmark me-1" > < / i > Documents
< / button >
< / li >
< li class = "nav-item" role = "presentation" >
< button class = "nav-link" id = "history-tab" data-bs-toggle = "tab" data-bs-target = "#history" type = "button" >
< i class = "bi bi-clock-history me-1" > < / i > Historique
< / button >
< / li >
< / ul >
< div class = "tab-content" >
<!-- Onglet Informations -->
< div class = "tab-pane fade show active" id = "info" role = "tabpanel" >
< form method = "POST" action = "{{ url_for('equipments.edit', id=equipment.id) }}" >
< input type = "hidden" name = "csrf_token" value = "{{ csrf_token() }}" >
< div class = "row" >
< div class = "col-lg-8" >
< div class = "card mb-3" >
< div class = "card-header" >
< i class = "bi bi-pencil me-1" > < / i > Informations générales
< / div >
< div class = "card-body" >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "name" class = "form-label" > Nom *< / label >
< input type = "text" class = "form-control" id = "name" name = "name"
value="{{ equipment.name }}" required>
< / div >
< div class = "col-md-6" >
< label for = "code" class = "form-label" > Code / N° série< / label >
< input type = "text" class = "form-control" id = "code" name = "code"
value="{{ equipment.code or '' }}">
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "category_id" class = "form-label" > Catégorie< / label >
< select class = "form-select" id = "category_id" name = "category_id" >
< option value = "" > -- Sans catégorie --< / option >
{% for cat in categories %}
< option value = "{{ cat.id }}" { { ' selected ' if equipment . category_id = = cat . id else ' ' } } >
{{ cat.name }}
< / option >
{% endfor %}
< / select >
< / div >
< div class = "col-md-6" >
< label for = "lot_id" class = "form-label" > Lot< / label >
< select class = "form-select" id = "lot_id" name = "lot_id" >
< option value = "" > -- Sans lot --< / option >
{% for lot in lots %}
2026-08-15 01:37:17 +02:00
< option value = "{{ lot.id }}" data-category-id = "{{ lot.category_id or '' }}" { { ' selected ' if equipment . lot_id = = lot . id else ' ' } } >
2026-08-14 18:02:25 +02:00
{{ lot.name }}
< / option >
{% endfor %}
< / select >
2026-08-15 01:37:17 +02:00
< button type = "button" class = "btn btn-sm btn-outline-primary mt-2" id = "quick-add-lot" > < i class = "bi bi-plus-lg" > < / i > Créer un lot dans cette catégorie< / button >
2026-08-14 18:02:25 +02:00
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "room_id" class = "form-label" > Salle< / label >
< select class = "form-select" id = "room_id" name = "room_id" >
< option value = "" > -- Non localisé --< / option >
{% for building in buildings %}
< optgroup label = "{{ building.name }}" >
{% for room in building.rooms %}
< option value = "{{ room.id }}" { { ' selected ' if equipment . room_id = = room . id else ' ' } } >
{{ room.name }}
< / option >
{% endfor %}
< / optgroup >
{% endfor %}
< / select >
< / div >
< div class = "col-md-6" >
< label for = "status" class = "form-label" > Statut< / label >
< select class = "form-select" id = "status" name = "status" >
< option value = "en_service" { { ' selected ' if equipment . status = = ' en_service ' else ' ' } } > En service< / option >
< option value = "en_panne" { { ' selected ' if equipment . status = = ' en_panne ' else ' ' } } > En panne< / option >
< option value = "en_maintenance" { { ' selected ' if equipment . status = = ' en_maintenance ' else ' ' } } > En maintenance< / option >
< option value = "hs" { { ' selected ' if equipment . status = = ' hs ' else ' ' } } > Hors service< / option >
< option value = "a_jeter" { { ' selected ' if equipment . status = = ' a_jeter ' else ' ' } } > À jeter< / option >
< option value = "jete" { { ' selected ' if equipment . status = = ' jete ' else ' ' } } > Jeté< / option >
< / select >
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-4" >
< label for = "quantity" class = "form-label" > Quantité< / label >
< input type = "number" class = "form-control" id = "quantity" name = "quantity"
value="{{ equipment.quantity }}" min="1">
< / div >
< div class = "col-md-4" >
< div class = "form-check mt-4" >
< input type = "checkbox" class = "form-check-input" id = "is_group" name = "is_group"
{{ 'checked' if equipment.is_group else '' }}>
< label for = "is_group" class = "form-check-label" > Est un groupe< / label >
< / div >
< / div >
< div class = "col-md-4" >
< div class = "form-check mt-4" >
< input type = "checkbox" class = "form-check-input" id = "tracked_individually" name = "tracked_individually"
{{ 'checked' if equipment.tracked_individually else '' }}>
< label for = "tracked_individually" class = "form-check-label" > Suivi individuel< / label >
< / div >
< / div >
< / div >
< div class = "mb-3" >
< label for = "description" class = "form-label" > Description< / label >
< textarea class = "form-control" id = "description" name = "description" rows = "3" > {{ equipment.description or '' }}< / textarea >
< / div >
< / div >
< / div >
< div class = "card mb-3" >
< div class = "card-header" >
< i class = "bi bi-calendar me-1" > < / i > Dates
< / div >
< div class = "card-body" >
< div class = "row" >
< div class = "col-md-6" >
< label for = "install_date" class = "form-label" > Date d'installation< / label >
< input type = "date" class = "form-control" id = "install_date" name = "install_date"
value="{{ equipment.install_date.strftime('%Y-%m-%d') if equipment.install_date else '' }}">
< / div >
< div class = "col-md-6" >
< label for = "warranty_end" class = "form-label" > Fin de garantie< / label >
< input type = "date" class = "form-control" id = "warranty_end" name = "warranty_end"
value="{{ equipment.warranty_end.strftime('%Y-%m-%d') if equipment.warranty_end else '' }}">
< / div >
< / div >
< / div >
< / div >
2026-08-14 21:16:01 +02:00
< div class = "card mb-3" > < div class = "card-header" > < i class = "bi bi-wrench-adjustable" > < / i > Données techniques< / div > < div class = "card-body row g-3" >
< div class = "col-md-4" > < label class = "form-label" for = "mobility" > Mobilité< / label > < select class = "form-select" id = "mobility" name = "mobility" > {% for value, label in [('non_precise','À préciser'),('mobile','Mobile'),('fixe','Fixe')] %}< option value = "{{ value }}" { % if equipment . mobility = = value % } selected { % endif % } > {{ label }}< / option > {% endfor %}< / select > < / div >
2026-08-20 00:49:15 +02:00
< div class = "col-md-8" > < label class = "form-label" for = "management_mode" > Mode de gestion< / label > < select class = "form-select" id = "management_mode" name = "management_mode" > < option value = "" { % if not equipment . management_mode % } selected { % endif % } > Hériter de la catégorie< / option > {% for value, label in [('quantitatif','Quantitatif (chaises, tables…)'),('individuel_fixe','Individuel fixe (prise, luminaire…)'),('individuel_mobile','Individuel mobile (outil, ordinateur…)'),('serialise','Sérialisé avec compteur/contrat'),('structure','Élément de bâtiment (mur, sol…)'),('consommable','Consommable / stock')] %}< option value = "{{ value }}" { % if equipment . management_mode = = value % } selected { % endif % } > {{ label }}< / option > {% endfor %}< / select > < / div >
2026-08-14 21:16:01 +02:00
< div class = "col-md-4" > < label class = "form-label" for = "serial_number" > N° de série< / label > < input class = "form-control" id = "serial_number" name = "serial_number" value = "{{ equipment.serial_number or '' }}" > < / div >
< div class = "col-md-4" > < label class = "form-label" for = "manufacturer" > Fabricant< / label > < input class = "form-control" id = "manufacturer" name = "manufacturer" value = "{{ equipment.manufacturer or '' }}" > < / div >
< div class = "col-md-4" > < label class = "form-label" for = "model_reference" > Modèle< / label > < input class = "form-control" id = "model_reference" name = "model_reference" value = "{{ equipment.model_reference or '' }}" > < / div >
< div class = "col-md-4" > < label class = "form-label" for = "supplier_id" > Fournisseur< / label > < select class = "form-select" id = "supplier_id" name = "supplier_id" > < option value = "" > —< / option > {% for company in companies %}< option value = "{{ company.id }}" { % if equipment . supplier_id = = company . id % } selected { % endif % } > {{ company.name }}< / option > {% endfor %}< / select > < / div >
< div class = "col-md-4" > < label class = "form-label" for = "supplier_reference" > Référence fournisseur< / label > < input class = "form-control" id = "supplier_reference" name = "supplier_reference" value = "{{ equipment.supplier_reference or '' }}" > < / div >
< div class = "col-md-4" > < label class = "form-label" for = "purchase_price" > Prix d'achat< / label > < input class = "form-control" id = "purchase_price" name = "purchase_price" type = "number" min = "0" step = "0.01" value = "{{ equipment.purchase_price or '' }}" > < / div >
< div class = "col-md-4" > < label class = "form-label" for = "purchase_date" > Date d'achat< / label > < input class = "form-control" id = "purchase_date" name = "purchase_date" type = "date" value = "{{ equipment.purchase_date.strftime('%Y-%m-%d') if equipment.purchase_date else '' }}" > < / div >
< div class = "col-md-4 d-flex align-items-end" > < div class = "form-check mb-2" > < input class = "form-check-input" id = "recurrence_monitoring" name = "recurrence_monitoring" type = "checkbox" { % if equipment . recurrence_monitoring % } checked { % endif % } > < label class = "form-check-label" for = "recurrence_monitoring" > Surveiller les récurrences< / label > < / div > < / div >
< / div > < / div >
2026-08-14 18:02:25 +02:00
< div class = "card mb-3" >
< div class = "card-header" >
< i class = "bi bi-geo me-1" > < / i > Position
< / div >
< div class = "card-body" >
< div class = "row" >
< div class = "col-md-4" >
< label for = "position" class = "form-label" > Position (texte)< / label >
< input type = "text" class = "form-control" id = "position" name = "position"
value="{{ equipment.position or '' }}" placeholder="Ex: Angle nord-ouest">
< / div >
< div class = "col-md-4" >
< label for = "position_x" class = "form-label" > Position X< / label >
< input type = "number" step = "0.01" class = "form-control" id = "position_x" name = "position_x"
value="{{ equipment.position_x or '' }}">
< / div >
< div class = "col-md-4" >
< label for = "position_y" class = "form-label" > Position Y< / label >
< input type = "number" step = "0.01" class = "form-control" id = "position_y" name = "position_y"
value="{{ equipment.position_y or '' }}">
< / div >
< / div >
< / div >
< / div >
< / div >
< div class = "col-lg-4" >
< div class = "card mb-3" >
< div class = "card-header" >
< i class = "bi bi-diagram-3 me-1" > < / i > Hiérarchie
< / div >
< div class = "card-body" >
{% if equipment.parent %}
< div class = "mb-3" >
< label class = "form-label" > Parent< / label >
< p class = "form-control-plaintext" >
< a href = "{{ url_for('equipments.detail', id=equipment.parent.id) }}" >
{{ equipment.parent.name }}
< / a >
< / p >
< / div >
{% endif %}
< div class = "mb-3" >
< label for = "parent_id" class = "form-label" > Changer de parent< / label >
< select class = "form-select" id = "parent_id" name = "parent_id" >
< option value = "" > -- Aucun parent --< / option >
{% for eq in parent_equipments %}
{% if eq.id != equipment.id %}
< option value = "{{ eq.id }}" { { ' selected ' if equipment . parent_id = = eq . id else ' ' } } >
{{ eq.name }}
< / option >
{% endif %}
{% endfor %}
< / select >
< / div >
{% if equipment.is_group and equipment.children_count > 0 %}
< div class = "alert alert-info" >
< i class = "bi bi-info-circle me-1" > < / i >
Cet équipement a {{ equipment.children_count }} enfant(s).
< / div >
{% endif %}
< / div >
< / div >
< / div >
< / div >
< div class = "d-flex justify-content-end gap-2 mt-3" >
< a href = "{{ url_for('equipments.detail', id=equipment.id) }}" class = "btn btn-outline-secondary" >
< i class = "bi bi-x-lg me-1" > < / i > Annuler
< / a >
< button type = "submit" class = "btn btn-primary" >
< i class = "bi bi-check-lg me-1" > < / i > Enregistrer
< / button >
< / div >
< / form >
<!-- Formulaire de suppression séparé (hors du formulaire principal) -->
< div class = "card border-danger mt-3" >
< div class = "card-header text-danger" >
< i class = "bi bi-exclamation-triangle me-1" > < / i > Zone dangereuse
< / div >
< div class = "card-body" >
< form action = "{{ url_for('equipments.soft_delete', id=equipment.id) }}" method = "POST"
onsubmit="return confirm('Supprimer cet équipement ?')">
< input type = "hidden" name = "csrf_token" value = "{{ csrf_token() }}" >
< button type = "submit" class = "btn btn-outline-danger btn-sm w-100" >
< i class = "bi bi-trash me-1" > < / i > Supprimer
< / button >
< / form >
< / div >
< / div >
< / div >
<!-- Onglet Compteurs -->
< div class = "tab-pane fade" id = "meters" role = "tabpanel" >
< div class = "card" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< span > < i class = "bi bi-speedometer2 me-1" > < / i > Compteurs< / span >
< button class = "btn btn-sm btn-primary" data-bs-toggle = "modal" data-bs-target = "#addMeterModal" >
< i class = "bi bi-plus-lg me-1" > < / i > Ajouter
< / button >
< / div >
< div class = "table-responsive" >
< table class = "table table-hover mb-0" >
< thead >
< tr >
< th > Nom< / th >
< th > Type< / th >
< th > Valeur actuelle< / th >
< th > Unité< / th >
< th > Seuil alerte< / th >
< th > Seuil critique< / th >
< th > Prochaine maintenance< / th >
< th > Actions< / th >
< / tr >
< / thead >
< tbody >
{% for meter in meters %}
< tr class = "{{ 'table-warning' if meter.warning_level == 'warning' else '' }}{{ 'table-danger' if meter.warning_level == 'critical' else '' }}" >
< td > {{ meter.name }}< / td >
< td > {{ meter.meter_type }}< / td >
< td > < strong > {{ meter.current_value }}< / strong > < / td >
< td > {{ meter.unit }}< / td >
< td > {{ meter.warning_threshold or '—' }}< / td >
< td > {{ meter.critical_threshold or '—' }}< / td >
< td >
{% if meter.next_maintenance_at %}
{{ meter.next_maintenance_at }} {{ meter.unit }}
{% else %}
—
{% endif %}
< / td >
< td >
< button class = "btn btn-sm btn-outline-primary" onclick = "addReading({{ meter.id }})" >
< i class = "bi bi-pencil" > < / i > Relevé
< / button >
< / td >
< / tr >
{% else %}
< tr >
< td colspan = "8" class = "text-center text-muted py-4" >
< i class = "bi bi-speedometer2 fs-1" > < / i >
< p > Aucun compteur< / p >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< / div >
< / div >
<!-- Onglet Consommables -->
< div class = "tab-pane fade" id = "consumables" role = "tabpanel" >
< div class = "card" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< span > < i class = "bi bi-box-seam me-1" > < / i > Consommables compatibles< / span >
< button class = "btn btn-sm btn-primary" data-bs-toggle = "modal" data-bs-target = "#addConsumableModal" >
< i class = "bi bi-plus-lg me-1" > < / i > Ajouter
< / button >
< / div >
< div class = "table-responsive" >
< table class = "table table-hover mb-0" >
< thead >
< tr >
< th > Consommable< / th >
< th > Réf.< / th >
< th > Intervalle (jours)< / th >
< th > Intervalle (heures)< / th >
< th > Stock< / th >
< th > Actions< / th >
< / tr >
< / thead >
< tbody >
{% for ec in equipment_consumables %}
< tr >
< td > {{ ec.consumable.name }}< / td >
< td > < code > {{ ec.consumable.reference or '—' }}< / code > < / td >
< td > {{ ec.replacement_interval_days or '—' }}< / td >
< td > {{ ec.replacement_interval_hours or '—' }}< / td >
< td >
< span class = "badge {{ 'bg-danger' if ec.consumable.is_low_stock else 'bg-success' }}" >
{{ ec.consumable.quantity }} {{ ec.consumable.unit }}
< / span >
< / td >
< td >
< button class = "btn btn-sm btn-outline-danger" onclick = "removeConsumable({{ ec.id }})" >
< i class = "bi bi-trash" > < / i >
< / button >
< / td >
< / tr >
{% else %}
< tr >
< td colspan = "6" class = "text-center text-muted py-4" >
< i class = "bi bi-box-seam fs-1" > < / i >
< p > Aucun consommable associé< / p >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< / div >
< / div >
<!-- Onglet Documents -->
< div class = "tab-pane fade" id = "documents" role = "tabpanel" >
< div class = "card" >
< div class = "card-header d-flex justify-content-between align-items-center" >
< span > < i class = "bi bi-file-earmark me-1" > < / i > Documents< / span >
< button class = "btn btn-sm btn-primary" data-bs-toggle = "modal" data-bs-target = "#addDocumentModal" >
< i class = "bi bi-upload me-1" > < / i > Téléverser
< / button >
< / div >
< div class = "table-responsive" >
< table class = "table table-hover mb-0" >
< thead >
< tr >
< th > Fichier< / th >
< th > Description< / th >
< th > Ajouté le< / th >
< th > Par< / th >
< th > Actions< / th >
< / tr >
< / thead >
< tbody >
{% for doc in equipment.documents %}
< tr >
< td >
< i class = "bi bi-file-earmark-text me-1" > < / i >
{{ doc.filename }}
< / td >
< td > {{ doc.description or '—' }}< / td >
< td > {{ doc.uploaded_at.strftime('%d/%m/%Y') }}< / td >
< td > {{ doc.uploaded_by.username if doc.uploaded_by else '—' }}< / td >
< td >
< a href = "{{ url_for('equipments_documents.download_document', id=doc.id) }}"
class="btn btn-sm btn-outline-primary">
< i class = "bi bi-download" > < / i >
< / a >
< button class = "btn btn-sm btn-outline-danger" onclick = "deleteDocument({{ doc.id }})" >
< i class = "bi bi-trash" > < / i >
< / button >
< / td >
< / tr >
{% else %}
< tr >
< td colspan = "5" class = "text-center text-muted py-4" >
< i class = "bi bi-file-earmark fs-1" > < / i >
< p > Aucun document< / p >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< / div >
< / div >
<!-- Onglet Historique -->
< div class = "tab-pane fade" id = "history" role = "tabpanel" >
< div class = "card" >
< div class = "card-header" >
< i class = "bi bi-clock-history me-1" > < / i > Historique des déplacements
< / div >
< div class = "table-responsive" >
< table class = "table table-hover mb-0" >
< thead >
< tr >
< th > Date< / th >
< th > Ancienne salle< / th >
< th > Nouvelle salle< / th >
< th > Raison< / th >
< th > Par< / th >
< / tr >
< / thead >
< tbody >
{% for h in room_history %}
< tr >
2026-08-15 00:47:55 +02:00
< td > {{ h.changed_at|datetime_fmt }}< / td >
2026-08-14 18:02:25 +02:00
< td > {{ h.old_room.name if h.old_room else '—' }}< / td >
< td > {{ h.new_room.name if h.new_room else '—' }}< / td >
< td > {{ h.reason or '—' }}< / td >
< td > {{ h.changed_by.username if h.changed_by else '—' }}< / td >
< / tr >
{% else %}
< tr >
< td colspan = "5" class = "text-center text-muted py-4" >
< i class = "bi bi-clock-history fs-1" > < / i >
< p > Aucun déplacement enregistré< / p >
< / td >
< / tr >
{% endfor %}
< / tbody >
< / table >
< / div >
< / div >
< / div >
< / div >
< / div >
<!-- Modal Ajouter Compteur -->
< div class = "modal fade" id = "addMeterModal" tabindex = "-1" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< form id = "meterForm" >
< input type = "hidden" name = "csrf_token" value = "{{ csrf_token() }}" >
< div class = "modal-header" >
< h5 class = "modal-title" > Ajouter un compteur< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" > < / button >
< / div >
< div class = "modal-body" >
< div class = "mb-3" >
< label for = "meter_name" class = "form-label" > Nom *< / label >
< input type = "text" class = "form-control" id = "meter_name" name = "name" required >
< / div >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "meter_type" class = "form-label" > Type< / label >
< select class = "form-select" id = "meter_type" name = "meter_type" >
< option value = "hours" > Heures< / option >
< option value = "cycles" > Cycles< / option >
< option value = "km" > Kilomètres< / option >
< option value = "custom" > Personnalisé< / option >
< / select >
< / div >
< div class = "col-md-6" >
< label for = "meter_unit" class = "form-label" > Unité< / label >
< input type = "text" class = "form-control" id = "meter_unit" name = "unit" value = "h" >
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "meter_initial" class = "form-label" > Valeur initiale< / label >
< input type = "number" step = "0.01" class = "form-control" id = "meter_initial" name = "initial_value" value = "0" >
< / div >
< div class = "col-md-6" >
< label for = "meter_current" class = "form-label" > Valeur actuelle< / label >
< input type = "number" step = "0.01" class = "form-control" id = "meter_current" name = "current_value" value = "0" >
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "meter_warning" class = "form-label" > Seuil alerte< / label >
< input type = "number" step = "0.01" class = "form-control" id = "meter_warning" name = "warning_threshold" >
< / div >
< div class = "col-md-6" >
< label for = "meter_critical" class = "form-label" > Seuil critique< / label >
< input type = "number" step = "0.01" class = "form-control" id = "meter_critical" name = "critical_threshold" >
< / div >
< / div >
< div class = "row mb-3" >
< div class = "col-md-6" >
< label for = "meter_interval" class = "form-label" > Intervalle maintenance< / label >
< input type = "number" step = "0.01" class = "form-control" id = "meter_interval" name = "maintenance_interval" >
< / div >
< div class = "col-md-6" >
< label for = "meter_last_maint" class = "form-label" > Dernière maintenance (valeur)< / label >
< input type = "number" step = "0.01" class = "form-control" id = "meter_last_maint" name = "last_maintenance_value" >
< / div >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Ajouter< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<!-- Modal Ajouter Consommable -->
< div class = "modal fade" id = "addConsumableModal" tabindex = "-1" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< form id = "consumableForm" >
< input type = "hidden" name = "csrf_token" value = "{{ csrf_token() }}" >
< input type = "hidden" name = "equipment_id" value = "{{ equipment.id }}" >
< div class = "modal-header" >
< h5 class = "modal-title" > Ajouter un consommable compatible< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" > < / button >
< / div >
< div class = "modal-body" >
< div class = "mb-3" >
< label for = "consumable_id" class = "form-label" > Consommable *< / label >
< select class = "form-select" id = "consumable_id" name = "consumable_id" required >
< option value = "" > -- Sélectionner --< / option >
{% for c in all_consumables %}
< option value = "{{ c.id }}" > {{ c.name }} ({{ c.reference or '—' }}) - Stock: {{ c.quantity }}< / option >
{% endfor %}
< / select >
< / div >
< div class = "row mb-3" >
< div class = "col-md-4" >
< label for = "interval_days" class = "form-label" > Intervalle (jours)< / label >
< input type = "number" class = "form-control" id = "interval_days" name = "replacement_interval_days" >
< / div >
< div class = "col-md-4" >
< label for = "interval_hours" class = "form-label" > Intervalle (heures)< / label >
< input type = "number" class = "form-control" id = "interval_hours" name = "replacement_interval_hours" >
< / div >
< div class = "col-md-4" >
< label for = "interval_cycles" class = "form-label" > Intervalle (cycles)< / label >
< input type = "number" class = "form-control" id = "interval_cycles" name = "replacement_interval_cycles" >
< / div >
< / div >
< div class = "mb-3" >
< label for = "consumable_notes" class = "form-label" > Notes< / label >
< textarea class = "form-control" id = "consumable_notes" name = "notes" rows = "2" > < / textarea >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Ajouter< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
<!-- Modal Téléverser Document -->
< div class = "modal fade" id = "addDocumentModal" tabindex = "-1" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< form id = "documentForm" enctype = "multipart/form-data" >
< input type = "hidden" name = "csrf_token" value = "{{ csrf_token() }}" >
< div class = "modal-header" >
< h5 class = "modal-title" > Téléverser un document< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" > < / button >
< / div >
< div class = "modal-body" >
< div class = "mb-3" >
< label for = "document_file" class = "form-label" > Fichier *< / label >
< input type = "file" class = "form-control" id = "document_file" name = "file" required >
< / div >
< div class = "mb-3" >
< label for = "document_description" class = "form-label" > Description< / label >
< textarea class = "form-control" id = "document_description" name = "description" rows = "2" > < / textarea >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-secondary" data-bs-dismiss = "modal" > Annuler< / button >
< button type = "submit" class = "btn btn-primary" > Téléverser< / button >
< / div >
< / form >
< / div >
< / div >
< / div >
< script >
2026-08-15 01:37:17 +02:00
const equipmentCategory = document.getElementById('category_id');
const equipmentLot = document.getElementById('lot_id');
const quickAddEquipmentLot = document.getElementById('quick-add-lot');
function filterEquipmentLots() {
const categoryId = equipmentCategory.value;
let selectedIsValid = !equipmentLot.value;
[...equipmentLot.options].forEach((option, index) => {
if (!index) return;
const visible = !!categoryId & & option.dataset.categoryId === categoryId;
option.hidden = !visible;
option.disabled = !visible;
if (visible & & option.selected) selectedIsValid = true;
});
if (!selectedIsValid) equipmentLot.value = '';
quickAddEquipmentLot.disabled = !categoryId;
}
equipmentCategory.addEventListener('change', filterEquipmentLots);
quickAddEquipmentLot.addEventListener('click', async () => {
const categoryName = equipmentCategory.selectedOptions[0]?.textContent.trim();
const name = window.prompt(`Nom du nouveau lot pour « ${categoryName} » :`);
if (!name || !name.trim()) return;
const response = await fetch('{{ url_for("wizard.quick_create_lot") }}', {
method: 'POST',
headers: {'Content-Type': 'application/json', 'X-CSRFToken': '{{ csrf_token() }}'},
body: JSON.stringify({name: name.trim(), category_id: equipmentCategory.value})
});
const data = await response.json();
if (!response.ok & & !data.lot) {
window.alert(data.error || 'Création du lot impossible.');
return;
}
const created = data.lot;
let option = [...equipmentLot.options].find(item => item.value === String(created.id));
if (!option) {
option = new Option(created.name, created.id);
option.dataset.categoryId = String(created.category_id);
equipmentLot.add(option);
}
filterEquipmentLots();
equipmentLot.value = String(created.id);
if (!response.ok) window.alert(data.error);
});
filterEquipmentLots();
2026-08-14 18:02:25 +02:00
// Gestion des formulaires AJAX
document.getElementById('meterForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('{{ url_for("equipments_meters.add_meter", id=equipment.id) }}', {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + (data.error || 'Impossible d\'ajouter le compteur'));
}
});
});
document.getElementById('consumableForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('{{ url_for("equipments_meters.add_consumable", id=equipment.id) }}', {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + (data.error || 'Impossible d\'ajouter le consommable'));
}
});
});
document.getElementById('documentForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('{{ url_for("equipments_documents.upload_document", id=equipment.id) }}', {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + (data.error || 'Impossible de téléverser le document'));
}
});
});
function addReading(meterId) {
const value = prompt('Entrez la nouvelle valeur du compteur:');
if (value !== null) {
fetch('{{ url_for("equipments_meters.add_meter_reading", id=equipment.id) }}', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({meter_id: meterId, value: parseFloat(value)})
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + (data.error || 'Impossible d\'ajouter le relevé'));
}
});
}
}
function removeConsumable(ecId) {
if (confirm('Retirer ce consommable ?')) {
fetch('{{ url_for("equipments_meters.remove_consumable", id=equipment.id) }}', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ec_id: ecId})
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + (data.error || 'Impossible de retirer le consommable'));
}
});
}
}
function deleteDocument(docId) {
if (confirm('Supprimer ce document ?')) {
fetch('{{ url_for("equipments_documents.delete_document", doc_id=0) }}'.replace('0', docId), {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'same-origin'
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + (data.error || 'Impossible de supprimer le document'));
}
});
}
}
< / script >
2026-08-14 21:16:01 +02:00
{% endblock %}