diff --git a/loko/stock/templates/stock/mobile/new_stock_batch_mobile.html b/loko/stock/templates/stock/mobile/new_stock_batch_mobile.html index 9bebd78..879ee88 100644 --- a/loko/stock/templates/stock/mobile/new_stock_batch_mobile.html +++ b/loko/stock/templates/stock/mobile/new_stock_batch_mobile.html @@ -38,6 +38,16 @@ {% endblock extra_head %} {% block content %} +{% if messages %} +
+ {% for message in messages %} + + {% endfor %} +
+{% endif %}
{% csrf_token %} @@ -368,17 +378,20 @@ function initProductAutocomplete(lineEl) { ? `${p.total_stock}` : `0`; item.innerHTML = `${escHtml(p.text)} ${escHtml(p.code || '')}${stockBadge}`; - item.addEventListener('mousedown', e => { + const selectProduct = (e) => { e.preventDefault(); hiddenInput.value = p.id; searchInput.value = p.text + (p.code ? ' (' + p.code + ')' : ''); + searchInput.classList.remove('is-invalid'); resultsBox.style.display = 'none'; if (p.is_serialized) { fetchSerializedItems(lineEl, p.id); } else { resetSerializedSection(lineEl); } - }); + }; + item.addEventListener('pointerdown', selectProduct); + item.addEventListener('mousedown', selectProduct); resultsBox.appendChild(item); }); } @@ -389,7 +402,7 @@ function initProductAutocomplete(lineEl) { }); searchInput.addEventListener('blur', () => { - setTimeout(() => { resultsBox.style.display = 'none'; }, 150); + setTimeout(() => { resultsBox.style.display = 'none'; }, 250); }); } @@ -694,7 +707,8 @@ function onCompanyInputChange() { // ── Filtrage des personnes par entreprise ──────────────────── function filterPersonsByCompany(companyId) { const personSelect = document.getElementById('person_id'); - const currentVal = personSelect.value; + if (!personSelect) return; + const currentOpt = personSelect.selectedIndex >= 0 ? personSelect.options[personSelect.selectedIndex] : null; Array.from(personSelect.options).forEach(opt => { if (!opt.value) return; // keep the blank option always const allowedCompanies = (opt.dataset.companies || '').split(','); @@ -751,13 +765,15 @@ if (bpSearchInput) { const item = document.createElement('div'); item.className = 'list-group-item list-group-item-action py-2 small'; item.innerHTML = `${escHtml(bp.text)} ${escHtml(bp.status)}`; - item.addEventListener('mousedown', e => { + const selectBp = (e) => { e.preventDefault(); bpHiddenId.value = bp.id; bpSearchInput.value = bp.text; bpResults.style.display = 'none'; if (bpLoadBtn) bpLoadBtn.disabled = false; - }); + }; + item.addEventListener('pointerdown', selectBp); + item.addEventListener('mousedown', selectBp); bpResults.appendChild(item); }); } @@ -767,7 +783,7 @@ if (bpSearchInput) { }, 280); }); bpSearchInput.addEventListener('blur', () => { - setTimeout(() => { bpResults.style.display = 'none'; }, 150); + setTimeout(() => { bpResults.style.display = 'none'; }, 250); }); } diff --git a/loko/stock/templates/stock/new_stock_batch.html b/loko/stock/templates/stock/new_stock_batch.html index 9581b41..682ea38 100644 --- a/loko/stock/templates/stock/new_stock_batch.html +++ b/loko/stock/templates/stock/new_stock_batch.html @@ -42,6 +42,17 @@ + {% if messages %} +
+ {% for message in messages %} + + {% endfor %} +
+ {% endif %} + {% csrf_token %} diff --git a/loko/stock/views.py b/loko/stock/views.py index b05d269..9282153 100644 --- a/loko/stock/views.py +++ b/loko/stock/views.py @@ -947,7 +947,13 @@ def _new_stock_batch_view(request, movement_type, return redirect(cancel_url_name) products = Product.objects.select_related("category").order_by("name") - locations = list(WarehouseLocation.objects.select_related("warehouse").order_by("warehouse__name", "name")) + locations = list( + filter_locations_by_permission( + WarehouseLocation.objects.select_related("warehouse"), + request.user, + can_manage=True + ).order_by("warehouse__name", "name") + ) from stock.permissions import user_can_administer_warehouse for loc in locations: loc.can_administer = user_can_administer_warehouse(request.user, loc.warehouse) @@ -1102,7 +1108,13 @@ def _new_stock_batch_view(request, movement_type, errors.append(_("Ligne %(n)s : produit invalide.") % {'n': i + 1}) continue - lines.append({'product_id': pid, 'qty': qty, 'src': src, 'dst': dst}) + lines.append({ + 'product_id': pid, + 'qty': qty, + 'src': src, + 'dst': dst, + 'line_index': i, + }) if errors: for err in errors: @@ -1153,9 +1165,10 @@ def _new_stock_batch_view(request, movement_type, reason=reason, batch=batch, ) + line_idx = line.get('line_index', 0) # Articles tracés (numéros de série) if product.is_serialized: - ids_str = serialized_ids_list[i] if i < len(serialized_ids_list) else '' + ids_str = serialized_ids_list[line_idx] if line_idx < len(serialized_ids_list) else '' s_ids = [int(x) for x in ids_str.split(',') if x.strip().isdigit()] s_items = list(SerializedItem.objects.filter(pk__in=s_ids, product=product)) if s_ids else [] if s_items: @@ -1165,7 +1178,7 @@ def _new_stock_batch_view(request, movement_type, ) # Nouveaux articles tracés (entrée uniquement) - new_serials_str = serialized_new_serials_list[i] if i < len(serialized_new_serials_list) else '' + new_serials_str = serialized_new_serials_list[line_idx] if line_idx < len(serialized_new_serials_list) else '' new_items = [] if movement_type == 'in' and new_serials_str.strip(): for sn in [s.strip() for s in new_serials_str.split(',') if s.strip()]: