Codifarticle AJAX with jQuery example ¶
Contents
articles.urls.py ¶
from .views_codif_article import view_update_codifarticle
path(
"ajax/codif_article_update",
view_update_codifarticle,
name="ajax_update_codif_article",
),
views.view_update_codifarticle ¶
1 import logging
2 from typing import Any, Dict
3 from datetime import datetime
4 from django.utils import timezone
5
6 from django.contrib import messages
7
8 from django.contrib.auth.mixins import LoginRequiredMixin
9 from django.contrib.auth.decorators import login_required
10
11 from django.http.request import HttpRequest
12 from django.http import HttpResponseRedirect, JsonResponse
13 from django.apps import apps
14 from django.forms.models import modelform_factory
15 from django.http import HttpResponseRedirect
16 from django.shortcuts import get_object_or_404, redirect
17 from django.urls import reverse
18 from django.views.generic.base import TemplateResponseMixin, View
19 from django.views.generic.edit import DeleteView, UpdateView
20
21 from employes.models import Employe
22
23 from .forms_codif_article import CodifArticleFormSetExtra0, CodifArticleFormSetExtra1
24 from .forms_demande_article import DemandeArticleUpdateFormInLine
25 from .models_codif_article import CodifArticle, DocCodifArticle, ReponseCodifArticle
26 from .models_demande_article import DemandeArticle
27
28 from projets.models import Projet
29 from articles.models import Article
30 from fabricants.models import Fabricant
31 from fournisseurs.models import Fournisseur
32
33
34 # Get an instance of a logger
35 logger = logging.getLogger(__name__)
36
37
38 def view_update_codifarticle(request: HttpRequest) -> JsonResponse:
39 """Mise à jour des codifications article par requete AJAX.
40 """
41 logger.info("Enter view_update_codifarticle()")
42
43 codif_article_id = request.GET.get("id", None)
44 logger.info(f"{codif_article_id=}")
45
46 try:
47 codif_article = CodifArticle.objects.get(pk=codif_article_id)
48 if codif_article.demande_cloturee():
49 data = {}
50 data["update"] = False
51 logger.info(f"No change authorized")
52 return JsonResponse(data)
53 else:
54 logger.info(f"Demande non cloturée {codif_article.demande_article}")
55
56 except:
57 pass
58
59
60 etat_poste = request.GET.get("etat_poste", None)
61 reponse = request.GET.get("reponse", None)
62 ofda = request.GET.get("ofda", None)
63
64 projet = request.GET.get("projet_id", None)
65 if projet is not None:
66 try:
67 projet = Projet.objects.get(pk=projet)
68 except Exception as error:
69 logger.error(f"view_update_codifarticle {error=}")
70
71 article = request.GET.get("article_id", None)
72 if article is not None:
73 try:
74 article = Article.objects.get(pk=article)
75 except Exception as error:
76 logger.error(f"view_update_sortie_stock {error=}")
77
78 designation = request.GET.get("designation", None)
79 fabricant = request.GET.get("fabricant_id", None)
80 if fabricant is not None:
81 try:
82 fabricant = Fabricant.objects.get(pk=fabricant)
83 except Exception as error:
84 logger.error(f"view_update_codifarticle {error=}")
85
86 ref_fabricant = request.GET.get("ref_fabricant", None)
87 fournisseur = request.GET.get("fournisseur_id", None)
88 if fournisseur is not None:
89 try:
90 fournisseur = Fournisseur.objects.get(pk=fournisseur)
91 except Exception as error:
92 logger.error(f"view_update_codifarticle {error=}")
93
94 ref_fournisseur = request.GET.get("ref_fournisseur", None)
95 date_butoir = None
96 try:
97 date_butoir_str = request.GET.get("date_butoir", None)
98 format_str = "%d/%m/%Y %H:%M"
99 date_butoir_unaware = datetime.strptime(
100 date_butoir_str, format_str
101 )
102 date_butoir = timezone.make_aware(
103 date_butoir_unaware, timezone.get_current_timezone()
104 )
105 logger.info(f"{date_butoir_str=} {date_butoir=}")
106 except Exception as error:
107 # logger.error(f"view_update_sortie_stock {error=}")
108 pass
109
110
111 demande_codification = request.GET.get("demande_codification", None)
112 if demande_codification is not None:
113 logger.info(f"{demande_codification=}")
114 if demande_codification == "true":
115 demande_codification = True
116 else:
117 demande_codification = False
118
119 besoin_reel = request.GET.get("besoin_reel", None)
120 besoin_potentiel = request.GET.get("besoin_potentiel", None)
121 sortie_stock = request.GET.get("sortie_stock", None)
122 cotation_par = request.GET.get("cotation_par", None)
123
124 data = {}
125 data["update"] = False
126 try:
127 save = False
128 msg = ""
129 if etat_poste is not None:
130 logger.info(f"{etat_poste=}")
131 codif_article.etat_poste = etat_poste
132 msg = f"new etat_poste:{etat_poste}"
133 save = True
134
135 if reponse is not None:
136 logger.info(f"{reponse=}")
137 codif_article.reponse = reponse
138 msg = f"new reponse:{reponse}"
139 save = True
140
141 if ofda is not None:
142 logger.info(f"{ofda=}")
143 codif_article.ofda = ofda
144 msg = f"new ofda:{ofda}"
145 save = True
146
147 if article is not None:
148 codif_article.article = article
149 msg = f"new article:{article}"
150 save = True
151
152 if projet is not None:
153 codif_article.projet = projet
154 msg = f"new projet:{projet}"
155 save = True
156
157 if designation is not None:
158 codif_article.designation = designation
159 msg = f"new designation:{designation}"
160 save = True
161
162 if fabricant is not None:
163 codif_article.fabricant = fabricant
164 msg = f"new fabricant:{fabricant}"
165 save = True
166
167 if ref_fabricant is not None:
168 codif_article.ref_fabricant = ref_fabricant
169 msg = f"new ref_fabricant:{ref_fabricant}"
170 save = True
171
172 if fournisseur is not None:
173 codif_article.fournisseur = fournisseur
174 msg = f"new fournisseur:{fournisseur}"
175 save = True
176
177 if ref_fournisseur is not None:
178 codif_article.ref_fournisseur = ref_fournisseur
179 msg = f"new ref_fournisseur:{ref_fournisseur}"
180 save = True
181
182 if date_butoir is not None:
183 codif_article.date_butoir = date_butoir
184 msg = f"new date_butoir:{date_butoir}"
185 save = True
186
187 if demande_codification is not None:
188 # logger.info(f"{demande_codification=}")
189 codif_article.demande_codification = demande_codification
190 msg = f"new demande_codification:{demande_codification}"
191 save = True
192
193 if besoin_reel is not None:
194 codif_article.besoin_reel = besoin_reel
195 msg = f"new besoin_reel:{besoin_reel}"
196 save = True
197
198 if besoin_potentiel is not None:
199 logger.info(f"{besoin_potentiel=}")
200 codif_article.besoin_potentiel = besoin_potentiel
201 msg = f"new besoin_potentiel:{besoin_potentiel}"
202 save = True
203
204 if sortie_stock is not None:
205 logger.info(f"{sortie_stock=}")
206 codif_article.sortie_stock = sortie_stock
207 msg = f"new sortie_stock:{sortie_stock}"
208 save = True
209
210 if cotation_par is not None:
211 logger.info(f"{cotation_par=}")
212 codif_article.cotation_par = cotation_par
213 msg = f"new cotation_par:{cotation_par}"
214 save = True
215
216 if save:
217 codif_article.save()
218 data["update"] = msg
219 # retour data
220 if article is not None:
221 data["libelle_article"] = article.get_libelle()
222 if projet is not None:
223 data["libelle_projet"] = projet.get_libelle()
224
225 except Exception as error:
226 logger.error(f"view_update_codifarticle {error=}")
227
228 return JsonResponse(data)
articles.templates.articles.demande.achat_service.articles_update.html ¶
1{% extends "base.html" %}
2{% load static %}
3{% load djmoney %}
4{% load article %}
5
6{% block stylesheet %}
7 <link rel="stylesheet" href="{% static 'css/couleurs_demande_article.css' %}">
8
9 <!-- CSS pour datetime picker -->
10 <link rel="stylesheet" href="{% static 'js/jquery.datetimepicker.min.css' %}">
11
12 <!-- CSS pour autocomplete_light -->
13 <link rel="stylesheet" href="{% static 'select2/css/select2.css' %}">
14 <link rel="stylesheet" href="{% static 'autocomplete_light/select2.css' %}">
15
16 <!-- Bordure des tables -->
17 <link rel="stylesheet" href="{% static 'css/table.css' %}">
18{% endblock %}
19
20
21{% block javascript %}
22
23 {# a employer dans les templates fils->{{ block.super }} #}
24 {{ block.super }}
25 <script src="{% static 'js/jquery.datetimepicker.full.js' %}"></script>
26
27 <script src="{% static 'autocomplete_light/jquery.init.js' %}"></script>
28 <script src="{% static 'autocomplete_light/autocomplete.init.js' %}"></script>
29 <script src="{% static 'select2/js/select2.full.js' %}"></script>
30 <script src="{% static 'autocomplete_light/forward.js' %}"></script>
31 <script src="{% static 'autocomplete_light/select2.js' %}"></script>
32
33
34{% endblock javascript %}
35
36
37
38{% block extra_js %}
39{# Code composé de Javascript et de Django Template Language #}
40{# ========================================================= #}
41
42<script type="text/javascript">
43
44{% comment %}
45https://learn.jquery.com/using-jquery-core/document-ready/
46
47Experienced developers sometimes use the shorthand $() for $( document ).ready().
48If you are writing code that people who aren't experienced with jQuery may see,
49it's best to use the long form.
50
51{% endcomment %}
52
53$(document).ready(function() {
54
55 // langue française pour les datetime pickers
56 $.datetimepicker.setLocale('fr');
57
58 {% for form_achat in formset_achats %}
59 $('#id_achatservice_related-{{ forloop.counter0 }}-etat_poste').change(function () {
60 let etat_poste = $(this).val()
61 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
62 let url = '{% url "articles:ajax_update_achat_service" %}';
63 $.ajax(
64 {
65 url: url,
66 data: {
67 'id': achatservice_id,
68 'etat_poste': etat_poste,
69 },
70 dataType: 'json',
71 success: function (data) {
72 // alert("Retour:" + data.update);
73 }
74 }
75 );
76 });
77 $('#id_achatservice_related-{{ forloop.counter0 }}-reponse').change(function () {
78 let reponse = $(this).val()
79 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
80 let url = '{% url "articles:ajax_update_achat_service" %}';
81 $.ajax(
82 {
83 url: url,
84 data: {
85 'id': achatservice_id,
86 'reponse': reponse,
87 },
88 dataType: 'json',
89 success: function (data) {
90 // alert("Retour:" + data.update);
91 }
92 }
93 );
94 });
95 $('#id_achatservice_related-{{ forloop.counter0 }}-article').change(function () {
96 let article_id = $(this).val()
97 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
98 let libelle_article = document.getElementById('libelle_article_{{ forloop.counter0 }}');
99
100 // alert("achatservice_id=" + achatservice_id + " article_id=" + article_id + + " libelle=" + libelle_article.textContent);
101 let url = '{% url "articles:ajax_update_achat_service" %}';
102
103 $.ajax(
104 {
105 url: url,
106 data: {
107 'id': achatservice_id,
108 'article_id': article_id,
109 },
110 dataType: 'json',
111 success: function (data) {
112 // alert("Retour:" + data.update + " libelle article:" + data.libelle_article);
113 libelle_article.textContent = data.libelle_article
114 }
115 }
116 );
117 });
118 $('#id_achatservice_related-{{ forloop.counter0 }}-projet').change(function () {
119 let projet_id = $(this).val()
120 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
121 let libelle_projet = document.getElementById('libelle_projet_{{ forloop.counter0 }}');
122
123 // alert("achatservice_id=" + achatservice_id + " projet_id=" + projet_id + " libelle=" + libelle_projet.textContent);
124 let url = '{% url "articles:ajax_update_achat_service" %}';
125 $.ajax(
126 {
127 url: url,
128 data: {
129 'id': achatservice_id,
130 'projet_id': projet_id,
131 },
132 dataType: 'json',
133 success: function (data) {
134 // alert("Retour:" + data.update);
135 libelle_projet.textContent = data.libelle_projet
136 }
137 }
138 );
139 });
140 $('#id_achatservice_related-{{ forloop.counter0 }}-prestataire').change(function () {
141 {# un prestataire est un tiers (classe Tiers et Prestataire proxy sur Tiers #}
142 let prestataire_id = $(this).val()
143 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
144 let libelle_prestataire = document.getElementById('libelle_prestataire_{{ forloop.counter0 }}');
145
146 // alert("achatservice_id=" + achatservice_id + " prestataire_id=" + prestataire_id + " libelle=" + libelle_prestataire.textContent);
147 let url = '{% url "articles:ajax_update_achat_service" %}';
148 $.ajax(
149 {
150 url: url,
151 data: {
152 'id': achatservice_id,
153 'prestataire_id': prestataire_id,
154 },
155 dataType: 'json',
156 success: function (data) {
157 // alert("Retour:" + data.update);
158 libelle_prestataire.textContent = data.libelle_prestataire
159 }
160 }
161 );
162 });
163 $('#id_achatservice_related-{{ forloop.counter0 }}-description').change(function () {
164 let description = $(this).val()
165 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
166 let url = '{% url "articles:ajax_update_achat_service" %}';
167 $.ajax(
168 {
169 url: url,
170 data: {
171 'id': achatservice_id,
172 'description': description,
173 },
174 dataType: 'json',
175 success: function (data) {
176 // alert("Retour:" + data.update);
177 }
178 }
179 );
180 });
181 $('#id_achatservice_related-{{ forloop.counter0 }}-quantite').change(function () {
182 let quantite = $(this).val()
183 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
184 let url = '{% url "articles:ajax_update_achat_service" %}';
185 // alert("achatservice_id=" + achatservice_id + " quantite=" + quantite);
186 $.ajax(
187 {
188 url: url,
189 data: {
190 'id': achatservice_id,
191 'quantite': quantite,
192 },
193 dataType: 'json',
194 success: function (data) {
195 // alert("Retour:" + data.update);
196 }
197 }
198 );
199 });
200 $('#id_achatservice_related-{{ forloop.counter0 }}-prix_unitaire_0').change(function () {
201 let prix_unitaire = $(this).val()
202 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
203 let url = '{% url "articles:ajax_update_achat_service" %}';
204 // alert("achatservice_id=" + achatservice_id + " prix unitaire=" + prix_unitaire);
205 $.ajax(
206 {
207 url: url,
208 data: {
209 'id': achatservice_id,
210 'prix_unitaire': prix_unitaire,
211 },
212 dataType: 'json',
213 success: function (data) {
214 // alert("Retour:" + data.update);
215 }
216 }
217 );
218 });
219
220 $('#id_achatservice_related-{{ forloop.counter0 }}-prix_unitaire_1').change(function () {
221 let currency = $(this).val()
222 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
223 let url = '{% url "articles:ajax_update_achat_service" %}';
224 // alert("achatservice_id=" + achatservice_id + " currency=" + currency);
225 $.ajax(
226 {
227 url: url,
228 data: {
229 'id': achatservice_id,
230 'currency': currency,
231 },
232 dataType: 'json',
233 success: function (data) {
234 // alert("Retour:" + data.update);
235 }
236 }
237 );
238
239 });
240
241
242 $('#id_achatservice_related-{{ forloop.counter0 }}-date_butoir').change(function () {
243 let date_butoir = $(this).val()
244 let achatservice_id = $('#id_achatservice_related-{{ forloop.counter0 }}-id').val();
245 let url = '{% url "articles:ajax_update_achat_service" %}';
246 $.ajax(
247 {
248 url: url,
249 data: {
250 'id': achatservice_id,
251 'datetime_livraison': date_butoir,
252 },
253 dataType: 'json',
254 success: function (data) {
255 }
256 }
257 );
258 });
259
260
261 {# Choix de la livraison souhaitée #}
262 $('#id_achatservice_related-{{ forloop.counter0 }}-date_butoir').datetimepicker(
263 {
264 // http://marcocecchetti.it/Post/Articolo/608
265 weeks: true,
266 rtl: false,
267 // formatTime:'H:i',
268 // formatDate:'d/m/Y',
269 format: 'd/m/Y H:i',
270 // date
271 datepicker: true,
272 opened: false,
273 todayButton: true, // Show button "Go To Today"
274 defaultSelect: true, // Highlight the current date even if the input is empty
275 dayOfWeekStart : 1, // Start week DatePicker. Default Sunday=0.
276 defaultDate: false,
277 // https://secure.php.net/manual/fr/function.date.php
278 minDate:0, // today
279 weekends : [],
280 disabledDates : [],
281 // time
282 timepicker:true,
283 timepickerScrollbar:true,
284 step: 60,
285 defaultTime:'10:00',
286 allowTimes:[
287 '8:00', '9:00', '10:00', '11:00', '12:00',
288 '13:00', '14:00', '15:00', '16:00', '17:00',
289 '18:00', '19:00'
290 ]
291 }
292 );
293
294 {% endfor %}
295
296});
297
298</script>
299{% endblock extra_js %}
300
301
302{% block content %}
303
304
305<a class="btn btn-success" href="{% url 'articles:demande_article_non_cloturee_list' %}">Liste des demandes non clôturées</a>
306<a class="btn btn-success" href="{% url 'articles:demande_article_list' %}">Liste de toutes les demandes</a>
307
308
309{% url 'articles:demande_achat_service_update' demande_article.pk as url_demande_achat_service_update %}
310
311
312{# https://getbootstrap.com/components/#labels #}
313
314{% if demande_article.demande_non_transmise %}
315<h4 class="couleur_demande_non_transmise">
316{% elif demande_article.demande_transmise %}
317<h4 class="couleur_demande_transmise">
318{% elif demande_article.demande_en_cours %}
319<h4 class="couleur_demande_en_cours">
320{% elif demande_article.demande_traitee %}
321<h4 class="couleur_demande_traitee">
322{% elif demande_article.demande_cloturee %}
323<h4 class="couleur_demande_cloturee">
324{% endif %}
325 <a href="{{ url_demande_achat_service_update }}">
326 Demande N°{{ demande_article.id }}
327 </a>
328 {{ demande_article.get_description_without_crlf}}
329</h4>
330
331
332{% if messages %}
333 <ul class="messages">
334 {% comment %} https://getbootstrap.com/components/#alerts {% endcomment %}
335 {% for message in messages %}
336 <!--li{% if message.tags %} class="{{ message.tags }}"{% endif %} -->
337 {% if message.level == DEFAULT_MESSAGE_LEVELS.ERROR %}
338 <div class="alert alert-danger" role="alert">{{ message }}</div>
339 {% elif message.level == DEFAULT_MESSAGE_LEVELS.SUCCESS %}
340 <div class="alert alert-success" role="alert">{{ message }}</div>
341 {% else %}
342 <div class="alert alert-info" role="alert">{{ message }}</div>
343 {% endif %}
344 <!-- /li -->
345 {% endfor %}
346 </ul>
347{% endif %}
348
349{% url 'tiers:create' as url_tiers_create %}
350
351<form id="articles_achats" method="post" action=".">
352 {% csrf_token %}
353 <input type="hidden" name="demande_article" value="{{ demande_article }}">
354 <div class="table-responsive">
355 <table id="id_list_table" class="table table-condensed">
356 <thead>
357 <tbody>
358 {{ formset_achats.management_form }}
359 {# rajout des erreurs #}
360 {% if formset_achats.errors %}
361 {% for error in formset_achats.non_field_errors %}
362 <div class="alert alert-error">
363 <strong>{{ error|escape }}</strong>
364 </div>
365 {% endfor %}
366 {% endif %}
367 {# Parcours des formulaires et des instances initiales associées #}
368 {% for form_achat, achat_service in formset_instances %}
369 {{ form_achat.id }}
370 <tr>
371 <td>
372 <table id="id_table_in_table" class="table table-hover table-condensed
373 {% if forloop.counter|divisibleby:"2" %}
374 table-pair
375 {% else %}
376 table-impair
377 {% endif %}
378 ">
379 {# un element de formulaire => un tableau dans un tableau #}
380 <tbody>
381 <tr>
382 {% url 'articles:achat_service_delete' form_achat.id.value as url_achat_service_delete %}
383 {% url 'articles:achat_service_clone' form_achat.id.value as url_achat_service_clone %}
384 {% if forloop.counter <= nb_articles %}
385 <td colspan=2 id={{ forloop.counter }}>
386 {% for num_article in list_articles %}
387 {% if num_article != forloop.parentloop.counter %}
388 <a href="#{{ num_article }}">Achat {{ num_article }}</a>
389 {% else %}
390 Achat {{ forloop.parentloop.counter }} N°{{achat_service.id }}
391 {% endif %}
392 {% endfor %}
393 {% if demande_article.demande_non_cloturee %}
394 <a href="{{ url_achat_service_clone }}">| Ajouter un article</a>
395 <a href="{{ url_achat_service_delete }}">| Supprimer un article</a
396 {% if forloop.counter >= 2 %}
397 <ul class=list-group>
398 <li class="alert alert-success list-group-item">
399 <a href="{{ url_demande_achat_service_update }}">Demande article N°{{ demande_article.id }}</a>
400 {{ demande_article.get_description_without_crlf }}
401 </li>
402 </ul>
403 {% endif %}
404 {% endif %}
405 </td>
406 {% else %}
407 <td colspan=2>
408 </td>
409 {% endif %}
410 </tr>
411 {% if demande_article.reponse_affichable %}
412 <tr>
413 {% comment %} Affichage en vert quand l'état du poste est dans l'état "Traité" {% endcomment %}
414 <td {% if achat_service.is_poste_traite %} class="text-right poste_traite" {% else %} class="text-right" {% endif %}>
415 Etat du poste {{ form_achat.etat_poste }}
416 </td>
417 <td {% if achat_service.is_poste_traite %} {% else %} class="info" {% endif %}>
418 Réponse {{ form_achat.reponse }}
419 </td>
420 </tr>
421 {% if achat_service.demande_cloturee_and_no_responses %}
422 {% else %}
423 <tr>
424 {% url 'articles:achat_service_reponse_list' achat_service.id as url_list_reponses %}
425 <td class="text-right">
426 {% if demande_article.demande_non_cloturee %}
427 <a href="{{ url_list_reponses }}">Documents réponse</a>
428 {% else %}
429 Documents réponse
430 {% endif %}
431 </td>
432 <td>
433 {% if forloop.counter <= nb_articles %}
434 {% for document in achat_service.responses.all %}
435 {% with media=document.item %}
436 {# https://getbootstrap.com/css/#tables-example #}
437 <p>{{ media.render }} </p>
438 {% endwith %}
439 {% endfor %}
440 {% endif %}
441 </td>
442 </tr>
443 {% endif %}
444 {% endif %}
445 <tr>
446 <td class="text-right">Code article</td>
447 <td class="danger">
448 {% if demande_article.demande_non_cloturee %}
449 {{ form_achat.article }}
450 {% endif %}
451 <span id="libelle_article_{{ forloop.counter0 }}"> {{ achat_service.get_libelle_article }}</span>
452 </td>
453 </tr>
454 <tr>
455 <td class="text-right">Projet</td>
456 <td>
457 {% if demande_article.demande_non_cloturee %}
458 {{ form_achat.projet }}
459 {% endif %}
460 <span id="libelle_projet_{{ forloop.counter0 }}" {{ achat_service.get_libelle_projet }} </span>
461 </td>
462 </tr>
463 <tr>
464 <td class="text-right">Description</td>
465 <td>{{ form_achat.description }}</td>
466 </tr>
467 <tr>
468 <td class="text-right">Prestataire</td>
469 <td>
470 {% if demande_article.demande_non_cloturee %}
471 {{ form_achat.prestataire }}
472 <a href="{{ url_tiers_create }}"> <img src="{% static "tiers/icon-addlink.svg" %}" alt="Ajouter"/> </a>
473 {% endif %}
474 <span id="libelle_prestataire_{{ forloop.counter0 }}" {{ achat_service.get_libelle_prestataire }} </span>
475 </td>
476 </tr>
477 <tr>
478 <td class="text-right">Quantite</td>
479 <td>{{ form_achat.quantite }} Prix {{ form_achat.prix_unitaire }} </td>
480 </tr>
481 <tr>
482 <td class="text-right">Livraison souhaitée</td>
483 <td class="danger">{{ form_achat.date_butoir }}</td>
484 </tr>
485 {% if achat_service.demande_cloturee_and_no_documents %}
486 {% else %}
487 <tr>
488 {% url 'articles:achat_service_doc_list' achat_service.id as url_list_documents %}
489 <td class="text-right">
490 {% if demande_article.demande_non_cloturee %}
491 {% if forloop.counter <= nb_articles %}
492 <a href="{{ url_list_documents }}">Documents associés</a>
493 {% endif %}
494 {% else %}
495 Documents associés
496 {% endif %}
497 </td>
498 <td>
499 {% if forloop.counter <= nb_articles %}
500 {% for document in achat_service.contents.all %}
501 {% with media=document.item %}
502 <p>{{ media.render }} </p>
503 {% endwith %}
504 {% endfor %}
505 {% endif %}
506 </td>
507 </tr>
508 {% endif %}
509 <tr>
510 <td colspan=2>
511 </td>
512 </tr>
513 </tbody>
514 {# table imbriquee #}
515 </table>
516 </td>
517 </tr>
518 {% endfor %}
519 </tbody>
520 </table>
521 </div>
522</form>
523
524
525
526{% endblock %}
527
528
529{% block footer %}
530{% endblock footer %}