Für Stammkunden

Schnellbestellung per Artikelnummer

Artikelnummer und Menge eintragen, prüfen lassen und alles auf einmal in den Warenkorb legen. Die Artikelnummer steht auf jeder Artikelseite, zum Beispiel 0080-3120.

Artikelnummer Menge Artikel Entfernen

Noch keine Positionen geprüft.

(function () { var START_ROWS = 5; var cache = {}; var timers = new WeakMap(); function root() { return document.getElementById('cy-qo'); } function rowsEl() { var r = root(); return r ? r.querySelector('[data-cy-qo-rows]') : null; } function norm(v) { return String(v || '').trim().toLowerCase().replace(/\s+/g, ''); } function el(tag, cls, text) { var e = document.createElement(tag); if (cls) e.className = cls; if (text != null) e.textContent = text; return e; } function addRow(number, qty) { var wrap = rowsEl(); if (!wrap) return null; var idx = wrap.children.length + 1; var row = el('div', 'cy-qo__row'); row.setAttribute('role', 'row'); var c1 = el('span', 'cy-qo__cell'); c1.setAttribute('role', 'cell'); var num = el('input', 'form-control cy-qo__num'); num.type = 'text'; num.autocomplete = 'off'; num.spellcheck = false; num.setAttribute('aria-label', 'Artikelnummer, Zeile ' + idx); num.placeholder = 'z. B. 0080-3120'; num.setAttribute('data-cy-qo-num', ''); if (number) num.value = number; c1.appendChild(num); var c2 = el('span', 'cy-qo__cell'); c2.setAttribute('role', 'cell'); var q = el('input', 'form-control cy-qo__qty'); q.type = 'number'; q.min = '1'; q.step = '1'; q.inputMode = 'numeric'; q.value = qty || 1; q.setAttribute('aria-label', 'Menge, Zeile ' + idx); q.setAttribute('data-cy-qo-qty', ''); c2.appendChild(q); var c3 = el('span', 'cy-qo__cell cy-qo__info'); c3.setAttribute('role', 'cell'); c3.setAttribute('data-cy-qo-info', ''); c3.appendChild(el('span', 'cy-qo__muted', '—')); var c4 = el('span', 'cy-qo__cell'); c4.setAttribute('role', 'cell'); var del = el('button', 'cy-qo__del'); del.type = 'button'; del.setAttribute('aria-label', 'Zeile ' + idx + ' entfernen'); del.setAttribute('data-cy-qo-del', ''); del.innerHTML = '×'; c4.appendChild(del); row.appendChild(c1); row.appendChild(c2); row.appendChild(c3); row.appendChild(c4); wrap.appendChild(row); if (number) check(row); return row; } function lookup(number) { var key = norm(number); if (cache[key]) return cache[key]; var url = '/rest/io/item/search?query=' + encodeURIComponent(number.trim()) + '&itemsPerPage=20'; cache[key] = fetch(url, { headers: { 'Accept': 'application/json' }, credentials: 'same-origin' }) .then(function (r) { if (!r.ok) throw new Error('http'); return r.json(); }) .then(function (json) { var docs = (((json || {}).data || {}).itemList || {}).documents || []; var hit = null; for (var i = 0; i < docs.length; i++) { var d = docs[i].data || {}; var v = d.variation || {}; if (norm(v.name) === key) { hit = d; break; } } if (!hit && /^\d+$/.test(key)) { for (var j = 0; j < docs.length; j++) { var d2 = docs[j].data || {}; if (String((d2.variation || {}).id) === key || String((d2.item || {}).id) === key) { hit = d2; break; } } } if (!hit) return null; var v2 = hit.variation || {}; var price = (((hit.prices || {}).default || {}).price || {}).formatted || ''; var path = (hit.texts || {}).urlPath || ''; return { variationId: v2.id, itemId: (hit.item || {}).id, number: v2.name, name: (hit.texts || {}).name1 || '', price: price, url: path ? '/' + path.replace(/^\//, '') + '/a-' + (hit.item || {}).id : '', min: Math.max(1, parseInt(v2.minimumOrderQuantity, 10) || 1), interval: parseInt(v2.intervalOrderQuantity, 10) || 0, salable: !hit.filter || hit.filter.isSalable !== false, needsPage: !!hit.hasRequiredOrderProperty }; }) .catch(function () { delete cache[key]; return 'error'; }); return cache[key]; } function setInfo(row, state, data, note) { var info = row.querySelector('[data-cy-qo-info]'); info.textContent = ''; row.setAttribute('data-state', state); row._cy = data || null; if (state === 'empty') { info.appendChild(el('span', 'cy-qo__muted', '—')); return; } if (state === 'loading') { info.appendChild(el('span', 'cy-qo__muted', 'Wird geprüft …')); return; } if (state === 'error') { info.appendChild(el('span', 'cy-qo__msg cy-qo__msg--error', note || 'Prüfung nicht möglich. Bitte erneut versuchen.')); return; } if (state === 'missing') { info.appendChild(el('span', 'cy-qo__msg cy-qo__msg--error', 'Artikelnummer nicht gefunden.')); return; } var name = data.url ? el('a', 'cy-qo__name', data.name) : el('span', 'cy-qo__name', data.name); if (data.url) { name.href = data.url; name.target = '_blank'; name.rel = 'noopener'; } info.appendChild(name); var meta = el('span', 'cy-qo__meta'); if (data.price) meta.appendChild(el('span', 'cy-qo__price', data.price)); if (state === 'page') meta.appendChild(el('span', 'cy-qo__msg cy-qo__msg--warn', 'Bitte auf der Artikelseite bestellen')); else if (state === 'unsalable') meta.appendChild(el('span', 'cy-qo__msg cy-qo__msg--warn', 'Derzeit nicht bestellbar')); else meta.appendChild(el('span', 'cy-qo__msg cy-qo__msg--ok', 'Gefunden')); if (note) meta.appendChild(el('span', 'cy-qo__msg cy-qo__msg--note', note)); info.appendChild(meta); } function fixQty(row, data) { var q = row.querySelector('[data-cy-qo-qty]'); var n = parseInt(q.value, 10) || 0; var note = ''; if (n < data.min) { n = data.min; note = 'Mindestmenge ' + data.min; } if (data.interval > 1) { var rest = (n - data.min) % data.interval; if (rest !== 0) { n = n + (data.interval - rest); note = 'Bestellbar in Schritten von ' + data.interval; } } q.min = String(data.min); if (data.interval > 1) q.step = String(data.interval); q.value = n; return note; } function check(row) { var num = row.querySelector('[data-cy-qo-num]').value; if (!norm(num)) { setInfo(row, 'empty'); update(); return Promise.resolve(); } setInfo(row, 'loading'); update(); var asked = norm(num); return lookup(num).then(function (data) { if (norm(row.querySelector('[data-cy-qo-num]').value) !== asked) return; if (data === 'error') { setInfo(row, 'error'); } else if (!data) { setInfo(row, 'missing'); } else if (data.needsPage) { setInfo(row, 'page', data); } else if (!data.salable) { setInfo(row, 'unsalable', data); } else { setInfo(row, 'ok', data, fixQty(row, data)); } update(); }); } function update() { var r = root(); if (!r) return; var rows = r.querySelectorAll('.cy-qo__rows .cy-qo__row'); var ok = 0, open = 0, bad = 0; rows.forEach(function (row) { var s = row.getAttribute('data-state'); if (s === 'ok') ok++; else if (s === 'loading') open++; else if (s && s !== 'empty') bad++; }); var sum = r.querySelector('[data-cy-qo-summary]'); var btn = r.querySelector('[data-cy-qo-submit]'); if (!ok && !open && !bad) sum.textContent = 'Noch keine Positionen geprüft.'; else { var t = ok + (ok === 1 ? ' Position bereit' : ' Positionen bereit'); if (bad) t += ', ' + bad + ' mit Hinweis'; if (open) t += ', ' + open + ' in Prüfung'; sum.textContent = t + '.'; } btn.disabled = ok === 0 || open > 0; } function parseList(text) { return String(text || '').split(/\r?\n/).map(function (line) { var parts = line.trim().split(/[;\t,]+|\s+/).filter(Boolean); if (!parts.length) return null; var qty = 1; if (parts.length > 1 && /^\d+$/.test(parts[parts.length - 1])) qty = parseInt(parts.pop(), 10); return { number: parts.join(' '), qty: qty }; }).filter(Boolean); } function importList() { var r = root(); var ta = r.querySelector('[data-cy-qo-paste]'); var list = parseList(ta.value); if (!list.length) return; var wrap = rowsEl(); var empties = Array.prototype.filter.call(wrap.children, function (row) { return !norm(row.querySelector('[data-cy-qo-num]').value); }); list.forEach(function (p) { var row = empties.shift(); if (row) { row.querySelector('[data-cy-qo-num]').value = p.number; row.querySelector('[data-cy-qo-qty]').value = p.qty; check(row); } else addRow(p.number, p.qty); }); ta.value = ''; } function addToBasket(variationId, quantity) { var store = window.vueApp && window.vueApp.$store; if (store && store._actions && store._actions.addBasketItem) { return store.dispatch('addBasketItem', { variationId: variationId, quantity: quantity, basketItemOrderParams: [] }); } return fetch('/rest/io/basket/items/', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' }, body: JSON.stringify({ variationId: variationId, quantity: quantity, basketItemOrderParams: [] }) }).then(function (r) { if (!r.ok) throw new Error('http'); return r.json(); }); } function submit() { var r = root(); var btn = r.querySelector('[data-cy-qo-submit]'); var res = r.querySelector('[data-cy-qo-result]'); var rows = Array.prototype.filter.call(r.querySelectorAll('.cy-qo__rows .cy-qo__row'), function (row) { return row.getAttribute('data-state') === 'ok'; }); if (!rows.length) return; btn.disabled = true; btn.textContent = 'Wird hinzugefügt …'; var done = 0, failed = []; rows.reduce(function (p, row) { return p.then(function () { var d = row._cy; var qty = parseInt(row.querySelector('[data-cy-qo-qty]').value, 10) || d.min; return addToBasket(d.variationId, qty).then(function () { done++; row.setAttribute('data-state', 'added'); setInfo(row, 'ok', d, 'Im Warenkorb'); row.setAttribute('data-state', 'added'); }, function () { failed.push(d.number); }); }); }, Promise.resolve()).then(function () { btn.textContent = 'Alle in den Warenkorb'; res.hidden = false; res.textContent = ''; res.className = 'cy-qo__result' + (failed.length ? ' cy-qo__result--warn' : ' cy-qo__result--ok'); var p = el('p', 'cy-qo__result-text', done + (done === 1 ? ' Position' : ' Positionen') + ' im Warenkorb.' + (failed.length ? ' Nicht hinzugefügt: ' + failed.join(', ') + '.' : '')); res.appendChild(p); var a = el('a', 'btn btn-primary', 'Zum Warenkorb'); a.href = '/basket'; res.appendChild(a); update(); }); } function init() { var wrap = rowsEl(); if (!wrap || wrap.getAttribute('data-ready')) return; wrap.setAttribute('data-ready', '1'); for (var i = 0; i < START_ROWS; i++) addRow(); } document.addEventListener('click', function (e) { var t = e.target; var r = root(); if (!r || !r.contains(t)) return; if (t.closest('[data-cy-qo-add]')) { var row = addRow(); if (row) row.querySelector('input').focus(); } else if (t.closest('[data-cy-qo-del]')) { var rw = t.closest('.cy-qo__row'); rw.parentNode.removeChild(rw); if (!rowsEl().children.length) addRow(); update(); } else if (t.closest('[data-cy-qo-reset]')) { rowsEl().textContent = ''; for (var i = 0; i < START_ROWS; i++) addRow(); r.querySelector('[data-cy-qo-result]').hidden = true; update(); } else if (t.closest('[data-cy-qo-import]')) { importList(); } else if (t.closest('[data-cy-qo-submit]')) { submit(); } }); document.addEventListener('input', function (e) { var t = e.target; if (!t.matches || !t.matches('#cy-qo [data-cy-qo-num]')) return; var row = t.closest('.cy-qo__row'); clearTimeout(timers.get(row)); timers.set(row, setTimeout(function () { check(row); }, 500)); }); document.addEventListener('change', function (e) { var t = e.target; if (!t.matches || !t.matches('#cy-qo [data-cy-qo-qty]')) return; var row = t.closest('.cy-qo__row'); if (row && row._cy && row.getAttribute('data-state') === 'ok') setInfo(row, 'ok', row._cy, fixQty(row, row._cy)); }); document.addEventListener('keydown', function (e) { var t = e.target; if (e.key !== 'Enter' || !t.matches || !t.matches('#cy-qo input')) return; e.preventDefault(); var row = t.closest('.cy-qo__row'); if (t.matches('[data-cy-qo-num]')) { row.querySelector('[data-cy-qo-qty]').focus(); return; } var next = row.nextElementSibling || addRow(); if (next) next.querySelector('[data-cy-qo-num]').focus(); }); if (document.readyState === 'complete') init(); else window.addEventListener('load', init); var tries = 0; var iv = setInterval(function () { init(); if (++tries > 20 || (rowsEl() && rowsEl().children.length)) clearInterval(iv); }, 500); })();