From 51c6748894327f5423a912dfea98e2dfe6805e5d Mon Sep 17 00:00:00 2001 From: Hickmeister <35031453+Hickmeister@users.noreply.github.com> Date: Sun, 11 Oct 2026 20:36:04 +0100 Subject: [PATCH] Read Parcel2Go label hash from order links when Hash is empty Co-Authored-By: Claude Sonnet 5.5 --- app/Http/Controllers/ShippingController.php | 5 +++-- app/Services/Parcel2Go.php | 19 +++++++++++++++++++ resources/views/shipping.blade.php | 2 +- tests/Feature/IntegrationsTest.php | 19 +++++++++++++++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/ShippingController.php b/app/Http/Controllers/ShippingController.php index 140bccb..58d7acc 100644 --- a/app/Http/Controllers/ShippingController.php +++ b/app/Http/Controllers/ShippingController.php @@ -225,8 +225,9 @@ class ShippingController extends Controller abort_unless(ctype_digit($orderLineId), 404); $orders = $parcel2Go->fetch('me/orders/detail')['Orders'] ?? []; $order = collect($orders)->first(fn ($order) => (string) ($order['OrderLineId'] ?? '') === $orderLineId); - abort_unless($order && ! empty($order['Hash']), 404); - $pdf = $parcel2Go->labelPdf($orderLineId, $order['Hash']); + $hash = $order ? $parcel2Go->labelHash($order) : null; + abort_unless($hash, 404); + $pdf = $parcel2Go->labelPdf($orderLineId, $hash); return response($pdf, 200, [ 'Content-Type' => 'application/pdf', diff --git a/app/Services/Parcel2Go.php b/app/Services/Parcel2Go.php index feaa340..0cead32 100644 --- a/app/Services/Parcel2Go.php +++ b/app/Services/Parcel2Go.php @@ -163,6 +163,25 @@ class Parcel2Go ])->throw()->json() ?? []; } + /** + * Parcel2Go leaves the order's Hash empty and puts the label hash in its "labels-a4" link instead. + * + * @param array $order + */ + public function labelHash(array $order): ?string + { + if (filled($order['Hash'] ?? null)) { + return (string) $order['Hash']; + } + $link = collect($order['Links'] ?? [])->first(fn ($link): bool => is_array($link) && str_starts_with((string) ($link['Name'] ?? ''), 'labels-a4'))['Link'] ?? null; + if (! is_string($link)) { + return null; + } + parse_str((string) parse_url($link, PHP_URL_QUERY), $query); + + return filled($query['hash'] ?? null) ? (string) $query['hash'] : null; + } + public function labelPdf(string $reference, string $hash): string { $token = $this->profileConnected() ? $this->profileAccessToken() : $this->accessToken(); diff --git a/resources/views/shipping.blade.php b/resources/views/shipping.blade.php index ed6d74d..6a63bfe 100644 --- a/resources/views/shipping.blade.php +++ b/resources/views/shipping.blade.php @@ -35,7 +35,7 @@

Existing shipments

Current Parcel2Go progress and labels from your account history.

@forelse(($orders['Orders'] ?? []) as $order) - + @empty@endforelse
OrderCourierServiceProgressEstimated deliveryRecipientDestinationLabel
{{ $order['OrderLineId'] ?? '—' }}{{ $order['Courier'] ?? '—' }}{{ $order['Service'] ?? '—' }} $order['Tracking']['Delivered'] ?? false, 'bg-sky-500/10 text-sky-300' => ! ($order['Tracking']['Delivered'] ?? false)])>{{ ($order['Tracking']['Delivered'] ?? false) ? 'Delivered' : 'In transit' }}{{ app(\App\Services\Display::class)->dateTime($order['EstimatedDeliveryDate'] ?? null) }}{{ $order['DeliveryAddress']['ContactName'] ?? '—' }}{{ app(\App\Services\Display::class)->flag($order['DeliveryAddress'] ?? []) }}@if(! empty($order['Hash']) && ! empty($order['OrderLineId']))Download PDF@elseUnavailable@endif
{{ $order['OrderLineId'] ?? '—' }}{{ $order['Courier'] ?? '—' }}{{ $order['Service'] ?? '—' }} $order['Tracking']['Delivered'] ?? false, 'bg-sky-500/10 text-sky-300' => ! ($order['Tracking']['Delivered'] ?? false)])>{{ ($order['Tracking']['Delivered'] ?? false) ? 'Delivered' : 'In transit' }}{{ app(\App\Services\Display::class)->dateTime($order['EstimatedDeliveryDate'] ?? null) }}{{ $order['DeliveryAddress']['ContactName'] ?? '—' }}{{ app(\App\Services\Display::class)->flag($order['DeliveryAddress'] ?? []) }}@if(app(\App\Services\Parcel2Go::class)->labelHash($order) && ! empty($order['OrderLineId']))Download PDF@elseUnavailable@endif
{{ $historyAvailable ? 'No shipments in Parcel2Go account history.' : 'Shipment history is unavailable. Check the Client Credentials in Settings.' }}
@endsection diff --git a/tests/Feature/IntegrationsTest.php b/tests/Feature/IntegrationsTest.php index c81d8e5..f926e40 100644 --- a/tests/Feature/IntegrationsTest.php +++ b/tests/Feature/IntegrationsTest.php @@ -191,6 +191,25 @@ class IntegrationsTest extends TestCase Http::assertSent(fn ($request) => str_contains($request->url(), '/labels/123') && str_contains($request->url(), 'hash=order-hash')); } + public function test_shipping_label_uses_the_hash_from_order_links_when_hash_field_is_empty(): void + { + Http::preventStrayRequests(); + Http::fake([ + 'https://auth.example.test/token' => Http::response(['access_token' => 'test-token']), + 'https://shipping.example.test/api/me/orders/detail' => Http::response(['Orders' => [[ + 'OrderLineId' => 123, 'Hash' => null, + 'Links' => [['Name' => 'labels-a4', 'Link' => 'https://www.parcel2go.com/label/orderline?media=0&orderlineid=123&hash=link%2Bhash%3D']], + ]]]), + 'https://shipping.example.test/api/labels/123*' => Http::response(['Base64EncodedLabels' => [base64_encode('%PDF-1.4 test label')]]), + ]); + config()->set('services.parcel2go', ['client_id' => 'id', 'client_secret' => 'secret', 'auth_url' => 'https://auth.example.test/token', 'base_url' => 'https://shipping.example.test/api']); + + $admin = User::factory()->create(['role' => 'admin']); + $this->actingAs($admin)->get(route('shipping'))->assertSee(route('shipping.label', 123), false); + $this->actingAs($admin)->get(route('shipping.label', 123))->assertOk()->assertSee('%PDF-1.4 test label'); + Http::assertSent(fn ($request) => str_contains($request->url(), '/labels/123') && str_contains($request->url(), 'hash=link%2Bhash%3D')); + } + public function test_collection_booking_uses_quoted_service_and_available_date(): void { $this->pendingEtsyOrder();