diff --git a/app/Http/Controllers/ShippingController.php b/app/Http/Controllers/ShippingController.php index 0b452e9..0152e84 100644 --- a/app/Http/Controllers/ShippingController.php +++ b/app/Http/Controllers/ShippingController.php @@ -45,16 +45,18 @@ class ShippingController extends Controller $profileNotice = $parcel2Go->profileConnected() ? 'Parcel2Go account access needs attention. Reconnect the account in Settings.' : ($exception instanceof RequestException && in_array($exception->response->status(), [401, 403], true) - ? 'Parcel2Go denied shipment history for this client. Connect an Authorization Code client in Settings.' + ? 'Parcel2Go denied shipment history for the saved Client Credentials client. Check that its Client ID and secret match the client used by your previous dashboard.' : 'Parcel2Go shipment history is temporarily unavailable.'); } - if ($parcel2Go->profileConnected() || $parcel2Go->hasScope('my-profile')) { - try { - $account = $parcel2Go->fetch('me/detail'); - $balance = $parcel2Go->fetch('me/prepay/balance'); - } catch (Throwable $exception) { - report($exception); - } + try { + $account = $parcel2Go->fetch('me/detail'); + } catch (Throwable $exception) { + report($exception); + } + try { + $balance = $parcel2Go->fetch('me/prepay/balance'); + } catch (Throwable $exception) { + report($exception); } } catch (Throwable $exception) { report($exception); diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index 9e9854c..05fd885 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -59,16 +59,16 @@ -

Keep basic public-api access for quotes and bookings. The separate Authorization Code client connects your own account for shipment history and labels.

+

The dashboard tries shipments, account details and balance with your Client Credentials connection, as the previous dashboard did. If Parcel2Go denies history, check that these credentials belong to the same client that worked before.

-

Parcel2Go account consent

$integrations['parcel2go']['profile_connected'], 'bg-amber-500/10 text-amber-200' => ! $integrations['parcel2go']['profile_connected']])>{{ $integrations['parcel2go']['profile_connected'] ? 'Connected' : 'Not connected' }}
+

Optional Parcel2Go account consent

$integrations['parcel2go']['profile_connected'], 'bg-amber-500/10 text-amber-200' => ! $integrations['parcel2go']['profile_connected']])>{{ $integrations['parcel2go']['profile_connected'] ? 'Connected' : 'Not connected' }}

Create an Authorization Code client in Parcel2Go. Set Application URL to {{ url('/') }} and Redirect URI to this exact address:

{{ $integrations['parcel2go']['callback_url'] }}

Save its Client ID above, then sign in and approve my-profile access. The account tokens are encrypted in the database. If Parcel2Go does not issue a refresh token, reconnect when access expires. If consent rejects this scope, contact apihelp@parcel2go.com.

diff --git a/resources/views/shipping.blade.php b/resources/views/shipping.blade.php index 15c0742..aa6129b 100644 --- a/resources/views/shipping.blade.php +++ b/resources/views/shipping.blade.php @@ -36,6 +36,6 @@ @forelse(($orders['Orders'] ?? []) as $order) - @empty@endforelse + @empty@endforelse
OrderCourierServiceProgressEstimated deliveryRecipientLabel
{{ $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' }}{{ $order['EstimatedDeliveryDate'] ?? '—' }}{{ $order['DeliveryAddress']['ContactName'] ?? '—' }}@if(! empty($order['Hash']) && ! empty($order['OrderLineId']))Download PDF@elseUnavailable@endif
{{ $historyAvailable ? 'No shipments in Parcel2Go account history.' : 'Shipment history is unavailable until Parcel2Go grants access to this client.' }}
{{ $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 1bb4fd7..e2a95ff 100644 --- a/tests/Feature/IntegrationsTest.php +++ b/tests/Feature/IntegrationsTest.php @@ -91,7 +91,11 @@ class IntegrationsTest extends TestCase return $request['scope'] === 'public-api' ? Http::response(['access_token' => 'test-token']) : Http::response(['error' => 'invalid_scope'], 400); - }, 'https://shipping.example.test/api/me/orders/detail' => Http::response([], 403)]); + }, + 'https://shipping.example.test/api/me/orders/detail' => Http::response([], 403), + 'https://shipping.example.test/api/me/detail' => Http::response([], 403), + 'https://shipping.example.test/api/me/prepay/balance' => Http::response([], 403), + ]); config()->set('services.parcel2go', [ 'client_id' => 'id', 'client_secret' => 'secret', 'auth_url' => 'https://auth.example.test/token', @@ -102,7 +106,7 @@ class IntegrationsTest extends TestCase $this->actingAs(User::factory()->create(['role' => 'admin']))->get(route('shipping')) ->assertOk()->assertSee('Pending Etsy orders')->assertSee('Parcel2Go denied shipment history') ->assertDontSee('Parcel2Go is unavailable'); - Http::assertSentCount(2); + Http::assertSentCount(4); } public function test_shipping_shows_existing_shipments_when_basic_access_can_read_history(): void @@ -115,6 +119,8 @@ class IntegrationsTest extends TestCase 'Tracking' => ['Delivered' => true], 'DeliveryAddress' => ['ContactName' => 'Buyer'], 'EstimatedDeliveryDate' => '2026-10-15', 'Hash' => 'hash', ]]]), + 'https://shipping.example.test/api/me/detail' => Http::response(['Forename' => 'Lee', 'Surname' => 'Hickman']), + 'https://shipping.example.test/api/me/prepay/balance' => Http::response(['Balance' => 12.5]), ]); config()->set('services.parcel2go', [ 'client_id' => 'id', 'client_secret' => 'secret', @@ -125,8 +131,11 @@ class IntegrationsTest extends TestCase $this->actingAs(User::factory()->create(['role' => 'admin']))->get(route('shipping')) ->assertOk()->assertSee('Existing shipments')->assertSee('Delivered')->assertSee('Buyer') + ->assertSee('Lee Hickman')->assertSee('12.50') ->assertDontSee('Parcel2Go denied shipment history'); - Http::assertSentCount(2); + Http::assertSent(fn ($request) => $request->url() === 'https://shipping.example.test/api/me/detail' && $request->hasHeader('Authorization', 'Bearer test-token')); + Http::assertSent(fn ($request) => $request->url() === 'https://shipping.example.test/api/me/prepay/balance' && $request->hasHeader('Authorization', 'Bearer test-token')); + Http::assertSentCount(4); } public function test_shipping_rejects_a_quote_for_an_order_that_is_not_pending(): void @@ -149,7 +158,11 @@ class IntegrationsTest extends TestCase return $request['scope'] === 'public-api' ? Http::response(['access_token' => 'test-token']) : Http::response(['error' => 'invalid_scope'], 400); - }, 'https://shipping.example.test/api/me/orders/detail' => Http::response([], 403)]); + }, + 'https://shipping.example.test/api/me/orders/detail' => Http::response([], 403), + 'https://shipping.example.test/api/me/detail' => Http::response([], 403), + 'https://shipping.example.test/api/me/prepay/balance' => Http::response([], 403), + ]); config()->set('services.parcel2go', [ 'client_id' => 'id', 'client_secret' => 'secret', 'auth_url' => 'https://auth.example.test/token', @@ -160,7 +173,7 @@ class IntegrationsTest extends TestCase $this->actingAs(User::factory()->create(['role' => 'admin']))->get(route('shipping')) ->assertOk()->assertSee('Parcel2Go denied shipment history') ->assertDontSee('Parcel2Go is unavailable'); - Http::assertSentCount(3); + Http::assertSentCount(5); } public function test_shipping_label_is_downloaded_for_an_order_in_account_history(): void