loko/streetup/interventions/templates/interventions/detail/card_posts.html
2026-07-22 14:48:40 +02:00

484 lines
34 KiB
HTML

{% load format_number i18n static %}
{% if can_view_posts %}
<div class="card mb-4" id="posts-section">
<div class="card-header d-flex justify-content-between align-items-center">
<h4 class="mb-0">{% translate "Prestations" %}</h4>
</div>
<div class="card-body">
<div id="postsSectionAlert" class="my-1"></div>
{% if intervention.maintain_type == 'ameliorative' %}
{% if period_validation_enabled or can_manage_period_validation %}
<div class="px-3 py-2 border-top border-bottom bg-light mb-3" id="periodValidationBlock">
<div class="d-flex align-items-center gap-3 flex-wrap">
{% if can_manage_period_validation %}
{% if not period_validation_enabled or period_number == 1 %}
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="togglePeriodValidation" {% if period_validation_enabled %}checked{% endif %}>
<label class="form-check-label" for="togglePeriodValidation">
{% translate "Validation par périodes" %}
</label>
</div>
{% endif %}
{% endif %}
<div id="periodInfo" class="{% if not period_validation_enabled %}d-none{% endif %}">
{% if period_validation_enabled %}
<span class="badge bg-info me-2">{% translate "Période" %} {{ period_number }}</span>
{% if can_manage_period_validation %}
{% if period_number == 1 %}
<small class="text-muted">{% translate "Vous pouvez désactiver tant que la période 1 est en cours." %}</small>
{% else %}
{% if not intervention.status in 'validated,invoiced,closed,canceled' %}
<div class="form-check d-inline-block ms-2">
<input class="form-check-input" type="checkbox" id="setLastPeriodCheckbox" {% if period_is_final %}checked{% endif %}>
<label class="form-check-label" for="setLastPeriodCheckbox">{% translate "Dernière période" %}</label>
</div>
<small class="text-muted d-block">{% translate "Si 'Dernière période' est activée, la prochaine validation sera définitive." %}</small>
{% endif %}
{% endif %}
{% if intervention.status in 'validated,invoiced,closed' and period_is_final %}
<small class="text-muted d-block">{% translate "Intervention définitivement validée." %}</small>
{% endif %}
{% else %}
{% if period_is_final and intervention.status in 'validated,invoiced,closed' %}
<small class="text-muted d-block">{% translate "Intervention définitivement validée." %}</small>
{% endif %}
{% endif %}
{% endif %}
</div>
</div>
{% if can_manage_period_validation %}<div id="periodValidationAlert" class="mt-2"></div>{% endif %}
</div>
{% endif %}
{% endif %}
<div class="mb-3 d-flex align-items-center">
<div id="orderAlertContainer" class="m-1"></div>
{% if 'posts' in allowed_update_fields or can_control %}
<button type="button" id="posts-expand-btn" class="btn btn-primary btn-sm mx-2" title="{% translate 'Vue étendue' %}">
<i class="bi bi-arrows-fullscreen"></i>
</button>
{% endif %}
<span class="label me-2">{% translate "Commande" %} :</span>
<div style="flex: 1;">
<span id="orderDisplayValue">
{% if intervention.order %}
<a href="{% url 'contracts:contracts_orders_detail' intervention.order.id %}">{{ intervention.order }}</a>
{% else %}
<em class="text-muted">{% translate "Aucune commande assignée" %}</em>
{% endif %}
</span>
</div>
</div>
<div class="table-responsive {% if intervention.status == 'in_preparation' or not contract_posts %} d-none {% endif %}" id="posts-table-container">
<div class="mb-2 d-flex justify-content-between align-items-center">
{% if period_validation_enabled or has_period_quantities %}
<div class="mb-2" id="consult-periods-toggle-container">
<button type="button" id="consult-show-periods-btn" class="btn btn-outline-secondary btn-sm" title="{% translate 'Voir les périodes' %}">
<i class="bi bi-calendar3"></i> {% translate "Voir les périodes" %}
</button>
</div>
{% else %}
<div></div>
{% endif %}
<div class="d-flex gap-2">
</div>
</div>
<table class="table table-bordered table-hover table-sm" id="contractTable"
data-quote-remaining-available="{{ quote_remaining_available|yesno:'true,false' }}">
<thead class="table-light">
<tr>
<th>{% translate "Poste" %}</th>
<th>{% translate "Code" %}</th>
<th>{% translate "Description" %}</th>
{% if quote_remaining_available %}
<th class="quote-remaining-header">{% translate "Qté devis (prévue/restante)" %}</th>
{% endif %}
<th class="quantity-header">{% translate "Quantité" %}{% if period_validation_enabled %} <span class="badge bg-info ms-1">P {{ period_number }}</span>{% endif %}</th>
<th class="comment-header">{% translate "Commentaire" %}</th>
{% if has_coefficient_posts %}
<th class="coefficient-col">{% translate "Type" %}</th>
<th class="coefficient-col text-center">{% translate "Coeff." %}</th>
{% endif %}
{% if can_view_prices %}
<th class="unit_price-header">{% translate "Prix Unitaire" %}</th>
<th class="total-header">{% translate "Total" %}</th>
{% endif %}
<th class="status-header">{% translate "Statut" %}</th>
<th class="text-nowrap">{% translate "Remarque" %}</th>
</tr>
<!-- Ligne de filtres -->
<tr class="posts-filter-row" id="postsFilterRow">
<th>
<input type="search" class="form-control form-control-sm" placeholder="{% translate 'Filtrer…' %}" data-filter-input="order_number">
</th>
<th>
<input type="search" class="form-control form-control-sm" placeholder="{% translate 'Filtrer…' %}" data-filter-input="code">
</th>
<th>
<input type="search" class="form-control form-control-sm" placeholder="{% translate 'Filtrer…' %}" data-filter-input="description">
</th>
{% if quote_remaining_available %}
<th></th>
{% endif %}
<th>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="posts-quantity-filter" data-filter-quantity>
<label class="form-check-label small" for="posts-quantity-filter">
{% translate "Qté>0" %}
</label>
</div>
</th>
<th class="comment-header"></th>
{% if has_coefficient_posts %}
<th class="coefficient-col"></th>
<th class="coefficient-col"></th>
{% endif %}
{% if can_view_prices %}
<th></th>
<th></th>
{% endif %}
<th class="status-header">
{% if can_control %}
<div class="d-flex justify-content-end">
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-success bulk-status-btn" data-bulk-status="validated" data-table-target="contractTable" title="{% translate 'Valider toutes les lignes' %}">
<i class="bi bi-check-circle"></i>
</button>
<button type="button" class="btn btn-outline-info bulk-status-btn" data-bulk-status="pending" data-table-target="contractTable" title="{% translate 'Mettre toutes en attente' %}">
<i class="bi bi-question-circle"></i>
</button>
<button type="button" class="btn btn-outline-danger bulk-status-btn" data-bulk-status="refused" data-table-target="contractTable" title="{% translate 'Refuser toutes les lignes' %}">
<i class="bi bi-x-circle"></i>
</button>
</div>
</div>
{% endif %}
</th>
<th></th>
</tr>
</thead>
<tbody>
{% for item in contract_posts %}
<tr data-contract-post-id="{{ item.contract_post.id }}"
data-order-number="{{ item.contract_post.order_number }}"
data-code="{{ item.contract_post.code }}"
data-post-type="{{ item.contract_post.post_type|default:'' }}"
data-is-coefficient-multipliable="{{ item.contract_post.is_coefficient_multipliable|yesno:'true,false' }}"
data-is-amount-to-be-justified="{{ item.contract_post.is_amount_to_be_justified|yesno:'true,false' }}"
data-coeff-amount-to-be-justified="{{ item.contract_post.coeff_amount_to_be_justified|default:1|stringformat:'g' }}"
data-unit="{{ item.contract_post.unit }}"
data-description="{% if LANGUAGE_CODE == 'nl' %}{{ item.contract_post.description_nl }}{% else %}{{ item.contract_post.description_fr }}{% endif %}">
<td class="data order_number-cell">{{ item.contract_post.order_number }}</td>
<td class="data code-cell">{{ item.contract_post.code }}</td>
<td class="data description-cell">
{% if LANGUAGE_CODE == "nl" %}
{{ item.contract_post.description_nl }}
{% else %}
{{ item.contract_post.description_fr }}
{% endif %}
</td>
{% if quote_remaining_available %}
{% with remaining=item.quote_remaining_quantity planned=item.quote_planned_quantity %}
<td class="data remaining_quantity-cell {% if remaining is not None and remaining < 0 %}text-danger{% endif %}">
{% if planned is not None %}
{{ planned|format_quantity }} /
{% endif %}
{% if remaining is not None %}
{{ remaining|format_quantity }}
{% else %}
-
{% endif %}
</td>
{% endwith %}
{% endif %}
<td class="data quantity-cell text-center">
{% if item.quantity is not None %}
{{ item.quantity|format_quantity }}&nbsp;{{ item.contract_post.unit }}
{% endif %}
</td>
<td class="data comment-cell">{{ item.comment|default:'' }}</td>
{% if has_coefficient_posts %}
<td class="data coefficient-col post-type-cell">{{ item.contract_post.post_type|default:"-" }}</td>
<td class="data coefficient-col text-center is-coefficient-cell">
{% if item.contract_post.is_coefficient_multipliable %}
<i class="bi bi-check-circle text-success" title="{% translate 'Poste avec coefficient multipliable' %}"></i>
{% else %}
-
{% endif %}
</td>
{% endif %}
{% if can_view_prices %}
<td class="data unit_price-cell text-nowrap">
{% if item.contract_post.unit_price %}
{{ item.contract_post.unit_price|format_price|safe }}
{% else %}
-
{% endif %}
</td>
<td class="data total-cell text-nowrap">{{ item.total_price|format_price|safe }}</td>
{% endif %}
<td class="data status-cell">
<div class="btn-group btn-group-sm" role="group" aria-label="Statut de contrôle">
<button type="button" {% if not can_control %}disabled{% endif %}
class="badge badge-pill badge-light post-status-badge btn {% if item.control_status == 'validated' %}active btn-success{% else %}btn-outline-secondary{% endif %}{% if can_control %} cursor-pointer{% endif %}"
data-status="validated"
data-post-id="{{ item.id }}"
title="{% if can_control %}{% translate 'Valider' %}{% endif %}">
<i class="bi bi-check-circle"></i>
</button>
<button type="button" {% if not can_control %}disabled{% endif %}
class="badge badge-pill badge-light post-status-badge btn {% if item.control_status == 'pending' %}active btn-info{% else %}btn-outline-secondary{% endif %}{% if can_control %} cursor-pointer{% endif %}"
data-status="pending"
data-post-id="{{ item.id }}"
title="{% if can_control %}{% translate 'En attente' %}{% endif %}">
<i class="bi bi-question-circle"></i>
</button>
<button type="button" {% if not can_control %}disabled{% endif %}
class="badge badge-pill badge-light post-status-badge btn {% if item.control_status == 'refused' %}active btn-danger{% else %}btn-outline-secondary{% endif %}{% if can_control %} cursor-pointer{% endif %}"
data-status="refused"
data-post-id="{{ item.id }}"
title="{% if can_control %}{% translate 'Refuser' %}{% endif %}">
<i class="bi bi-x-circle"></i>
</button>
</div>
</td>
<td class="data control_comment-cell">{{ item.control_comment|default:'' }}</td>
<td class="actions-cell" style="display: none;">
{% if 'posts' in allowed_update_fields or can_control %}
<button class="edit-btn btn btn-sm btn-primary"><i class="bi bi-pencil"></i></button>
{% endif %}
{% if 'posts' in allowed_update_fields and not can_control %}
<button class="reset-qty-btn btn btn-sm btn-warning" title="{% translate 'Remettre la quantité à 0' %}">
<i class="bi bi-arrow-counterclockwise"></i>
</button>
{% endif %}
</td>
</tr>
{% endfor %}
<!-- Ligne vide pour ajout -->
{% if 'posts' in allowed_update_fields and not can_control %}
<tr id="newRow" style="display: none;">
<td class="order_number-cell"></td>
<td class="code-cell"></td>
<td class="description-cell"></td>
{% if quote_remaining_available %}
<td class="remaining_quantity-cell"></td>
{% endif %}
<td class="quantity-cell text-center"></td>
<td class="comment-cell"></td>
{% if can_view_prices %}
<td class="unit_price-cell"></td>
<td class="total-cell"></td>
{% endif %}
<td class="status-cell"></td>
<td class="control_comment-cell"></td>
<td class="actions-cell">
{% if 'posts' in allowed_update_fields %}
<button class="add-btn btn btn-sm btn-success"><i class="bi bi-plus-circle"></i></button>
{% endif %}
</td>
</tr>
{% endif %}
</tbody>
{% if can_view_prices %}
<tfoot>
<tr>
<th colspan="{% if quote_remaining_available %}{% if has_coefficient_posts %}9{% else %}7{% endif %}{% else %}{% if has_coefficient_posts %}8{% else %}6{% endif %}{% endif %}" class="text-end">{% translate "Total Général" %} :</th>
<th class="total-general">{{ total_general|floatformat:2 }} €</th>
<!-- Si l'intervention est dans un statut >= validated, il ne faut pas afficher le montant validé -->
{% if intervention.status in 'validated,invoiced,closed,canceled' %}
<th colspan="1"></th>
{% else %}
<th class="text-success total-validated">{{ total_validated|floatformat:2 }} €</th>
<th colspan="1"></th>
{% endif %}
</tr>
</tfoot>
{% endif %}
</table>
</div>
<datalist id="contract-post-suggestions"></datalist>
</div>
</div>
<!-- Modal plein écran pour l'édition des prestations -->
<div class="modal fade" id="postsFullscreenModal" tabindex="-1" aria-labelledby="postsFullscreenModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="postsFullscreenModalLabel">
{% translate "Édition des prestations" %} - {{ intervention.code }}
</h5>
<div class="d-flex gap-2 ms-auto me-2">
{% if 'posts' in allowed_update_fields and not can_control %}
<button type="button" id="posts-show-all-btn" class="btn btn-outline-primary btn-sm">
<i class="bi bi-list-ul"></i> {% translate "Afficher tous les postes du contrat" %}
</button>
<button type="button" id="posts-add-quote-btn" class="btn btn-outline-secondary btn-sm {% if not intervention.order or not intervention.order.quote %}d-none{% endif %}"
data-order-id="{% if intervention.order %}{{ intervention.order.id }}{% endif %}"
title="{% translate 'Ajouter les postes du devis' %}">
<i class="bi bi-list-plus"></i> {% translate "Ajouter les postes du devis" %}
</button>
<button type="button" id="posts-add-line-btn" class="btn btn-outline-success btn-sm">
<i class="bi bi-plus-lg"></i> {% translate "Ajouter une ligne" %}
</button>
{% endif %}
{% if period_validation_enabled %}
<button type="button" id="posts-show-periods-btn" class="btn btn-outline-secondary btn-sm" title="{% translate 'Voir les périodes' %}">
<i class="bi bi-calendar3"></i> {% translate "Voir les périodes" %}
</button>
{% endif %}
</div>
</div>
<div class="modal-body">
<div id="postsFullscreenAlert"></div>
<!-- Sélecteur de commande -->
{% if 'order' in allowed_update_fields %}
<div class="mb-3 p-3 border rounded bg-light">
<div class="row align-items-center">
<div class="col-md-3">
<label for="orderSelect" class="form-label fw-bold mb-0">
<i class="bi bi-file-earmark-text me-1"></i>
{% translate "Commande" %}
</label>
</div>
<div class="col-md-9">
<select class="form-select" id="orderSelect" style="width: 100%;">
<option value="">-- {% translate "Sélectionnez une commande" %} --</option>
{% for order in orders %}
<option value="{{ order.id }}"
data-contract="{{ order.contract.contract_number }}"
data-order-code="{{ order.order_code }}"
data-has-quote="{% if order.quote %}true{% else %}false{% endif %}"
{% if intervention.order and order.id == intervention.order.id %}selected{% endif %}>
{{ order.contract.contract_number }} - {{ order.order_code }}
</option>
{% endfor %}
</select>
<small class="text-muted d-block mt-1">
<i class="bi bi-info-circle me-1"></i>
{% translate "Sélectionnez la commande associée à cette intervention" %}
</small>
</div>
</div>
</div>
{% endif %}
<div class="table-responsive">
<table class="table table-bordered table-hover table-sm" id="postsFullscreenTable">
<thead class="table-light">
<tr>
<th>
{% translate "Poste" %}
</th>
<th>{% translate "Code" %}</th>
<th>{% translate "Description" %}</th>
{% if quote_remaining_available %}
<th>{% translate "Qté devis (prévue/restante)" %}</th>
{% endif %}
<th>{% translate "Quantité" %}{% if period_validation_enabled %} <span class="badge bg-info ms-1">P {{ period_number }}</span>{% endif %}</th>
<th>{% translate "Commentaire" %}</th>
<th class="coefficient-col" style="{% if not has_coefficient_posts %}display: none;{% endif %}">{% translate "Type" %}</th>
<th class="coefficient-col" style="{% if not has_coefficient_posts %}display: none;{% endif %}">{% translate "Coeff." %}</th>
{% if can_view_prices %}
<th>{% translate "Prix Unit." %}</th>
<th>{% translate "Total" %}</th>
{% endif %}
<th>{% translate "Statut" %}</th>
<th class="text-nowrap">{% translate "Remarque" %}</th>
<th>{% translate "Actions" %}</th>
</tr>
<!-- Ligne de filtres -->
<tr class="posts-filter-row" id="postsFilterRowFullscreen">
<th>
<input type="search" class="form-control form-control-sm" placeholder="{% translate 'Filtrer…' %}" data-filter-input="order_number">
</th>
<th>
<input type="search" class="form-control form-control-sm" placeholder="{% translate 'Filtrer…' %}" data-filter-input="code">
</th>
<th>
<input type="search" class="form-control form-control-sm" placeholder="{% translate 'Filtrer…' %}" data-filter-input="description">
</th>
{% if quote_remaining_available %}
<th></th>
{% endif %}
<th>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="posts-quantity-filter" data-filter-quantity>
<label class="form-check-label small" for="posts-quantity-filter">
{% translate "Qté>0" %}
</label>
</div>
</th>
<th></th>
<th class="coefficient-col" style="{% if not has_coefficient_posts %}display: none;{% endif %}"></th>
<th class="coefficient-col" style="{% if not has_coefficient_posts %}display: none;{% endif %}"></th>
{% if can_view_prices %}
<th></th>
<th></th>
{% endif %}
<th>
{% if can_control %}
<div class="d-flex justify-content-end">
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-success bulk-status-btn" data-bulk-status="validated" title="{% translate 'Valider toutes les lignes' %}">
<i class="bi bi-check-circle"></i>
</button>
<button type="button" class="btn btn-outline-info bulk-status-btn" data-bulk-status="pending" title="{% translate 'Mettre toutes en attente' %}">
<i class="bi bi-question-circle"></i>
</button>
<button type="button" class="btn btn-outline-danger bulk-status-btn" data-bulk-status="refused" title="{% translate 'Refuser toutes les lignes' %}">
<i class="bi bi-x-circle"></i>
</button>
</div>
</div>
{% endif %}
</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody id="postsFullscreenTableBody">
<!-- Le contenu sera injecté par JavaScript -->
</tbody>
{% if can_view_prices %}
<tfoot>
<tr>
<th colspan="{% if quote_remaining_available %}{% if has_coefficient_posts %}9{% else %}7{% endif %}{% else %}{% if has_coefficient_posts %}8{% else %}6{% endif %}{% endif %}" class="text-end">{% translate "Total Général" %} :</th>
<th class="total-general text-nowrap">0,00 €</th>
<th class="text-success total-validated text-nowrap">0,00 €</th>
<th colspan="2"></th>
</tr>
</tfoot>
{% endif %}
</table>
</div>
<div id="posts-no-results" class="text-center text-muted py-4" style="display: none;">
{% translate "Aucun poste ne correspond aux filtres." %}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="posts-cancel-btn">
<i class="bi bi-x-circle"></i> {% translate "Annuler" %}
</button>
<button type="button" class="btn btn-primary" id="posts-save-btn">
<i class="bi bi-check-circle"></i> {% translate "Sauvegarder" %}
</button>
</div>
</div>
</div>
</div>
{% endif %}