feat(shipments): add ShipmentProviderInterface and ShipmentProviderRegistry
- Introduced ShipmentProviderInterface to define the contract for shipment providers. - Implemented ShipmentProviderRegistry to manage and retrieve shipment providers. - Added a new tool for probing Apaczka order_send payload variants, enhancing debugging capabilities.
This commit is contained in:
@@ -5,20 +5,31 @@ $receiver = is_array($receiverAddr ?? null) ? $receiverAddr : [];
|
||||
$prefs = is_array($preferences ?? null) ? $preferences : [];
|
||||
$comp = is_array($company ?? null) ? $company : [];
|
||||
$services = is_array($deliveryServices ?? null) ? $deliveryServices : [];
|
||||
$apaczkaSvcList = is_array($apaczkaServices ?? null) ? $apaczkaServices : [];
|
||||
$packages = is_array($existingPackages ?? null) ? $existingPackages : [];
|
||||
$servicesError = (string) ($deliveryServicesError ?? '');
|
||||
$flashSuccessMsg = (string) ($flashSuccess ?? '');
|
||||
$flashErrorMsg = (string) ($flashError ?? '');
|
||||
$deliveryMappingDiagnostic = trim((string) ($deliveryMappingDiagnostic ?? ''));
|
||||
|
||||
$mapping = is_array($deliveryMapping ?? null) ? $deliveryMapping : [];
|
||||
$mappedMethodId = trim((string) ($mapping['allegro_delivery_method_id'] ?? ''));
|
||||
$mappedCredentialsId = trim((string) ($mapping['allegro_credentials_id'] ?? ''));
|
||||
$mappedCarrierId = trim((string) ($mapping['allegro_carrier_id'] ?? ''));
|
||||
$mappedCarrier = trim((string) ($mapping['carrier'] ?? ''));
|
||||
$mappedServiceName = trim((string) ($mapping['allegro_service_name'] ?? ''));
|
||||
$deliveryMethodId = $mappedCarrier === 'allegro' && $mappedMethodId !== ''
|
||||
? $mappedMethodId
|
||||
: ($mappedCarrier !== 'inpost' ? trim((string) ($prefs['delivery_method_id'] ?? ($orderRow['external_carrier_account_id'] ?? ''))) : '');
|
||||
$mappedMethodId = trim((string) ($mapping['provider_service_id'] ?? ''));
|
||||
$mappedCredentialsId = trim((string) ($mapping['provider_account_id'] ?? ''));
|
||||
$mappedCarrierId = trim((string) ($mapping['provider_carrier_id'] ?? ''));
|
||||
$mappedProvider = trim((string) ($mapping['provider'] ?? ''));
|
||||
$mappedServiceName = trim((string) ($mapping['provider_service_name'] ?? ''));
|
||||
$mappedCarrier = $mappedProvider === 'apaczka' ? 'apaczka' : 'allegro';
|
||||
if ($mappedCarrier !== 'apaczka' && stripos($mappedCarrierId, 'inpost') !== false) {
|
||||
$mappedCarrier = 'inpost';
|
||||
}
|
||||
$deliveryMethodId = '';
|
||||
if ($mappedCarrier === 'apaczka' && $mappedMethodId !== '') {
|
||||
$deliveryMethodId = $mappedMethodId;
|
||||
} elseif (($mappedCarrier === 'allegro' || $mappedCarrier === 'inpost') && $mappedMethodId !== '') {
|
||||
$deliveryMethodId = $mappedMethodId;
|
||||
} elseif ($mappedCarrier !== 'inpost') {
|
||||
$deliveryMethodId = trim((string) ($prefs['delivery_method_id'] ?? ($orderRow['external_carrier_account_id'] ?? '')));
|
||||
}
|
||||
$deliveryMethodName = trim((string) ($orderRow['external_carrier_id'] ?? ''));
|
||||
$inpostSvcList = is_array($inpostServices ?? null) ? $inpostServices : [];
|
||||
$preselectedCarrier = $mappedCarrier !== '' ? $mappedCarrier : ($mappedMethodId !== '' ? 'allegro' : '');
|
||||
@@ -90,23 +101,32 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
<td><?= $e($pkgCarrier !== '' ? $pkgCarrier : '-') ?></td>
|
||||
<td>
|
||||
<?php if ($pkgLabelPath !== ''): ?>
|
||||
<?php if ($pkgStatus === 'error'): ?>
|
||||
-
|
||||
<?php else: ?>
|
||||
<form method="post" action="/orders/<?= $e((string) ($orderId ?? 0)) ?>/shipment/<?= $e((string) $pkgId) ?>/label" style="display:inline">
|
||||
<input type="hidden" name="_csrf_token" value="<?= $e($csrfToken ?? '') ?>">
|
||||
<button type="submit" class="btn btn--sm btn--secondary">Pobierz</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
<?php elseif ($pkgShipmentId !== '' && $pkgStatus === 'created'): ?>
|
||||
<form method="post" action="/orders/<?= $e((string) ($orderId ?? 0)) ?>/shipment/<?= $e((string) $pkgId) ?>/label" style="display:inline">
|
||||
<input type="hidden" name="_csrf_token" value="<?= $e($csrfToken ?? '') ?>">
|
||||
<button type="submit" class="btn btn--sm btn--primary">Generuj etykiete</button>
|
||||
</form>
|
||||
<span class="muted">Generowanie etykiety...</span>
|
||||
<?php else: ?>
|
||||
-
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-nowrap"><?= $e((string) ($pkg['created_at'] ?? '')) ?></td>
|
||||
<td>
|
||||
<?php if ($pkgStatus === 'pending'): ?>
|
||||
<button type="button" class="btn btn--sm btn--secondary" data-check-status="<?= $e((string) $pkgId) ?>" data-order-id="<?= $e((string) ($orderId ?? 0)) ?>">Sprawdz status</button>
|
||||
<?php
|
||||
$shouldCheckStatus = $pkgStatus === 'pending' || ($pkgStatus === 'created' && $pkgLabelPath === '');
|
||||
?>
|
||||
<?php if ($shouldCheckStatus): ?>
|
||||
<button type="button"
|
||||
class="btn btn--sm btn--secondary"
|
||||
data-check-status="<?= $e((string) $pkgId) ?>"
|
||||
data-order-id="<?= $e((string) ($orderId ?? 0)) ?>"
|
||||
data-package-status="<?= $e($pkgStatus) ?>"
|
||||
data-auto-check="1">Sprawdz status</button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -134,9 +154,13 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
<option value="">-- Wybierz --</option>
|
||||
<option value="allegro"<?= $preselectedCarrier === 'allegro' ? ' selected' : '' ?>>Allegro</option>
|
||||
<option value="inpost"<?= $preselectedCarrier === 'inpost' ? ' selected' : '' ?>>InPost</option>
|
||||
<option value="apaczka"<?= $preselectedCarrier === 'apaczka' ? ' selected' : '' ?>>Apaczka</option>
|
||||
</select>
|
||||
<?php if ($deliveryMethodName !== ''): ?>
|
||||
<div class="muted mt-4" style="font-size:12px">Metoda z zamowienia: <strong><?= $e($deliveryMethodName) ?></strong><?php if ($mappedServiceName !== ''): ?> → <?= $e($mappedCarrier === 'inpost' ? 'InPost' : 'Allegro') ?>: <?= $e($mappedServiceName) ?><?php endif; ?></div>
|
||||
<div class="muted mt-4" style="font-size:12px">Metoda z zamowienia: <strong><?= $e($deliveryMethodName) ?></strong><?php if ($mappedServiceName !== ''): ?> → <?= $e($mappedCarrier === 'inpost' ? 'InPost' : ($mappedCarrier === 'apaczka' ? 'Apaczka' : 'Allegro')) ?>: <?= $e($mappedServiceName) ?><?php endif; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($deliveryMappingDiagnostic !== ''): ?>
|
||||
<div class="flash flash--error mt-8"><?= $e($deliveryMappingDiagnostic) ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
@@ -199,11 +223,39 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div id="shipment-apaczka-panel" style="<?= $preselectedCarrier !== 'apaczka' ? 'display:none' : '' ?>">
|
||||
<?php if ($apaczkaSvcList === []): ?>
|
||||
<div class="muted">Brak uslug Apaczka (sprawdz konfiguracje App ID/App Secret).</div>
|
||||
<?php else: ?>
|
||||
<select class="form-control" id="shipment-apaczka-select">
|
||||
<option value="">-- Wybierz usluge Apaczka --</option>
|
||||
<?php foreach ($apaczkaSvcList as $aSvc): ?>
|
||||
<?php
|
||||
if (!is_array($aSvc)) {
|
||||
continue;
|
||||
}
|
||||
$aSvcId = trim((string) ($aSvc['service_id'] ?? $aSvc['id'] ?? ''));
|
||||
$aSvcName = trim((string) ($aSvc['name'] ?? ''));
|
||||
$aSvcCarrierCode = trim((string) ($aSvc['carrier_code'] ?? ''));
|
||||
$aSvcSelected = $mappedCarrier === 'apaczka' && $mappedMethodId === $aSvcId;
|
||||
?>
|
||||
<option
|
||||
value="<?= $e($aSvcId) ?>"
|
||||
data-carrier-id="<?= $e($aSvcCarrierCode) ?>"
|
||||
<?= $aSvcSelected ? 'selected' : '' ?>>
|
||||
<?= $e($aSvcName !== '' ? $aSvcName : ('ID ' . $aSvcId)) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div id="shipment-empty-panel" class="muted" style="<?= $preselectedCarrier !== '' ? 'display:none' : '' ?>">Wybierz przewoznika</div>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="credentials_id" id="shipment-credentials-id" value="">
|
||||
<input type="hidden" name="carrier_id" id="shipment-carrier-id" value="">
|
||||
<input type="hidden" name="provider_code" id="shipment-provider-code" value="<?= $e($preselectedCarrier === 'apaczka' ? 'apaczka' : 'allegro_wza') ?>">
|
||||
|
||||
<label class="form-field">
|
||||
<span class="field-label">Typ paczki</span>
|
||||
@@ -349,7 +401,6 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
// ── Generic searchable select enhancer ──
|
||||
function enhanceSelect(selectEl) {
|
||||
if (!selectEl || selectEl.dataset.enhanced) return;
|
||||
selectEl.dataset.enhanced = '1';
|
||||
@@ -458,17 +509,17 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
selectEl._syncTrigger = syncTrigger;
|
||||
}
|
||||
|
||||
// ── Enhance all native selects on the page ──
|
||||
var carrierSelect = document.getElementById('shipment-carrier-select');
|
||||
var inpostSelect = document.getElementById('shipment-inpost-select');
|
||||
var apaczkaSelect = document.getElementById('shipment-apaczka-select');
|
||||
|
||||
document.querySelectorAll('form select.form-control').forEach(function (sel) {
|
||||
enhanceSelect(sel);
|
||||
});
|
||||
|
||||
// ── Carrier / service panel logic ──
|
||||
var allegroPanel = document.getElementById('shipment-allegro-panel');
|
||||
var inpostPanel = document.getElementById('shipment-inpost-panel');
|
||||
var apaczkaPanel = document.getElementById('shipment-apaczka-panel');
|
||||
var emptyPanel = document.getElementById('shipment-empty-panel');
|
||||
|
||||
var wrapper = document.getElementById('shipment-service-wrapper');
|
||||
@@ -477,6 +528,7 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
var dropdown = document.getElementById('shipment-service-dropdown');
|
||||
var credentialsInput = document.getElementById('shipment-credentials-id');
|
||||
var carrierInput = document.getElementById('shipment-carrier-id');
|
||||
var providerInput = document.getElementById('shipment-provider-code');
|
||||
|
||||
if (!carrierSelect || !hiddenInput) return;
|
||||
|
||||
@@ -489,12 +541,13 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
}
|
||||
|
||||
function showPanel(carrier) {
|
||||
allegroPanel.style.display = carrier === 'allegro' ? '' : 'none';
|
||||
inpostPanel.style.display = carrier === 'inpost' ? '' : 'none';
|
||||
emptyPanel.style.display = carrier === '' ? '' : 'none';
|
||||
if (allegroPanel) allegroPanel.style.display = carrier === 'allegro' ? '' : 'none';
|
||||
if (inpostPanel) inpostPanel.style.display = carrier === 'inpost' ? '' : 'none';
|
||||
if (apaczkaPanel) apaczkaPanel.style.display = carrier === 'apaczka' ? '' : 'none';
|
||||
if (emptyPanel) emptyPanel.style.display = carrier === '' ? '' : 'none';
|
||||
if (providerInput) providerInput.value = carrier === 'apaczka' ? 'apaczka' : 'allegro_wza';
|
||||
}
|
||||
|
||||
// --- Carrier select ---
|
||||
carrierSelect.addEventListener('change', function () {
|
||||
clearHiddenFields();
|
||||
if (searchInput) searchInput.value = '';
|
||||
@@ -502,17 +555,21 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
inpostSelect.selectedIndex = 0;
|
||||
if (inpostSelect._syncTrigger) inpostSelect._syncTrigger();
|
||||
}
|
||||
if (apaczkaSelect) {
|
||||
apaczkaSelect.selectedIndex = 0;
|
||||
if (apaczkaSelect._syncTrigger) apaczkaSelect._syncTrigger();
|
||||
}
|
||||
allegroOpts.forEach(function (o) { o.classList.remove('is-selected'); });
|
||||
showPanel(carrierSelect.value);
|
||||
});
|
||||
|
||||
// --- InPost select ---
|
||||
if (inpostSelect) {
|
||||
function syncInpostFields() {
|
||||
var opt = inpostSelect.options[inpostSelect.selectedIndex];
|
||||
hiddenInput.value = inpostSelect.value;
|
||||
credentialsInput.value = opt ? (opt.getAttribute('data-credentials-id') || '') : '';
|
||||
carrierInput.value = opt ? (opt.getAttribute('data-carrier-id') || '') : '';
|
||||
if (providerInput) providerInput.value = 'allegro_wza';
|
||||
}
|
||||
inpostSelect.addEventListener('change', syncInpostFields);
|
||||
if (carrierSelect.value === 'inpost' && inpostSelect.value !== '') {
|
||||
@@ -520,7 +577,20 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
}
|
||||
}
|
||||
|
||||
// --- Allegro searchable select ---
|
||||
if (apaczkaSelect) {
|
||||
function syncApaczkaFields() {
|
||||
var opt = apaczkaSelect.options[apaczkaSelect.selectedIndex];
|
||||
hiddenInput.value = apaczkaSelect.value;
|
||||
credentialsInput.value = '';
|
||||
carrierInput.value = opt ? (opt.getAttribute('data-carrier-id') || '') : '';
|
||||
if (providerInput) providerInput.value = 'apaczka';
|
||||
}
|
||||
apaczkaSelect.addEventListener('change', syncApaczkaFields);
|
||||
if (carrierSelect.value === 'apaczka' && apaczkaSelect.value !== '') {
|
||||
syncApaczkaFields();
|
||||
}
|
||||
}
|
||||
|
||||
if (wrapper && searchInput && dropdown) {
|
||||
var isAllegroOpen = false;
|
||||
|
||||
@@ -528,6 +598,7 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
hiddenInput.value = opt.getAttribute('data-value') || '';
|
||||
credentialsInput.value = opt.getAttribute('data-credentials-id') || '';
|
||||
carrierInput.value = opt.getAttribute('data-carrier-id') || '';
|
||||
if (providerInput) providerInput.value = 'allegro_wza';
|
||||
searchInput.value = opt.getAttribute('data-label') || '';
|
||||
closeAllegro();
|
||||
allegroOpts.forEach(function (o) { o.classList.remove('is-selected'); });
|
||||
@@ -592,7 +663,6 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
}
|
||||
}
|
||||
|
||||
// --- Check status ---
|
||||
function checkPackageStatus(pkgId, oId, btn, attempt) {
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
@@ -601,19 +671,24 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
fetch('/orders/' + oId + '/shipment/' + pkgId + '/status')
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
if (data.status === 'created' || data.status === 'label_ready') {
|
||||
if (data.status === 'label_ready') {
|
||||
window.location.reload();
|
||||
} else if (data.status === 'created' || data.status === 'in_progress' || data.status === 'pending') {
|
||||
if (attempt < 10) {
|
||||
var delayCreated = Math.min(2000 * Math.pow(1.5, attempt), 15000);
|
||||
setTimeout(function () {
|
||||
checkPackageStatus(pkgId, oId, btn, attempt + 1);
|
||||
}, delayCreated);
|
||||
if (btn) btn.textContent = 'Generuje etykiete... (' + (attempt + 1) + ')';
|
||||
} else if (btn) {
|
||||
btn.textContent = 'W toku... Odswiez status';
|
||||
btn.disabled = false;
|
||||
}
|
||||
} else if (data.status === 'error') {
|
||||
if (btn) {
|
||||
btn.textContent = 'Blad: ' + (data.error || '');
|
||||
btn.disabled = false;
|
||||
}
|
||||
} else if (attempt < 10) {
|
||||
var delay = Math.min(2000 * Math.pow(1.5, attempt), 15000);
|
||||
setTimeout(function () {
|
||||
checkPackageStatus(pkgId, oId, btn, attempt + 1);
|
||||
}, delay);
|
||||
if (btn) btn.textContent = 'Sprawdzam... (' + (attempt + 1) + ')';
|
||||
} else {
|
||||
if (btn) {
|
||||
btn.textContent = 'W toku... Sprobuj ponownie';
|
||||
@@ -629,7 +704,6 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
});
|
||||
}
|
||||
|
||||
// Manual check buttons
|
||||
document.querySelectorAll('[data-check-status]').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
checkPackageStatus(
|
||||
@@ -641,15 +715,25 @@ $defaultCodAmount = $isCod ? number_format($totalWithTax, 2, '.', '') : '0';
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-poll pending packages on page load
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
var autoCheckId = params.get('check');
|
||||
if (autoCheckId) {
|
||||
var autoBtn = document.querySelector('[data-check-status="' + autoCheckId + '"]');
|
||||
var autoOrderId = autoBtn ? autoBtn.getAttribute('data-order-id') : params.get('id');
|
||||
if (autoOrderId) {
|
||||
checkPackageStatus(autoCheckId, autoOrderId, autoBtn, 0);
|
||||
|
||||
document.querySelectorAll('[data-check-status][data-auto-check=\"1\"]').forEach(function (btn, idx) {
|
||||
var pkgId = btn.getAttribute('data-check-status');
|
||||
var oId = btn.getAttribute('data-order-id');
|
||||
var pkgStatus = (btn.getAttribute('data-package-status') || '').toLowerCase();
|
||||
if (!pkgId || !oId) return;
|
||||
|
||||
if (autoCheckId) {
|
||||
if (pkgId !== autoCheckId) return;
|
||||
} else {
|
||||
if (pkgStatus !== 'pending') return;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
checkPackageStatus(pkgId, oId, btn, 0);
|
||||
}, idx * 400);
|
||||
});
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user