{% extends "@App/Default/base.html.twig" %}
{% block stylesheets %}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.4.2/chosen.css">
<link rel="stylesheet" type="text/css" media="screen" href="{{ asset('css/bootstrap-switch.min.css') }}" />
{% endblock %}
{% block content %}
{% form_theme form 'jquery.collection.html.twig' %}
<div class="ibox-content">
<div class="sk-spinner sk-spinner-wave">
<div class="sk-rect1"></div>
<div class="sk-rect2"></div>
<div class="sk-rect3"></div>
<div class="sk-rect4"></div>
<div class="sk-rect5"></div>
</div>
{{ form_start(form) }}
<div class="row mb-2">
<div class="col-md-5">
<div class="row mb-2">
<div class="col-md-6 mb-1">{{ form_row(form.motifMouvement) }}</div>
<div class="col-md-6" id="autre-motif">{{ form_row(form.autreMotif) }}</div>
</div>
<div class="row mb-2" id="agence-depart">
<div class="col-md-6">{{ form_row(form.agenceDepart) }}</div>
</div>
<div class="row mb-2">
<div class="col-md-6">{{ form_row(form.typeEmplacementDepart) }}</div>
<div class="col-md-6">
<p><strong>{{ "Emplacement de départ"|trans }}</strong></p>
<p id="local-depart">{{ form_widget(form.localDepart) }}</p>
<p id="nr-depart">{{ form_widget(form.nanoReseauDepart) }}</p>
<p id="client-depart">{{ form_widget(form.clientDepart) }}</p>
<p id="user-depart">{{ form_widget(form.userDepart) }}</p>
</div>
</div>
</div>
<div class="col-md-2 text-center">
<div class="col-md-12" style="margin-top: 50%;"><i class="fa fa-4x fa-arrow-right"></i></div>
</div>
<div class="col-md-5">
<div class="row mb-2">
<div class="col-md-6">{{ "Date du mouvement"|trans }}</div>
<div class="col-md-6">{{ form_widget(form.date) }}</div>
</div>
<div class="row mb-2" id="agence-arrivee">
<div class="col-md-6">{{ "Agence d'arrivée"|trans }}</div>
<div class="col-md-6">{{ form_widget(form.agenceArrivee) }}</div>
</div>
<div class="row mb-2">
<div class="col-md-6">{{ form_row(form.typeEmplacementArrivee) }}</div>
<div class="col-md-6">
<p><strong>{{ "Emplacement d'arrivée"|trans }}</strong></p>
<p id="local-arrivee">{{ form_widget(form.localArrivee) }}</p>
<p id="nr-arrivee">{{ form_widget(form.nanoReseauArrivee) }}</p>
<p id="client-arrivee">{{ form_widget(form.clientArrivee) }}</p>
<p id="user-arrivee">{{ form_widget(form.userArrivee) }}</p>
</div>
</div>
</div>
</div>
{# Materiels #}
<div style="position: relative;">
<div class="row mb-1">
<h3 class="mb-2 col-md-12">{{ "Liste des matériels" | trans }}</h3>
<div class="col-md-4">{{ "Model" | trans }}</div>
<div class="col-md-3">{{ "Identifiants" | trans }}</div>
<div class="col-md-2">{{ "Quantité" | trans }}</div>
<div class="col-md-2">{{ "Quantité disponible" | trans }}</div>
<div class="col-md-1"></div>
</div>
{{ form_row(form.materielMouvements) }}
</div>
<div class="row mb-2">
<div class="col-md-12">{{ form_row(form.commentaire) }}</div>
</div>
<div class="modal inmodal in" id="validation-modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content fadeIn">
<div class="modal-header">
<h3></h3>
</div>
<div class="modal-body">
{{ form_row(form.gestionnaire) }}
{{ form_row(form.codeSecret) }}
</div>
<div class="modal-footer">
<button class="btn btn-success" type="submit" name="btn_submit" value="1">
<i class="fa fa-save"></i>
{% trans %}Save and validate{% endtrans %}
</button>
<button type="button" class="btn btn-white" data-dismiss="modal">
{% trans %}Close{% endtrans %}
<i class="fa fa-times"></i>
</button>
</div>
</div>
</div>
</div>
<div class="hr-line-dashed"></div>
{% if not mouvement.valide %}
<div class="form-group text-center">
<a class="btn btn-white" href="{{ path('app.mouvement.list') }}">
<i class="fa fa-times"></i>
{% trans %}Cancel{% endtrans %}
</a>
<button class="btn btn-success" type="button" id="validation-btn" name="btn_submit" value="1">
<i class="fa fa-save"></i>
{% trans %}Save and validate{% endtrans %}
</button>
<button class="btn btn-primary" type="submit" name="btn_submit" value="0">
<i class="fa fa-save"></i>
{% trans %}Save{% endtrans %}
</button>
</div>
{% endif %}
{{ form_end(form) }}
</div>
{% endblock %}
{% block javascripts %}
<script src="{{ asset('/js/jquery.collection.js') }}"></script>
<script src="{{ asset('js/profileForm.js') }}"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.4.2/chosen.jquery.js"></script>
<script type="text/javascript">
$('#validation-btn').click(function(){
$('#validation-modal').modal('show');
});
$(document).ready(function () {
initChosen();
// Initialiser les champs en fonction de la valeur existante (édition)
$('#mouvement_form_motifMouvement').trigger('change');
$('#mouvement_form_agenceDepart').trigger('change');
$('#mouvement_form_agenceArrivee').trigger('change');
// $('.stock_select').trigger('change');
});
$('body').on('click', async function () {
initChosen();
});
function initChosen() {
$(".chosen-select").chosen();
}
$('#mouvement_form_materielMouvements').collection({
allow_up: false,
allow_down: false,
hide_useless_buttons: true,
init_with_n_elements: 1,
min: 1,
add: '<a href="#" class="collection-add btn btn-primary" style="position: absolute; top: -1rem; left: 25rem;"><span class="glyphicon glyphicon-plus-sign"></span></a>',
remove: '',
add_at_the_end: true,
after_add: function (collection, element) {
// initChosen();
}
});
const route = {
locaux: (agenceId) => Routing.generate('app.locaux_by_agence.get', { 'id': agenceId }),
nrs: (agenceId) => Routing.generate('app.nr_by_agence.get', { 'id': agenceId }),
clients: (agenceId) => Routing.generate('app.customers_by_agence.get', { 'id': agenceId }),
users: (agenceId) => Routing.generate('app.users_by_agence.get', { 'id': agenceId }),
stocksByLocal: (localId) => Routing.generate('app.locaux_by_agence.get', { 'id': agenceId }),
stockIdentifiants: (stockId) => Routing.generate('app.ids_from_stock.get', { 'id': stockId }),
};
const fillSelect = ($select, items, placeholder = 'Choisir', chosen = false) => {
$select.empty().append(new Option(placeholder, ''));
items.forEach(i => $select.append(new Option(i.label, i.id)));
if (chosen) $select.trigger('chosen:updated');
};
// Dépendances agences -> (locaux, nrs, clients, users)
$('#mouvement_form_agenceDepart').on('change', async function () {
const id = this.value;
if (!id) return;
await Promise.all([
loadInto(route.locaux(id), '#mouvement_form_localDepart', true),
loadInto(route.nrs(id), '#mouvement_form_nanoReseauDepart', true),
loadInto(route.clients(id), '#mouvement_form_clientDepart', true),
loadInto(route.users(id), '#mouvement_form_userDepart', true),
]);
const motif = $('#mouvement_form_motifMouvement').val();
if (parseInt(motif) == 1) {
$('#mouvement_form_agenceArrivee').val(id);
$('#mouvement_form_agenceArrivee').trigger('change');
$('#mouvement_form_agenceArrivee').prop('readonly', true);
$('#mouvement_form_agenceArrivee').hide();
} else {
$('#mouvement_form_agenceArrivee').show();
}
});
$('#mouvement_form_agenceArrivee').on('change', async function () {
const id = this.value;
if (!id) return;
await Promise.all([
loadInto(route.locaux(id), '#mouvement_form_localArrivee', true),
loadInto(route.nrs(id), '#mouvement_form_nanoReseauArrivee', true),
loadInto(route.clients(id), '#mouvement_form_clientArrivee', true),
loadInto(route.users(id), '#mouvement_form_userArrivee', true),
]);
});
// Local départ -> stocks de la collection[0] au départ (l'utilisateur peut ensuite dupliquer via jquery.collection)
$('body').on('change', '#mouvement_form_localDepart', async function () {
const localId = this.value; if (!localId) return;
const res = await fetch(route.stocksByLocal(localId));
const stocks = await res.json();
// Remplit le premier item existant; les suivants se dupliqueront
fillSelect($('#mouvement_form_materielMouvements_0_stock'), stocks, 'Choisir', true);
});
// Sur changement de stock: maj qteDisponible + identifiants
$('body').on('change', '.stock_select, [id$="_stock"]', async function () {
const $stock = $(this);
const stockId = $stock.val(); if (!stockId) return;
// Récupérer qte (depuis option si chargée via /ajax/stocks) sinon via attribut data-qte
const qte = parseInt($stock.find(':selected').data('qte') ?? 0, 10);
const idAttr = $stock.attr('id');
const pos = idAttr.match(/materielMouvements_(\d+)_stock/)[1];
// maj qteDisponible + contraintes
const $qteDispo = $(`#mouvement_form_materielMouvements_${pos}_qteDisponible`);
const $qte = $(`#mouvement_form_materielMouvements_${pos}_qte`);
const $ids = $(`#mouvement_form_materielMouvements_${pos}_identifiants`);
// Charger identifiants
const data = await (await fetch(route.stockIdentifiants(stockId))).json();
if ($stock.find(':selected').data('individuel') == '0') {
// $ids.prop('disabled', true);
let quantite = data.qte;
$qteDispo.val(quantite);
$qte.val(0).attr('max', quantite);
} else {
const ids = data.ids;
$qteDispo.val(ids.length);
$qte.val(0).attr('max', ids.length);
$qte.val(0).attr('min', 1);
$qte.prop('readonly', true);
fillSelect($ids, ids, 'Choisir', true);
// $ids.prop('disabled', qte <= 1);
}
});
// Synchroniser qte avec nombre d'identifiants sélectionnés (si multi)
$('body').on('change', '.identifiant_select', function () {
const id = $(this).attr('id');
const pos = id.match(/materielMouvements_(\d+)_identifiants/)[1];
const nb = ($(this).val() || []).length;
$(`#mouvement_form_materielMouvements_${pos}_qte`).val(nb);
});
function loadInto(url, selector, chosen = false) {
$.ajax({
url: url,
method: 'GET',
dataType: 'json',
success: function (data, textStatus, jqXHR) {
// Remplir le select
fillSelect($(selector), data, 'Choisir', chosen);
},
error: function (jqXHR, textStatus, errorThrown) {
console.error('[loadInto] ERREUR AJAX');
console.error('[loadInto] Status:', textStatus);
console.error('[loadInto] Code HTTP:', jqXHR.status);
console.error('[loadInto] Message:', errorThrown);
console.error('[loadInto] Réponse brute:', jqXHR.responseText);
},
});
}
$('#mouvement_form_motifMouvement').on('change', function () {
const motif = parseInt($(this).val());
// Cache tous les blocs
$('#local-depart, #local-arrivee, #nr-depart, #nr-arrivee, #client-depart, #client-arrivee, #user-depart, #user-arrivee, #autre-motif').hide();
// Désactive toutes les radios
$('#mouvement_form_typeEmplacementDepart input[type="radio"], #mouvement_form_typeEmplacementArrivee input[type="radio"]').prop('disabled', true).prop('checked', false);
// Réinitialise "required" partout
$('#mouvement_form input, #mouvement_form select').not('#mouvement_form_commentaire, [id*="identifiants"]').prop('required', false);
// Fonction utilitaire : affiche un bloc et rend ses champs requis
function showAndRequire(selector) {
$(selector).show();
// $(selector).find('select, input').not('#mouvement_form_commentaire, [id*="identifiants"]').prop('required', true);
}
switch (motif) {
case 1:
showAndRequire('#local-depart');
showAndRequire('#local-arrivee');
$('#mouvement_form_typeEmplacementDepart_1, #mouvement_form_typeEmplacementArrivee_1').prop('checked', true).prop('disabled', false);
break;
case 2:
showAndRequire('#local-depart');
showAndRequire('#user-arrivee');
$('#mouvement_form_typeEmplacementDepart_1, #mouvement_form_typeEmplacementArrivee_2').prop('checked', true).prop('disabled', false);
break;
case 3:
showAndRequire('#user-depart');
showAndRequire('#nr-arrivee');
$('#mouvement_form_typeEmplacementDepart_2, #mouvement_form_typeEmplacementArrivee_4').prop('checked', true).prop('disabled', false);
break;
case 4:
showAndRequire('#nr-depart');
showAndRequire('#nr-arrivee');
$('#mouvement_form_typeEmplacementDepart_4, #mouvement_form_typeEmplacementArrivee_4').prop('checked', true).prop('disabled', false);
break;
case 5:
showAndRequire('#local-depart');
showAndRequire('#nr-arrivee');
$('#mouvement_form_typeEmplacementDepart_1, #mouvement_form_typeEmplacementArrivee_4').prop('checked', true).prop('disabled', false);
break;
case 6:
showAndRequire('#nr-depart');
showAndRequire('#nr-arrivee');
$('#mouvement_form_typeEmplacementDepart_2, #mouvement_form_typeEmplacementArrivee_1').prop('checked', true).prop('disabled', false);
break;
case 7:
showAndRequire('#local-depart');
showAndRequire('#nr-arrivee');
$('#mouvement_form_typeEmplacementDepart_1, #mouvement_form_typeEmplacementArrivee_2').prop('checked', true).prop('disabled', false);
break;
case 8:
showAndRequire('#local-depart');
$('#mouvement_form_typeEmplacementDepart_1').prop('checked', true).prop('disabled', false);
break;
default:
showAndRequire('#autre-motif');
showAndRequire('#local-depart');
showAndRequire('#local-arrivee');
$('#mouvement_form_typeEmplacementDepart_1, #mouvement_form_typeEmplacementArrivee_1').prop('checked', true).prop('disabled', false);
break;
}
});
</script>
{% endblock %}