(function () { 'use strict'; function qs(sel, root) { return (root || document).querySelector(sel); } function qsa(sel, root) { return Array.prototype.slice.call((root || document).querySelectorAll(sel)); } function resolveUrl() { return window.DEVIS_AJAX_URL || window.ajaxUrl || ''; } /* ───────────────────────────────────────────── Helpers affichage client ───────────────────────────────────────────── */ function asText(value) { if (value === null || value === undefined) return ''; return String(value).trim(); } function buildCustomerDisplayLabel(row) { if (!row) return ''; var firstname = asText(row.firstname); var lastname = asText(row.lastname); var email = asText(row.email); var name = (firstname + ' ' + lastname).trim(); if (name && email) return name + ' (' + email + ')'; if (name) return name; if (email) return '(' + email + ')'; return ''; } function getCustomerShopLabel(row) { if (!row) return ''; var shopLabel = asText(row.shop_label); if (shopLabel) return shopLabel; var idShop = parseInt(row.id_shop, 10); var shopName = asText(row.shop_name); if (idShop > 0 && shopName) { return 'Shop ' + idShop + ' — ' + shopName; } if (idShop > 0) { return 'Shop ' + idShop; } return ''; } function buildCustomerSearchResultText(row) { var base = buildCustomerDisplayLabel(row); var shop = getCustomerShopLabel(row); if (base && shop) return base + ' — ' + shop; return base; } function updateSelectedCustomerLabel(row) { var lbl = qs('#devisCustomerSelectedLabel'); if (!lbl) return; if (!row) { lbl.textContent = ''; return; } var base = buildCustomerDisplayLabel(row); if (!base) { base = asText(row.label); } var shop = getCustomerShopLabel(row); if (base && shop) { lbl.textContent = base + ' — ' + shop; } else { lbl.textContent = base; } } /* ── Champs cachés client ── */ function setCustomerFields(idCust, idAddrInv, idAddrDel) { var elC = qs('input[name="id_customer"]'); var elI = qs('input[name="id_address_invoice"]'); var elD = qs('input[name="id_address_delivery"]'); if (elC) elC.value = idCust || 0; if (elI) elI.value = idAddrInv || 0; if (elD) elD.value = idAddrDel || 0; } /* ── Recherche client ── */ function bindCustomerSearch() { var input = qs('#devisCustomerSearch'); var results = qs('#devisCustomerResults'); if (!input || !results) return; var timer = null; input.addEventListener('input', function () { var v = input.value.trim(); if (timer) clearTimeout(timer); if (v.length < 2) { results.style.display = 'none'; return; } timer = setTimeout(function () { var p = new URLSearchParams(); p.append('ajax', '1'); p.append('action', 'SearchCustomers'); p.append('q', v); fetch(resolveUrl(), { method: 'POST', body: p }) .then(function (r) { return r.json(); }) .then(function (rows) { results.innerHTML = ''; if (!rows || !rows.length) { results.style.display = 'none'; return; } rows.forEach(function (r) { var a = document.createElement('a'); a.className = 'list-group-item'; a.style.cursor = 'pointer'; a.textContent = buildCustomerSearchResultText(r); a.addEventListener('click', function (e) { e.preventDefault(); setCustomerFields( r.id_customer, r.id_address_invoice || 0, r.id_address_delivery || 0 ); updateSelectedCustomerLabel(r); var msg = qs('#devisCustomerMsg'); if (msg) msg.innerHTML = ' Client lié.'; results.style.display = 'none'; recalcTotals(); }); results.appendChild(a); }); results.style.display = 'block'; }) .catch(function () { results.style.display = 'none'; }); }, 250); }); } /* ── Créer / Lier client ── */ function bindCreateCustomer() { var btn = qs('#devisCreateCustomerBtn'); if (!btn) return; btn.addEventListener('click', function (e) { e.preventDefault(); var email = ((qs('#devisC_email') || {}).value || '').trim(); var firstname = ((qs('#devisC_firstname') || {}).value || '').trim(); var lastname = ((qs('#devisC_lastname') || {}).value || '').trim(); var company = ((qs('#devisC_company') || {}).value || '').trim(); var address1 = ((qs('#devisC_address1') || {}).value || '').trim(); var postcode = ((qs('#devisC_postcode') || {}).value || '').trim(); var city = ((qs('#devisC_city') || {}).value || '').trim(); var id_country = ((qs('#devisC_id_country') || {}).value || '0'); var msg = qs('#devisCustomerMsg'); if (!email || !firstname || !lastname) { if (msg) msg.innerHTML = ' Email, prénom et nom sont obligatoires.'; return; } if (msg) msg.innerHTML = ' Traitement…'; var p = new URLSearchParams(); p.append('ajax', '1'); p.append('action', 'CreateCustomer'); p.append('email', email); p.append('firstname', firstname); p.append('lastname', lastname); p.append('company', company); p.append('address1', address1); p.append('postcode', postcode); p.append('city', city); p.append('id_country', id_country); fetch(resolveUrl(), { method: 'POST', body: p }) .then(function (r) { return r.json(); }) .then(function (res) { if (res && res.ok) { setCustomerFields( res.id_customer, res.id_address_invoice, res.id_address_delivery ); var displayData = { firstname: asText(res.firstname) || firstname, lastname: asText(res.lastname) || lastname, email: asText(res.email) || email, id_shop: res.id_shop, shop_name: res.shop_name, shop_label: res.shop_label, }; updateSelectedCustomerLabel(displayData); if (msg) msg.innerHTML = res.linked ? ' Client existant lié au devis.' : ' Client créé et lié !'; recalcTotals(); } else { var err = (res && res.errors) ? res.errors.join(', ') : 'Erreur inconnue'; if (msg) msg.innerHTML = ' ' + err + ''; } }) .catch(function () { if (msg) msg.innerHTML = 'Erreur réseau.'; }); }); } /* ── Lire le JSON "live" ── */ function getLiveProductsJson() { var products = []; var container = qs('#products-tbody') || qs('#devis-products-panel'); if (!container) return null; qsa('tr[data-id], tr[data-product-id]', container).forEach(function (tr) { var idP = tr.getAttribute('data-id') || tr.getAttribute('data-product-id'); var qtyEl = qs('.qty-input', tr) || qs('input.qty', tr); if (!idP || !qtyEl) return; var puEl = qs('.price-input', tr) || qs('input.unit_price_ht', tr); var fixedEl = qs('.fixed-price-input', tr); var idAttr = tr.getAttribute('data-attr') || tr.getAttribute('data-id-product-attribute') || 0; var q = parseInt(qtyEl.value, 10) || 0; var pu = puEl ? (parseFloat(String(puEl.value).replace(',', '.')) || 0) : 0; var fixed = fixedEl ? (parseFloat(String(fixedEl.value).replace(',', '.')) || 0) : 0; /* ── Lecture du taux de TVA ── */ var taxRateRaw = tr.getAttribute('data-tax-rate'); var taxRate = 0; if (taxRateRaw !== null && taxRateRaw !== undefined) { taxRate = parseFloat(String(taxRateRaw).replace(',', '.')); if (!isFinite(taxRate)) taxRate = 0; } /* ── Lecture du flag marquage ── */ var isMarkingRaw = tr.getAttribute('data-is-marking'); var isMarkingProduct = 0; if (isMarkingRaw !== null && isMarkingRaw !== undefined) { isMarkingProduct = parseInt(isMarkingRaw, 10) === 1 ? 1 : 0; } if (q > 0) { products.push({ id_product: parseInt(idP, 10), id_product_attribute: parseInt(idAttr, 10) || 0, quantity: q, unit_price_ht: pu, fixed_unit_price_ht: fixed, tax_rate: taxRate, is_marking_product: isMarkingProduct, }); } }); return products.length > 0 ? JSON.stringify(products) : null; } /* ── UI helpers ── */ function setSpan(id, val) { var el = document.getElementById(id); if (!el) return; var n = parseFloat(val); if (!isFinite(n)) n = 0; el.innerText = n.toFixed(2).replace('.', ',') + '\u00a0€'; } function showRow(rowId, condition) { var row = document.getElementById(rowId); if (row) row.style.display = condition ? '' : 'none'; } /* ── Bloc Remises ── */ function updateCartRules(cartRules) { var panel = document.getElementById('devis-totals-panel'); if (!panel) return; var body = qs('.panel-body', panel); if (!body) return; qsa('.devis-tier-dynamic', body).forEach(function (e) { e.remove(); }); var tierBlock = qs('#devis_tot_cart_rules_box', body); if (!cartRules || !cartRules.length) { if (tierBlock) tierBlock.style.display = 'none'; return; } if (!tierBlock) { tierBlock = document.createElement('div'); tierBlock.id = 'devis_tot_cart_rules_box'; tierBlock.style.cssText = 'margin-top:12px;padding:8px 12px;background:#fff8e1;border-left:3px solid #f9a825;border-radius:3px;'; body.appendChild(tierBlock); } tierBlock.style.display = ''; tierBlock.innerHTML = ' Remise(s) appliquée(s) :'; cartRules.forEach(function (rule) { var div = document.createElement('div'); div.className = 'devis-tier-dynamic devis_tot_rule_line'; div.style.cssText = 'margin-top:4px;color:#8a6d3b;font-size:12px;'; var name = rule.name || ''; if (rule.reduction_percent > 0) { div.innerHTML = ' ' + parseFloat(rule.reduction_percent).toFixed(1) + '% — ' + name; } else if (rule.reduction_amount > 0) { div.innerHTML = ' ' + parseFloat(rule.reduction_amount).toFixed(2).replace('.', ',') + ' € — ' + name; } else { div.innerHTML = ' ' + name; } tierBlock.appendChild(div); }); } /* ───────────────────────────────────────────── Bloc vérification quantités marquage Source unique : data-is-marking sur chaque tr ───────────────────────────────────────────── */ function refreshQuantityControlTotals() { var totalProducts = 0; var totalMarking = 0; var totalNonMarking = 0; var tbody = document.getElementById('products-tbody'); if (!tbody) return; var rows = tbody.querySelectorAll('tr'); for (var i = 0; i < rows.length; i++) { var tr = rows[i]; // Lecture quantité – valeur invalide => 0 var qtyInput = tr.querySelector('.qty-input'); var qty = 0; if (qtyInput) { var rawQty = parseInt(qtyInput.value, 10); qty = (isFinite(rawQty) && rawQty > 0) ? rawQty : 0; } // Lecture du flag marquage uniquement via data-is-marking var isMarkingAttr = tr.getAttribute('data-is-marking'); var isMarking = (isMarkingAttr !== null && parseInt(isMarkingAttr, 10) === 1) ? 1 : 0; totalProducts += qty; if (isMarking === 1) { totalMarking += qty; } else { totalNonMarking += qty; } } // Mise à jour DOM var elTP = document.getElementById('js-total-products-qty'); var elTM = document.getElementById('js-total-marking-qty'); var elTNM = document.getElementById('js-total-non-marking-qty'); if (elTP) elTP.textContent = totalProducts; if (elTM) elTM.textContent = totalMarking; if (elTNM) elTNM.textContent = totalNonMarking; } /* ───────────────────────────────────────────── Recalcul des totaux financiers ───────────────────────────────────────────── */ var _recalcTimer = null; function recalcTotalsThrottled() { if (_recalcTimer) clearTimeout(_recalcTimer); _recalcTimer = setTimeout(function () { _recalcTimer = null; recalcTotals(); }, 200); } function recalcTotals() { var url = resolveUrl(); if (!url) return; var live = getLiveProductsJson(); var fd = new FormData(); fd.append('ajax', '1'); fd.append('action', 'RecalcTotals'); fd.append('id_customer', (qs('input[name="id_customer"]') || { value: '0' }).value || '0'); fd.append('id_address_invoice', (qs('input[name="id_address_invoice"]') || { value: '0' }).value || '0'); fd.append('id_address_delivery', (qs('input[name="id_address_delivery"]') || { value: '0' }).value || '0'); fd.append('products_json', live || JSON.stringify([])); fetch(url, { method: 'POST', body: fd }) .then(function (r) { return r.json(); }) .then(function (data) { if (!data || !data.ok || !data.totals) return; var t = data.totals; setSpan('devis_tot_subtotal_products_ht', t.subtotal_products_ht); setSpan('devis_tot_discounts_ht', t.discounts_ht); setSpan('devis_tot_total_products_ht', t.total_products_ht); setSpan('devis_tot_shipping_ht', t.shipping_ht); setSpan('devis_tot_preparation_ht', t.preparation_ht); showRow('devis_tot_preparation_row', (parseFloat(t.preparation_ht) || 0) > 0.01); setSpan('devis_tot_total_ht', t.total_ht); setSpan('devis_tot_tax_amount', t.tax_amount); setSpan('devis_tot_total_ttc', t.total_ttc); showRow('devis_tot_discounts_row', (parseFloat(t.discounts_ht) || 0) > 0.01); showRow('devis_tot_remise_row', (parseFloat(t.discounts_ht) || 0) > 0.01); showRow('devis_tot_shipping_row', (parseFloat(t.shipping_ht) || 0) > 0.01); updateCartRules(data.cart_rules || []); refreshQuantityControlTotals(); }) .catch(function () {}); } /* ── Initialisation ── */ document.addEventListener('DOMContentLoaded', function () { bindCustomerSearch(); bindCreateCustomer(); document.addEventListener('input', function (e) { if (!e || !e.target || !e.target.classList) return; if ( e.target.classList.contains('qty-input') || e.target.classList.contains('price-input') || e.target.classList.contains('fixed-price-input') ) { refreshQuantityControlTotals(); recalcTotalsThrottled(); } }); if (window.DEVIS_PREFILL && parseInt(window.DEVIS_PREFILL.id_customer, 10) > 0) { setCustomerFields( window.DEVIS_PREFILL.id_customer, window.DEVIS_PREFILL.id_address_invoice, window.DEVIS_PREFILL.id_address_delivery ); updateSelectedCustomerLabel(window.DEVIS_PREFILL); } recalcTotals(); refreshQuantityControlTotals(); var form = qs('#devis_form') || qs('form[name="devis_form"]'); if (form) { form.addEventListener('submit', function () { var hidden = qs('#products_json'); if (!hidden) return; var live = getLiveProductsJson(); if (live !== null) { hidden.value = live; } }); } }); /* ── Exposition globale ── */ window.DevisRecalcTotals = recalcTotals; window.DevisRefreshQtyControl = refreshQuantityControlTotals; })(); SG ACCESSORIES - BAGS FE-4631 LFS | GRAND SAC FEUTRINE
GRAND SAC FEUTRINEFE-4631 LFSSG Accessories - BAGS

GRAND SAC FEUTRINE

GR 640.57
Code fabricant: FE-4631 LFS
Marque: SG Accessories - BAGS

FE-4631 LFS - Bags by JASSZ

Large Felt Shopper

DESCRIPTION

  • 430 g/m²
  • 100% polyester (feutre)
  • Poignées courtes (SH): ca. 43 cm
  • Fermeture Velcro® ton sur ton
  • Poche intérieure: 14 x 15 cm
  • Plié à la base: 34 x 12 cm
  • Dimensions: 46 x 31 x 12 cm
  • Convient pour l`impression numérique, la sublimation, la broderie, la découpe laser et la gravure laser.

CONDITIONNEMENT

  • colisage1colisage  40

Articles éco-responsable Oeko-Tex Standard 100 est un label de qualité, il garantit l'innocuité des textiles ou des produits utilisés lors du processus de production, pour les travailleurs, les consommateurs et l'Environnement. BSCI

Chine
42029298
visibility 3 personnes consultent ce produit en ce moment.
shopping_cart 18 personnes ont acheté ce produit récemment.
A partir de
4,40 € HT
Grâce à notre réseau auprès des fabricants et de nos partenaires, nous sommes fiers de pouvoir vous proposer les tarifs les plus bas et compétitifs du marché.
TARIFS DÉGRESSIFS info
  • Charcoal Melange
  • Grey Melange

Charcoal Melange

1 à 5
One Size 7,33 €
6 à 15
One Size 6,01 €
16 à 40
One Size 5,64 €
41 à 99
One Size 5,28 €
100 à 199
One Size 4,91 €
200 à 349
One Size 4,54 €
350 à 1500
One Size 4,40 €
1 à 5
One Size 7,33 €
6 à 15
One Size 6,01 €
16 à 40
One Size 5,64 €
41 à 99
One Size 5,28 €
100 à 199
One Size 4,91 €
200 à 349
One Size 4,54 €
350 à 1500
One Size 4,40 €
EXPÉDIÉ PAR ENTREPÔT FA
Livraison France, Corse et export Dom-Tom par transitaire. info local_shipping Départ des commandes le jours même si passée avant 11 heures
  • GRAND SAC FEUTRINEFE-4631 LFSSG Accessories - BAGS
  • Charcoal Melange
  • Grey Melange
Choisissez une couleur pour simplifier votre saisie et commander sans erreur.
  • Charcoal Melange
  • Grey Melange
  • Toutes les couleurs
Charcoal Melange Couleur sélectionnée : Charcoal Melange
Charcoal Melange
Charcoal Melange
Votre tarif help_outline Tarifs dégressifs - Couleur : Charcoal Melange
TARIFS DÉGRESSIFS info
  • Charcoal Melange
  • Grey Melange

Charcoal Melange

1 à 5
One Size 7,33 €
6 à 15
One Size 6,01 €
16 à 40
One Size 5,64 €
41 à 99
One Size 5,28 €
100 à 199
One Size 4,91 €
200 à 349
One Size 4,54 €
350 à 1500
One Size 4,40 €
1 à 5
One Size 7,33 €
6 à 15
One Size 6,01 €
16 à 40
One Size 5,64 €
41 à 99
One Size 5,28 €
100 à 199
One Size 4,91 €
200 à 349
One Size 4,54 €
350 à 1500
One Size 4,40 €
One Size 369 en stock
369 en stock
Grey Melange
Grey Melange
Votre tarif help_outline Tarifs dégressifs - Couleur : Grey Melange
TARIFS DÉGRESSIFS info
  • Charcoal Melange
  • Grey Melange

Charcoal Melange

1 à 5
One Size 7,33 €
6 à 15
One Size 6,01 €
16 à 40
One Size 5,64 €
41 à 99
One Size 5,28 €
100 à 199
One Size 4,91 €
200 à 349
One Size 4,54 €
350 à 1500
One Size 4,40 €
1 à 5
One Size 7,33 €
6 à 15
One Size 6,01 €
16 à 40
One Size 5,64 €
41 à 99
One Size 5,28 €
100 à 199
One Size 4,91 €
200 à 349
One Size 4,54 €
350 à 1500
One Size 4,40 €
One Size indisponible
non disponible
Commentaires (0)
Articles éco-responsable Oeko-Tex Standard 100 est un label de qualité, il garantit l'innocuité des textiles ou des produits utilisés lors du processus de production, pour les travailleurs, les consommateurs et l'Environnement. BSCI

Service Fermé. On répond demain.
keyboard_arrow_up