/** * np-ttn.js — Оформлення ТТН Нової Пошти для CarpetUA * Підключити: */ window.NovaPoshta = (() => { 'use strict'; // Мапа ФОПів із їхніми унікальними "Ref" відправника const FOP_MAP = { 'БІЛА': { SenderRef: '1501a6cd-f741-11ea-8513-b88303659df5', EDRPOU: '3250916726' }, 'ПРИЩЕНКО': { SenderRef: '14fa7192-f741-11ea-8513-b88303659df5', EDRPOU: '3142312442' }, 'ЗВАРИЧ': { SenderRef: '14f42298-f741-11ea-8513-b88303659df5', EDRPOU: '2818821181' }, }; // Місто відправника — Хмельницький const SENDER_CITY_REF = 'db5c88ac-391c-11dd-90d9-001a92567626'; // Ваше 1-ше відділення у Хмельницькому const SENDER_BRANCH_REF = '511fd008-e1c2-11e3-8c4a-0050568002cf'; let _order = null; // поточне замовлення function _getOrders() { try { if (typeof orders !== 'undefined' && Array.isArray(orders)) return orders; } catch(e){} return []; } function openModal(orderId) { const list = _getOrders(); const o = list.find(x => x.id === orderId); if (!o) { try { const cid = typeof currentOrderId !== 'undefined' ? currentOrderId : null; if (cid) { const o2 = list.find(x => x.id === cid); if (o2) { _open(o2); return; } } } catch(e){} alert('Замовлення не знайдено. Збережіть замовлення і спробуйте знову.'); return; } _open(o); } function _open(order) { if (!FOP_MAP[order.fop]) { alert('Оберіть ФОП перед оформленням ТТН'); return; } _order = order; _ensureModal(); _renderForm(order); document.getElementById('np-ttn-modal').classList.add('open'); } function closeModal() { const m = document.getElementById('np-ttn-modal'); if (m) m.classList.remove('open'); } function _renderForm(order) { const total = (order.products || []).reduce((s, p) => s + ((+p.qty) * (+p.price)), 0); const prepay = order.paymentType === 'partial' ? (parseFloat(order.prepay) || 0) : 0; const cod = order.paymentType === 'partial' ? Math.max(0, total - prepay) : 0; const canCOD = order.fop === 'БІЛА' && order.paymentType === 'partial' && cod > 0; const fop = FOP_MAP[order.fop]; const addInfo = (order.products || []) .filter(p => p.name) .map(p => `${p.name}${+p.qty > 1 ? ' x' + p.qty : ''}`) .join(', '); const recipientName = [order.lastName, order.firstName].filter(Boolean).join(' '); const today = new Date().toISOString().split('T')[0]; const fmtU = n => Math.round(n).toLocaleString('uk-UA') + ' ₴'; document.getElementById('np-ttn-modal-body').innerHTML = `
📤 Відправник
ФОП ${_e(order.fop)} ЄДРПОУ: ${fop.EDRPOU}
📥 Отримувач
🏪 Відділення отримувача
📦 Параметри посилки
${canCOD ? `
💵 Контроль оплати (COD) — ФОП БІЛА
Доплата на пошті
${fmtU(cod)}
Передплата: ${fmtU(prepay)}
Загалом: ${fmtU(total)}
` : ''}
`; } let _ct; function _cs(q) { clearTimeout(_ct); const drop = document.getElementById('npt-city-drop'); if (!drop) return; if (q.length < 2) { drop.style.display = 'none'; return; } _ct = setTimeout(async () => { try { const res = await _post('np_search_city', { query: q }); const items = res?.data?.[0]?.Addresses || []; drop.innerHTML = items.length ? items.slice(0,10).map(it => `
${_e(it.Present || it.MainDescription)}
`).join('') : '
Нічого не знайдено
'; drop.style.display = 'block'; } catch(e) { console.error('NP city search', e); } }, 350); } function _sc(name, ref) { _val('npt-city', name); _val('npt-city-ref', ref); _hide('npt-city-drop'); const b = document.getElementById('npt-branch'); if (b) { b.disabled = false; b.placeholder = 'Пошук відділення...'; b.value = ''; } _val('npt-branch-ref', ''); } let _bt; function _bs(q) { clearTimeout(_bt); const cityRef = document.getElementById('npt-city-ref')?.value; const drop = document.getElementById('npt-branch-drop'); if (!cityRef || !drop) return; _bt = setTimeout(async () => { try { const res = await _post('np_search_warehouse', { cityRef, query: q }); const items = res?.data || []; drop.innerHTML = items.length ? items.slice(0,20).map(it => `
${_e(it.Description)}
`).join('') : '
Нічого не знайдено
'; drop.style.display = 'block'; } catch(e) { console.error('NP branch search', e); } }, 350); } function _sb(name, ref) { _val('npt-branch', name); _val('npt-branch-ref', ref); _hide('npt-branch-drop'); } async function createTTN() { const order = _order; if (!order) return; const btn = document.getElementById('npt-btn'); if (btn) { btn.disabled = true; btn.textContent = '⏳ Створення...'; } try { const fop = FOP_MAP[order.fop]; const phone = document.getElementById('npt-phone')?.value.replace(/\D/g,'') || ''; const name = document.getElementById('npt-name')?.value.trim() || ''; const cref = document.getElementById('npt-city-ref')?.value.trim() || ''; const bref = document.getElementById('npt-branch-ref')?.value.trim() || ''; if (!phone || phone.length < 9) throw new Error('Введіть коректний телефон отримувача'); if (!name) throw new Error('Введіть ПІБ отримувача'); if (!cref) throw new Error('Оберіть місто'); if (!bref) throw new Error('Оберіть відділення'); const result = await _post('np_create_ttn', { fopKey: order.fop, orgRef: fop.SenderRef, // Передаємо ID ФОПа senderCityRef: SENDER_CITY_REF, senderBranchRef: SENDER_BRANCH_REF, cityRef: cref, branchRef: bref, recipientName: name, recipientPhone: '380' + phone.slice(-9), description: document.getElementById('npt-desc')?.value.trim() || 'Килим', cost: parseFloat(document.getElementById('npt-cost')?.value) || 0, weight: parseFloat(document.getElementById('npt-weight')?.value) || 1, seats: parseInt(document.getElementById('npt-seats')?.value) || 1, orderNum: document.getElementById('npt-onum')?.value.trim() || '', addInfo: document.getElementById('npt-info')?.value.trim() || '', sendDate: document.getElementById('npt-date')?.value || '', codValue: parseFloat(document.getElementById('npt-cod')?.value) || 0, }); if (result?.success && result?.data?.[0]) { const num = result.data[0].IntDocNumber || result.data[0].Ref || '—'; _result(`
✅ ТТН успішно створено!
${_e(num)}
Вартість: ${result.data[0].CostOnSite || '—'} ₴
`); try { const list = _getOrders(); const o = list.find(x => x.id === order.id); if (o) { o.npTTN = num; if (typeof saveOrderServer === 'function') saveOrderServer(); } } catch(e) {} if (btn) btn.textContent = '✅ Готово'; } else { throw new Error(result?.errors?.[0] || result?.error || JSON.stringify(result)); } } catch(e) { _result(`
❌ ${_e(e.message)}
`); if (btn) { btn.disabled = false; btn.textContent = '📋 Створити ТТН'; } } } function _val(id, v) { const el = document.getElementById(id); if (el) el.value = v; } function _hide(id) { const el = document.getElementById(id); if (el) el.style.display = 'none'; } function _result(html) { const el = document.getElementById('npt-result'); if (el) { el.innerHTML = html; el.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } } function _e(s) { return String(s ?? '').replace(/&/g,'&').replace(/"/g,'"').replace(//g,'>'); } function _eq(s) { return String(s ?? '').replace(/\\/g,'\\\\').replace(/'/g,"\\'"); } async function _post(action, data) { const r = await fetch(`api.php?action=${action}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }); if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); } function _ensureModal() { if (document.getElementById('np-ttn-modal')) return; const style = document.createElement('style'); style.textContent = ` ._npt-drop { position:absolute;top:100%;left:0;right:0;background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);max-height:200px;overflow-y:auto;z-index:99999;box-shadow:var(--shadow); } ._npt-item { padding:8px 12px;cursor:pointer;font-size:12px;border-bottom:1px solid var(--border); } ._npt-item:hover { background:var(--accent-glow);color:var(--accent); } `; document.head.appendChild(style); const el = document.createElement('div'); el.id = 'np-ttn-modal'; el.className = 'modal-overlay'; el.innerHTML = ` `; document.body.appendChild(el); el.addEventListener('click', e => { if (e.target === el) closeModal(); }); document.addEventListener('click', e => { if (!e.target.closest('#npt-city,#npt-city-drop')) _hide('npt-city-drop'); if (!e.target.closest('#npt-branch,#npt-branch-drop')) _hide('npt-branch-drop'); }, true); } return { openModal, closeModal, createTTN, _cs, _sc, _bs, _sb }; })();