525 lines
18 KiB
JavaScript
525 lines
18 KiB
JavaScript
const currentUrl = window.location.href.split('#')[0]; // odcinamy część z hash
|
|
const patterns = [
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/news\/?$/,
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/in-progress\/?$/,
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/to-send\/?$/,
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/completed\/?$/,
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/status\/?$/,
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/(news|in-progress|to-send|completed|all)\/?$/,
|
|
/^https:\/\/projectpro\.apilo\.com\/order\/order\/status\/[^\/?#]+\/?$/
|
|
];
|
|
if (patterns.some(pattern => pattern.test(currentUrl))) {
|
|
console.log('test');
|
|
waitForTableAndSetImage();
|
|
attachTableReloadListener();
|
|
} else {
|
|
console.log('Nie pasuje do żadnego wzorca URL');
|
|
}
|
|
|
|
// --- 2) Czekanie na tabelę i start przetwarzania ---
|
|
function waitForTableAndSetImage() {
|
|
const start = Date.now();
|
|
const maxWait = 10000; // 10s
|
|
const intervalId = setInterval(() => {
|
|
const tbody = document.querySelector('#DataTables_Table_0 tbody');
|
|
if (tbody && tbody.querySelector('tr')) {
|
|
clearInterval(intervalId);
|
|
setImageToProduct();
|
|
} else if (Date.now() - start > maxWait) {
|
|
clearInterval(intervalId);
|
|
}
|
|
}, 120);
|
|
}
|
|
|
|
// --- 3) Obserwator zmian w tabeli (przeładowanie/paginacja) ---
|
|
function attachTableReloadListener() {
|
|
const tbody = document.querySelector('#DataTables_Table_0 tbody');
|
|
if (!tbody) return;
|
|
const observer = new MutationObserver(mutations => {
|
|
for (const m of mutations) {
|
|
if (m.type === 'childList') {
|
|
setImageToProduct();
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
observer.observe(tbody, { childList: true, subtree: false });
|
|
}
|
|
|
|
// --- 4) Główny worker: wstawianie miniatur wg SKU ---
|
|
const imgCache = new Map(); // SKU -> imgURL
|
|
const previewState = {
|
|
largeImg: null,
|
|
sourceImg: null,
|
|
onMove: null
|
|
};
|
|
let previewGuardsAttached = false;
|
|
|
|
function hideLargePreview() {
|
|
if (previewState.onMove) {
|
|
document.removeEventListener('mousemove', previewState.onMove);
|
|
}
|
|
if (previewState.largeImg) {
|
|
previewState.largeImg.remove();
|
|
}
|
|
previewState.largeImg = null;
|
|
previewState.sourceImg = null;
|
|
previewState.onMove = null;
|
|
}
|
|
|
|
function ensurePreviewGuardListeners() {
|
|
if (previewGuardsAttached) return;
|
|
previewGuardsAttached = true;
|
|
|
|
window.addEventListener('blur', hideLargePreview);
|
|
document.addEventListener('visibilitychange', () => {
|
|
if (document.hidden) hideLargePreview();
|
|
});
|
|
document.addEventListener('scroll', hideLargePreview, true);
|
|
}
|
|
|
|
function setImageToProduct() {
|
|
hideLargePreview();
|
|
|
|
const tbody = document.querySelector('#DataTables_Table_0 tbody');
|
|
if (!tbody) return;
|
|
|
|
const rows = Array.from(tbody.querySelectorAll('tr'));
|
|
rows.forEach(tr => {
|
|
const cells = tr.querySelectorAll('td');
|
|
if (cells.length < 4) return;
|
|
|
|
// Kolumna 2 zawiera info z domeną (wklejone w tym samym TD co numer zamówienia itp.)
|
|
const domain = detectDomainFromCell(cells[1]);
|
|
if (!domain) return;
|
|
|
|
// Kolumna 4: "Dane produktu"
|
|
const productsCell = cells[3];
|
|
// ============ POPRAWIONY FRAGMENT ============
|
|
|
|
// Każdy produkt: <div data-item="all-products"><div data-item="product">...</div></div>
|
|
const productBlocks = productsCell.querySelectorAll('[data-item="all-products"] [data-item="product"]');
|
|
|
|
productBlocks.forEach(block => {
|
|
// nie rób drugi raz
|
|
if (block.dataset.imgInserted === '1') return;
|
|
|
|
// Struktura: [data-item="product"] > .d-flex.mb-2 > [imgHolder DIV] + [dataHolder DIV]
|
|
const flex =
|
|
block.querySelector(':scope > .d-flex.mb-2') ||
|
|
block.querySelector('.d-flex.mb-2') ||
|
|
block.firstElementChild; // awaryjnie, gdyby klasy się zmieniły
|
|
|
|
if (!flex) return;
|
|
|
|
const imgHolder = flex.children?.[0]; // <div class="d-flex ... mr-3"><i .../></div>
|
|
const dataHolder = flex.children?.[1]; // <div> z nazwą, SKU, EAN, ceną
|
|
if (!imgHolder || !dataHolder) return;
|
|
|
|
// Jeśli już jest <img> w imgHolder, pomijamy
|
|
if (imgHolder.querySelector('img')) {
|
|
block.dataset.imgInserted = '1';
|
|
return;
|
|
}
|
|
|
|
// Znajdź konkretnie DIV z SKU (bez mieszania z innymi liniami)
|
|
const skuDiv = Array.from(dataHolder.querySelectorAll('div'))
|
|
.find(d => /SKU\s*:/i.test(d.textContent || ''));
|
|
|
|
const skuMatch = (skuDiv?.textContent || '').match(/SKU\s*:\s*([A-Za-z0-9_-]+)/i);
|
|
const sku = skuMatch?.[1]?.toUpperCase();
|
|
if (!sku) return;
|
|
|
|
const placeImage = (imgUrl) => {
|
|
if (!imgUrl) return;
|
|
// czyścimy ikonę <i> i wstawiamy miniaturę
|
|
imgHolder.innerHTML = '';
|
|
const imgEl = makeImg(imgUrl);
|
|
imgHolder.appendChild(imgEl);
|
|
setupPreview(imgEl, imgUrl);
|
|
block.dataset.imgInserted = '1';
|
|
};
|
|
|
|
if (imgCache.has(sku)) {
|
|
placeImage(imgCache.get(sku));
|
|
} else {
|
|
getProductData(sku, domain)
|
|
.then(url => {
|
|
if (url) imgCache.set(sku, url);
|
|
placeImage(url);
|
|
})
|
|
.catch(() => { });
|
|
}
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
function detectDomainFromCell(td) {
|
|
const text = (td.textContent || '').toLowerCase();
|
|
if (text.includes('marianek.pl')) return 'marianek.pl';
|
|
if (text.includes('pomysloweprezenty.pl')) return 'pomysloweprezenty.pl';
|
|
return null;
|
|
}
|
|
|
|
function makeImg(src) {
|
|
const img = document.createElement('img');
|
|
img.src = src;
|
|
img.alt = 'product';
|
|
img.className = 'img-fluid center-block';
|
|
img.style.maxWidth = '48px';
|
|
img.style.maxHeight = '48px';
|
|
img.style.objectFit = 'contain';
|
|
img.style.cursor = 'zoom-in';
|
|
return img;
|
|
}
|
|
|
|
// --- 5) Podgląd dużego obrazka ---
|
|
function setupPreview(imgElement, src) {
|
|
ensurePreviewGuardListeners();
|
|
|
|
const onMove = (ev) => {
|
|
if (!previewState.largeImg) return;
|
|
if (!previewState.sourceImg || !previewState.sourceImg.isConnected || !previewState.sourceImg.matches(':hover')) {
|
|
hideLargePreview();
|
|
return;
|
|
}
|
|
const pad = 10;
|
|
previewState.largeImg.style.top = (ev.pageY - previewState.largeImg.height / 2) + 'px';
|
|
previewState.largeImg.style.left = (ev.pageX + pad) + 'px';
|
|
};
|
|
|
|
const onOver = (ev) => {
|
|
hideLargePreview();
|
|
|
|
const largeImg = document.createElement('img');
|
|
largeImg.id = 'largeImagePreview';
|
|
largeImg.src = src;
|
|
largeImg.style.position = 'absolute';
|
|
largeImg.style.maxWidth = '400px';
|
|
largeImg.style.maxHeight = '400px';
|
|
largeImg.style.border = '1px solid #ccc';
|
|
largeImg.style.background = '#fff';
|
|
largeImg.style.zIndex = '10000';
|
|
largeImg.style.pointerEvents = 'none';
|
|
document.body.appendChild(largeImg);
|
|
|
|
previewState.largeImg = largeImg;
|
|
previewState.sourceImg = imgElement;
|
|
previewState.onMove = onMove;
|
|
|
|
onMove(ev);
|
|
document.addEventListener('mousemove', onMove);
|
|
};
|
|
|
|
const onOut = () => hideLargePreview();
|
|
|
|
imgElement.addEventListener('mouseenter', onOver);
|
|
imgElement.addEventListener('mouseout', onOut);
|
|
imgElement.addEventListener('mouseleave', onOut);
|
|
}
|
|
|
|
// --- 6) API: pobranie URL obrazka po SKU i domenie ---
|
|
async function getProductData(sku, domain) {
|
|
let url = null;
|
|
if (domain === 'marianek.pl') {
|
|
url = `https://marianek.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`;
|
|
} else if (domain === 'pomysloweprezenty.pl') {
|
|
url = `https://pomysloweprezenty.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`;
|
|
} else {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
const resp = await fetch(url, { credentials: 'omit' });
|
|
if (!resp.ok) {
|
|
throw new Error(`HTTP error! status: ${resp.status}`);
|
|
}
|
|
const data = await resp.json();
|
|
// zakładam, że API zwraca { img: "https://..." }
|
|
return data?.img || null;
|
|
} catch (err) {
|
|
console.error('Error fetching product data:', url, err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
const currentUrl2 = window.location.href;
|
|
const pattern = /^https:\/\/projectpro\.apilo\.com\/warehouse\/shipment\/new-for-order\/.+/;
|
|
|
|
if (pattern.test(currentUrl2)) {
|
|
const portletBody = document.querySelector('.kt-portlet__body');
|
|
if (portletBody) {
|
|
const buttonContainer = document.createElement('div');
|
|
buttonContainer.className = 'custom-button-container';
|
|
buttonContainer.style.display = 'flex';
|
|
buttonContainer.style.gap = '10px';
|
|
buttonContainer.style.marginBottom = '15px';
|
|
portletBody.parentNode.insertBefore(buttonContainer, portletBody);
|
|
|
|
const buttonP2D = createButton('Inpost P2D', '#007bff', 'P2D.inpost', 'RZE14N||RZE14N');
|
|
const buttonD2D = createButton('Inpost D2D', '#ff7800', 'D2D.inpostkurier');
|
|
const buttonD2P = createButton('Inpost D2P', '#28a745', 'D2P.inpost');
|
|
const buttonP2P = createButton('Inpost P2P', '#ffc107', 'P2P.inpost', 'RZE14N||RZE14N');
|
|
const buttonD2Dapaczka = createButton('D2D Apaczka', '#ff7800', 'D2D.apaczka');
|
|
const buttonD2PApaczka = createButton('D2P Apaczka', '#28a745', 'D2P.apaczka');
|
|
const buttonP2Papaczka = createButton('P2P Apaczka', '#ffc107', 'P2P.apaczka');
|
|
const buttonOrlen = createButton('Orlen', 'rgb(255, 7, 193)', 'P2P.orlen');
|
|
|
|
// buttonContainer.appendChild(buttonP2D);
|
|
buttonContainer.appendChild(buttonD2Dapaczka);
|
|
buttonContainer.appendChild(buttonD2PApaczka);
|
|
buttonContainer.appendChild(buttonP2Papaczka);
|
|
buttonContainer.appendChild(buttonOrlen);
|
|
// buttonContainer.appendChild(buttonD2D);
|
|
// buttonContainer.appendChild(buttonD2P);
|
|
// buttonContainer.appendChild(buttonP2P);
|
|
}
|
|
}
|
|
|
|
function createButton(text, backgroundColor, method, dropoffPoint = null) {
|
|
const button = document.createElement('button');
|
|
button.textContent = text;
|
|
button.style.background = backgroundColor;
|
|
button.style.display = 'inline-flex';
|
|
button.style.width = '200px';
|
|
button.style.height = '40px';
|
|
button.style.alignItems = 'center';
|
|
button.style.justifyContent = 'center';
|
|
button.style.color = '#FFF';
|
|
button.style.border = 'none';
|
|
button.style.cursor = 'pointer';
|
|
|
|
button.addEventListener('click', () => handleShipment(method, dropoffPoint));
|
|
|
|
return button;
|
|
}
|
|
|
|
async function handleShipment(method, dropoffPoint = null) {
|
|
try {
|
|
await selectPackageType(method);
|
|
await setShipmentMethod(method);
|
|
if (dropoffPoint) {
|
|
await setDropoffPoint(dropoffPoint);
|
|
}
|
|
await setContent(method);
|
|
await setParcelWeight('1');
|
|
await submitShipment();
|
|
} catch (error) {
|
|
console.error('Wystąpił błąd: ', error);
|
|
}
|
|
}
|
|
|
|
function retryUntilSuccess(fn, interval = 1000, retries = 10) {
|
|
return new Promise((resolve, reject) => {
|
|
const attempt = async () => {
|
|
try {
|
|
const result = await fn();
|
|
resolve(result);
|
|
} catch (err) {
|
|
if (retries === 0) {
|
|
reject(err);
|
|
} else {
|
|
setTimeout(() => {
|
|
retries--;
|
|
attempt();
|
|
}, interval);
|
|
}
|
|
}
|
|
};
|
|
attempt();
|
|
});
|
|
}
|
|
|
|
function setContent(method) {
|
|
if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') {
|
|
return retryUntilSuccess(() => {
|
|
return new Promise((resolve, reject) => {
|
|
const selectElement = document.getElementById('warehousebundle_shipment_preferences_content');
|
|
selectElement.value = 'prezent';
|
|
const event = document.createEvent('HTMLEvents');
|
|
event.initEvent('change', true, false);
|
|
selectElement.dispatchEvent(event);
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function selectPackageType(method) {
|
|
return retryUntilSuccess(() => {
|
|
return new Promise((resolve, reject) => {
|
|
|
|
if (method == 'P2P.orlen') {
|
|
|
|
//warehousebundle_shipment_carrierAccount
|
|
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
|
selectElement.value = 17;
|
|
const event = document.createEvent('HTMLEvents');
|
|
event.initEvent('change', true, false);
|
|
selectElement.dispatchEvent(event);
|
|
|
|
// settimeout
|
|
setTimeout(() => {
|
|
const selectElement2 = document.getElementById('warehousebundle_shipment_method');
|
|
selectElement2.value = 50;
|
|
const event2 = document.createEvent('HTMLEvents');
|
|
event2.initEvent('change', true, false);
|
|
selectElement2.dispatchEvent(event2);
|
|
|
|
// settimeout
|
|
setTimeout(() => {
|
|
const selectElement3 = document.getElementById('warehousebundle_shipment_preferences_packageType');
|
|
selectElement3.value = 'PACZKA';
|
|
const event3 = document.createEvent('HTMLEvents');
|
|
event3.initEvent('change', true, false);
|
|
selectElement3.dispatchEvent(event3);
|
|
resolve();
|
|
|
|
}, 1000);
|
|
}, 1000);
|
|
|
|
} else if (method == 'D2P.apaczka' || method == 'P2P.apaczka') {
|
|
|
|
//warehousebundle_shipment_carrierAccount
|
|
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
|
selectElement.value = 17;
|
|
const event = document.createEvent('HTMLEvents');
|
|
event.initEvent('change', true, false);
|
|
selectElement.dispatchEvent(event);
|
|
|
|
// settimeout
|
|
setTimeout(() => {
|
|
const selectElement2 = document.getElementById('warehousebundle_shipment_method');
|
|
selectElement2.value = 41;
|
|
const event2 = document.createEvent('HTMLEvents');
|
|
event2.initEvent('change', true, false);
|
|
selectElement2.dispatchEvent(event2);
|
|
|
|
// settimeout
|
|
setTimeout(() => {
|
|
const selectElement3 = document.getElementById('warehousebundle_shipment_preferences_packageType');
|
|
selectElement3.value = 'PACZKA';
|
|
const event3 = document.createEvent('HTMLEvents');
|
|
event3.initEvent('change', true, false);
|
|
selectElement3.dispatchEvent(event3);
|
|
resolve();
|
|
|
|
}, 1000);
|
|
}, 1000);
|
|
|
|
|
|
} else if (method == 'D2D.apaczka') {
|
|
|
|
const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount');
|
|
selectElement.value = 17;
|
|
const event = document.createEvent('HTMLEvents');
|
|
event.initEvent('change', true, false);
|
|
selectElement.dispatchEvent(event);
|
|
|
|
// settimeout
|
|
setTimeout(() => {
|
|
const selectElement2 = document.getElementById('warehousebundle_shipment_method');
|
|
selectElement2.value = 42;
|
|
const event2 = document.createEvent('HTMLEvents');
|
|
event2.initEvent('change', true, false);
|
|
selectElement2.dispatchEvent(event2);
|
|
|
|
// settimeout
|
|
setTimeout(() => {
|
|
const selectElement3 = document.getElementById('warehousebundle_shipment_preferences_packageType');
|
|
selectElement3.value = 'PACZKA';
|
|
const event3 = document.createEvent('HTMLEvents');
|
|
event3.initEvent('change', true, false);
|
|
selectElement3.dispatchEvent(event3);
|
|
resolve();
|
|
|
|
}, 1000);
|
|
}, 1000);
|
|
|
|
} else {
|
|
const selectElement = document.getElementById('warehousebundle_shipment_packageType');
|
|
if (selectElement) {
|
|
selectElement.value = 'package';
|
|
const event = document.createEvent('HTMLEvents');
|
|
event.initEvent('change', true, false);
|
|
selectElement.dispatchEvent(event);
|
|
resolve();
|
|
} else {
|
|
reject('Nie znaleziono elementu packageType');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function setShipmentMethod(method) {
|
|
if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') {
|
|
return new Promise((resolve, reject) => {
|
|
resolve();
|
|
});
|
|
}
|
|
return retryUntilSuccess(() => {
|
|
return new Promise((resolve, reject) => {
|
|
const methodElement = document.getElementById('warehousebundle_shipment_method');
|
|
if (methodElement) {
|
|
methodElement.value = method;
|
|
const methodEvent = document.createEvent('HTMLEvents');
|
|
methodEvent.initEvent('change', true, false);
|
|
methodElement.dispatchEvent(methodEvent);
|
|
resolve();
|
|
} else {
|
|
reject('Nie znaleziono elementu shipment_method');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function setDropoffPoint(dropoffPoint) {
|
|
return retryUntilSuccess(() => {
|
|
return new Promise((resolve, reject) => {
|
|
const dropoffPointElement = document.getElementById('warehousebundle_shipment_preferences_dropoffPoint');
|
|
if (dropoffPointElement) {
|
|
dropoffPointElement.value = dropoffPoint;
|
|
const dropoffPointEvent = document.createEvent('HTMLEvents');
|
|
dropoffPointEvent.initEvent('change', true, false);
|
|
dropoffPointElement.dispatchEvent(dropoffPointEvent);
|
|
resolve();
|
|
} else {
|
|
reject('Nie znaleziono elementu dropoffPoint');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function setParcelWeight(weight) {
|
|
return retryUntilSuccess(() => {
|
|
return new Promise((resolve, reject) => {
|
|
const weightElement = document.getElementById('warehousebundle_shipment_shipmentParcels_0_weight');
|
|
if (weightElement) {
|
|
weightElement.value = weight;
|
|
const weightEvent = document.createEvent('HTMLEvents');
|
|
weightEvent.initEvent('change', true, false);
|
|
weightElement.dispatchEvent(weightEvent);
|
|
resolve();
|
|
} else {
|
|
reject('Nie znaleziono elementu shipmentParcels_0_weight');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function submitShipment() {
|
|
return retryUntilSuccess(() => {
|
|
return new Promise((resolve, reject) => {
|
|
const submitButton = document.getElementById('warehousebundle_shipment_buttons_submit');
|
|
if (submitButton) {
|
|
submitButton.click();
|
|
resolve();
|
|
} else {
|
|
reject('Nie znaleziono przycisku submit');
|
|
}
|
|
});
|
|
});
|
|
}
|