feat(07-pre-expansion-fixes): complete phase 07 — milestone v0.2 done
Phase 7 complete (5 plans): - 07-01: Performance (N+1→LEFT JOIN, static cache, DB indexes) - 07-02: Stability (SSL verification, cron throttle DB, migration 000014b) - 07-03: UX (orderpro_to_allegro disable, lista zamówień fixes, SSL hotfix) - 07-04: Tests (12 unit tests for AllegroTokenManager + AllegroOrderImportService) - 07-05: InPost ShipX API (natywny provider, workaround remap usunięty) Additional fixes: - 5 broken use-statements fixed across 4 files - vendor/ excluded from ftp-kr auto-upload - PHPUnit + dg/bypass-finals infrastructure Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
230
tests/Unit/AllegroOrderImportServiceTest.php
Normal file
230
tests/Unit/AllegroOrderImportServiceTest.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Core\Exceptions\AllegroApiException;
|
||||
use App\Modules\Orders\OrderImportRepository;
|
||||
use App\Modules\Orders\OrdersRepository;
|
||||
use App\Modules\Settings\AllegroApiClient;
|
||||
use App\Modules\Settings\AllegroIntegrationRepository;
|
||||
use App\Modules\Settings\AllegroOrderImportService;
|
||||
use App\Modules\Settings\AllegroStatusMappingRepository;
|
||||
use App\Modules\Settings\AllegroTokenManager;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use RuntimeException;
|
||||
|
||||
final class AllegroOrderImportServiceTest extends TestCase
|
||||
{
|
||||
private AllegroIntegrationRepository&MockObject $integrationRepository;
|
||||
private AllegroTokenManager&MockObject $tokenManager;
|
||||
private AllegroApiClient&MockObject $apiClient;
|
||||
private OrderImportRepository&MockObject $orders;
|
||||
private AllegroStatusMappingRepository&MockObject $statusMappings;
|
||||
private OrdersRepository&MockObject $ordersRepository;
|
||||
private AllegroOrderImportService $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->integrationRepository = $this->createMock(AllegroIntegrationRepository::class);
|
||||
$this->tokenManager = $this->createMock(AllegroTokenManager::class);
|
||||
$this->apiClient = $this->createMock(AllegroApiClient::class);
|
||||
$this->orders = $this->createMock(OrderImportRepository::class);
|
||||
$this->statusMappings = $this->createMock(AllegroStatusMappingRepository::class);
|
||||
$this->ordersRepository = $this->createMock(OrdersRepository::class);
|
||||
|
||||
$this->service = new AllegroOrderImportService(
|
||||
$this->integrationRepository,
|
||||
$this->tokenManager,
|
||||
$this->apiClient,
|
||||
$this->orders,
|
||||
$this->statusMappings,
|
||||
$this->ordersRepository
|
||||
);
|
||||
}
|
||||
|
||||
public function testImportSingleOrderHappyPath(): void
|
||||
{
|
||||
$checkoutFormId = 'abc-123';
|
||||
$payload = $this->buildMinimalPayload($checkoutFormId);
|
||||
|
||||
$this->tokenManager
|
||||
->method('resolveToken')
|
||||
->willReturn(['access-token-xyz', 'sandbox']);
|
||||
|
||||
$this->apiClient
|
||||
->method('getCheckoutForm')
|
||||
->with('sandbox', 'access-token-xyz', $checkoutFormId)
|
||||
->willReturn($payload);
|
||||
|
||||
$this->apiClient
|
||||
->method('getCheckoutFormShipments')
|
||||
->willReturn([]);
|
||||
|
||||
$this->integrationRepository
|
||||
->method('getActiveIntegrationId')
|
||||
->willReturn(5);
|
||||
|
||||
$this->statusMappings
|
||||
->method('findMappedOrderproStatusCode')
|
||||
->willReturn('new');
|
||||
|
||||
$this->orders
|
||||
->expects($this->once())
|
||||
->method('upsertOrderAggregate')
|
||||
->willReturn(['order_id' => 42, 'created' => true]);
|
||||
|
||||
$this->ordersRepository
|
||||
->expects($this->once())
|
||||
->method('recordActivity')
|
||||
->with(42, 'import', $this->stringContains('Zaimportowano'));
|
||||
|
||||
$result = $this->service->importSingleOrder($checkoutFormId);
|
||||
|
||||
$this->assertSame(42, $result['order_id']);
|
||||
$this->assertTrue($result['created']);
|
||||
$this->assertSame($checkoutFormId, $result['source_order_id']);
|
||||
}
|
||||
|
||||
public function testImportSingleOrderRetryOn401(): void
|
||||
{
|
||||
$checkoutFormId = 'retry-456';
|
||||
$payload = $this->buildMinimalPayload($checkoutFormId);
|
||||
|
||||
$this->tokenManager
|
||||
->method('resolveToken')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
['stale-token', 'sandbox'],
|
||||
['fresh-token', 'sandbox']
|
||||
);
|
||||
|
||||
$callCount = 0;
|
||||
$this->apiClient
|
||||
->method('getCheckoutForm')
|
||||
->willReturnCallback(function () use (&$callCount, $payload): array {
|
||||
$callCount++;
|
||||
if ($callCount === 1) {
|
||||
throw new RuntimeException('ALLEGRO_HTTP_401');
|
||||
}
|
||||
return $payload;
|
||||
});
|
||||
|
||||
$this->apiClient->method('getCheckoutFormShipments')->willReturn([]);
|
||||
$this->integrationRepository->method('getActiveIntegrationId')->willReturn(1);
|
||||
$this->statusMappings->method('findMappedOrderproStatusCode')->willReturn(null);
|
||||
|
||||
$this->orders
|
||||
->expects($this->once())
|
||||
->method('upsertOrderAggregate')
|
||||
->willReturn(['order_id' => 99, 'created' => true]);
|
||||
|
||||
$result = $this->service->importSingleOrder($checkoutFormId);
|
||||
|
||||
$this->assertSame(99, $result['order_id']);
|
||||
$this->assertSame(2, $callCount);
|
||||
}
|
||||
|
||||
public function testImportSingleOrderThrowsOnEmptyId(): void
|
||||
{
|
||||
$this->expectException(AllegroApiException::class);
|
||||
$this->expectExceptionMessage('Podaj ID zamowienia');
|
||||
|
||||
$this->service->importSingleOrder('');
|
||||
}
|
||||
|
||||
public function testImportSingleOrderPropagatesNon401RuntimeException(): void
|
||||
{
|
||||
$this->tokenManager
|
||||
->method('resolveToken')
|
||||
->willReturn(['token', 'sandbox']);
|
||||
|
||||
$this->apiClient
|
||||
->method('getCheckoutForm')
|
||||
->willThrowException(new RuntimeException('ALLEGRO_HTTP_500'));
|
||||
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage('ALLEGRO_HTTP_500');
|
||||
|
||||
$this->service->importSingleOrder('order-789');
|
||||
}
|
||||
|
||||
public function testImportSingleOrderReturnsCorrectFieldsOnReImport(): void
|
||||
{
|
||||
$checkoutFormId = 'reimport-001';
|
||||
$payload = $this->buildMinimalPayload($checkoutFormId);
|
||||
|
||||
$this->tokenManager->method('resolveToken')->willReturn(['tok', 'production']);
|
||||
$this->apiClient->method('getCheckoutForm')->willReturn($payload);
|
||||
$this->apiClient->method('getCheckoutFormShipments')->willReturn([]);
|
||||
$this->integrationRepository->method('getActiveIntegrationId')->willReturn(1);
|
||||
$this->statusMappings->method('findMappedOrderproStatusCode')->willReturn(null);
|
||||
|
||||
$this->orders
|
||||
->method('upsertOrderAggregate')
|
||||
->willReturn(['order_id' => 10, 'created' => false]);
|
||||
|
||||
$this->ordersRepository
|
||||
->expects($this->once())
|
||||
->method('recordActivity')
|
||||
->with(10, 'import', $this->stringContains('Zaktualizowano'));
|
||||
|
||||
$result = $this->service->importSingleOrder($checkoutFormId);
|
||||
|
||||
$this->assertSame(10, $result['order_id']);
|
||||
$this->assertFalse($result['created']);
|
||||
$this->assertArrayHasKey('image_diagnostics', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildMinimalPayload(string $checkoutFormId): array
|
||||
{
|
||||
return [
|
||||
'id' => $checkoutFormId,
|
||||
'status' => 'READY_FOR_PROCESSING',
|
||||
'fulfillment' => ['status' => 'NEW'],
|
||||
'payment' => [
|
||||
'id' => 'pay-1',
|
||||
'type' => 'allegro',
|
||||
'status' => 'paid',
|
||||
'amount' => ['amount' => '99.00', 'currency' => 'PLN'],
|
||||
'paidAmount' => ['amount' => '99.00', 'currency' => 'PLN'],
|
||||
],
|
||||
'summary' => [
|
||||
'totalToPay' => ['amount' => '99.00', 'currency' => 'PLN'],
|
||||
],
|
||||
'buyer' => [
|
||||
'login' => 'test-buyer',
|
||||
'firstName' => 'Jan',
|
||||
'lastName' => 'Kowalski',
|
||||
'email' => 'jan@example.com',
|
||||
'phoneNumber' => '500100200',
|
||||
],
|
||||
'delivery' => [
|
||||
'method' => ['id' => 'inpost', 'name' => 'InPost Paczkomaty'],
|
||||
'address' => [
|
||||
'firstName' => 'Jan',
|
||||
'lastName' => 'Kowalski',
|
||||
'street' => 'ul. Testowa 1',
|
||||
'city' => 'Warszawa',
|
||||
'zipCode' => '00-001',
|
||||
'countryCode' => 'PL',
|
||||
],
|
||||
],
|
||||
'lineItems' => [
|
||||
[
|
||||
'id' => 'item-1',
|
||||
'offer' => ['id' => 'offer-1', 'name' => 'Produkt testowy'],
|
||||
'quantity' => 2,
|
||||
'originalPrice' => ['amount' => '49.50', 'currency' => 'PLN'],
|
||||
],
|
||||
],
|
||||
'invoice' => [],
|
||||
'marketplace' => ['id' => 'allegro-pl'],
|
||||
'boughtAt' => '2026-03-14T10:00:00Z',
|
||||
'updatedAt' => '2026-03-14T10:05:00Z',
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user