Skip to content

Commit

Permalink
Throw invalid NIP exception in wFirma contractor book (#60)
Browse files Browse the repository at this point in the history
This can be used to throw a specific exception when the contractor NIP (PL Vat Id) is invalid and wFirma returns an error response.
  • Loading branch information
devofdisaster authored May 23, 2023
1 parent a31e7cf commit 684cab5
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 55 deletions.
11 changes: 11 additions & 0 deletions src/Bookkeeping/Contractor/Exception/InvalidVatIdException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Landingi\BookkeepingBundle\Bookkeeping\Contractor\Exception;

use RuntimeException;

final class InvalidVatIdException extends RuntimeException
{
}
15 changes: 15 additions & 0 deletions src/Wfirma/Client/Exception/ErrorResponseException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Landingi\BookkeepingBundle\Wfirma\Client\Exception;

use Landingi\BookkeepingBundle\Wfirma\Client\WfirmaClientException;

final class ErrorResponseException extends WfirmaClientException
{
public function __construct(string $url, array $result, string $request)
{
parent::__construct($url, $result, $request, 'External system returns an error');
}
}
101 changes: 56 additions & 45 deletions src/Wfirma/Client/WfirmaClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@

namespace Landingi\BookkeepingBundle\Wfirma\Client;

use JsonException;
use Landingi\BookkeepingBundle\Bookkeeping\Expense\Collection\ExpenseCondition;
use Landingi\BookkeepingBundle\Bookkeeping\Invoice\Collection\InvoiceCondition;
use Landingi\BookkeepingBundle\Curl\Curl;
use Landingi\BookkeepingBundle\Curl\CurlException;
use Landingi\BookkeepingBundle\Wfirma\Client\Credentials\WfirmaCredentials;
use Landingi\BookkeepingBundle\Wfirma\Client\Exception\AuthorizationException;
use Landingi\BookkeepingBundle\Wfirma\Client\Exception\ErrorResponseException;
use Landingi\BookkeepingBundle\Wfirma\Client\Exception\FatalException;
use Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException;
use Landingi\BookkeepingBundle\Wfirma\Client\Exception\OutOfServiceException;
Expand Down Expand Up @@ -36,60 +39,63 @@ public function __construct(
}

/**
* @throws \JsonException
* @throws \Landingi\BookkeepingBundle\Curl\CurlException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\AuthorizationException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\FatalException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\OutOfServiceException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalRequestsLimitExceededException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalExecutionTimeLimitExceededException
* @throws JsonException
* @throws CurlException
* @throws AuthorizationException
* @throws FatalException
* @throws NotFoundException
* @throws OutOfServiceException
* @throws TotalRequestsLimitExceededException
* @throws TotalExecutionTimeLimitExceededException
* @throws ErrorResponseException
*/
public function requestGET(string $url): array
{
return $this->handleResponse(json_decode($this->getCurl($url)->requestGET(), true, 512, JSON_THROW_ON_ERROR), $url);
}

/**
* @throws \JsonException
* @throws \Landingi\BookkeepingBundle\Curl\CurlException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\AuthorizationException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\FatalException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\OutOfServiceException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalRequestsLimitExceededException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalExecutionTimeLimitExceededException
* @throws JsonException
* @throws CurlException
* @throws AuthorizationException
* @throws FatalException
* @throws NotFoundException
* @throws OutOfServiceException
* @throws TotalRequestsLimitExceededException
* @throws TotalExecutionTimeLimitExceededException
* @throws ErrorResponseException
*/
public function requestPOST(string $url, string $data): array
{
return $this->handleResponse(json_decode($this->getCurl($url)->requestPOST($data), true, 512, JSON_THROW_ON_ERROR), $url);
}

/**
* @throws \JsonException
* @throws \Landingi\BookkeepingBundle\Curl\CurlException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\AuthorizationException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\FatalException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\OutOfServiceException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalRequestsLimitExceededException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalExecutionTimeLimitExceededException
* @throws JsonException
* @throws CurlException
* @throws AuthorizationException
* @throws FatalException
* @throws NotFoundException
* @throws OutOfServiceException
* @throws TotalRequestsLimitExceededException
* @throws TotalExecutionTimeLimitExceededException
* @throws ErrorResponseException
*/
public function requestDELETE(string $url): array
{
return $this->handleResponse(json_decode($this->getCurl($url)->requestDELETE(), true, 512, JSON_THROW_ON_ERROR), $url);
}

/**
* @throws \JsonException
* @throws \Landingi\BookkeepingBundle\Curl\CurlException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\AuthorizationException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\FatalException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\OutOfServiceException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalRequestsLimitExceededException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalExecutionTimeLimitExceededException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\WfirmaClientException
* @throws JsonException
* @throws CurlException
* @throws AuthorizationException
* @throws FatalException
* @throws NotFoundException
* @throws OutOfServiceException
* @throws TotalRequestsLimitExceededException
* @throws TotalExecutionTimeLimitExceededException
* @throws WfirmaClientException
*/
public function getVatId(string $countryCode, int $vatRate): int
{
Expand Down Expand Up @@ -135,10 +141,10 @@ public function getVatId(string $countryCode, int $vatRate): int
}

/**
* @throws \JsonException
* @throws \Landingi\BookkeepingBundle\Curl\CurlException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\WfirmaClientException
* @throws JsonException
* @throws CurlException
* @throws NotFoundException
* @throws WfirmaClientException
*/
public function requestInvoiceDownload(string $url): string
{
Expand Down Expand Up @@ -179,6 +185,9 @@ function (string $carry, ExpenseCondition $condition) {
));
}

/**
* @throws CurlException
*/
private function getCurl(string $url): Curl
{
return Curl::withHeaderAuth(
Expand All @@ -193,12 +202,13 @@ private function getCurl(string $url): Curl
}

/**
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\AuthorizationException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\FatalException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\OutOfServiceException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalRequestsLimitExceededException
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\TotalExecutionTimeLimitExceededException
* @throws AuthorizationException
* @throws FatalException
* @throws NotFoundException
* @throws OutOfServiceException
* @throws TotalRequestsLimitExceededException
* @throws TotalExecutionTimeLimitExceededException
* @throws ErrorResponseException
*/
private function handleResponse(array $result, string $url, string $data = ''): array
{
Expand All @@ -216,15 +226,16 @@ private function handleResponse(array $result, string $url, string $data = ''):
throw new TotalExecutionTimeLimitExceededException($url, $result, $data);
case 'TOTAL REQUESTS LIMIT EXCEEDED':
throw new TotalRequestsLimitExceededException($url, $result, $data);
case 'FATAL':
case 'ERROR':
throw new ErrorResponseException($url, $result, $data);
case 'FATAL':
default:
throw new FatalException($url, $result, $data);
}
}

/**
* @throws \Landingi\BookkeepingBundle\Wfirma\Client\Exception\NotFoundException
* @throws NotFoundException
*/
private function handleFileResponse(string $result, string $url, string $data = ''): string
{
Expand Down
47 changes: 37 additions & 10 deletions src/Wfirma/Contractor/WfirmaContractorBook.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\ContractorBook;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\ContractorException;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\ContractorIdentifier;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\Exception\InvalidVatIdException;
use Landingi\BookkeepingBundle\Wfirma\Client\Exception\ErrorResponseException;
use Landingi\BookkeepingBundle\Wfirma\Client\WfirmaClient;
use Landingi\BookkeepingBundle\Wfirma\Client\WfirmaClientException;
use Landingi\BookkeepingBundle\Wfirma\Contractor\Factory\ContractorFactory;
Expand Down Expand Up @@ -58,17 +60,28 @@ public function find(ContractorIdentifier $identifier): Contractor
*/
public function create(Contractor $contractor): Contractor
{
return $this->contractorFactory->getContractor(
$this->getContractorResult(
$this->client->requestPOST(
sprintf(
self::CONTRACTOR_API_URL,
sprintf('%s', 'add')
),
$contractor->print(WfirmaMedia::api())->toString()
try {
return $this->contractorFactory->getContractor(
$this->getContractorResult(
$this->client->requestPOST(
sprintf(
self::CONTRACTOR_API_URL,
sprintf('%s', 'add')
),
$contractor->print(WfirmaMedia::api())->toString()
)
)
)
);
);
} catch (ErrorResponseException $e) {
try {
$contractor = $this->getContractorResult($e->getResult());
} catch (WfirmaException $invalidResponseStructureException) {
throw $e;
}

$this->tryToThrowSpecificExceptionFromResponse($contractor);
throw $e;
}
}

/**
Expand Down Expand Up @@ -111,4 +124,18 @@ private function getContractorResult(array $response): array

return $response['contractors'][0]['contractor'];
}

private function tryToThrowSpecificExceptionFromResponse(array $contractor): void
{
$error = $contractor['errors'][0]['error'] ?? [];

if (isset($error['field'])) {
switch ($error['field']) {
case 'nip':
throw new InvalidVatIdException($error['message'] ?: 'Invalid Vat Id provided');
default:
// Do nothing
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"companies": [
{
"id": "1234",
"name": "Polish Company",
"email": "[email protected]",
"street": "Witkiewicza",
"zip": "44-100",
"city": "Gliwice",
"country": "PL",
"nip": "12345678"
}
]
}
32 changes: 32 additions & 0 deletions tests/Integration/Wfirma/Contractor/WfirmaContractorBookTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\Company;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\ContractorBook;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\ContractorEmail;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\Exception\InvalidVatIdException;
use Landingi\BookkeepingBundle\Bookkeeping\Contractor\Person;
use Landingi\BookkeepingBundle\Integration\IntegrationTestCase;
use Landingi\BookkeepingBundle\Memory\Contractor\Company\ValueAddedTax\MemoryIdentifierFactory;
Expand All @@ -17,6 +18,7 @@
use Landingi\BookkeepingBundle\Wfirma\Client\WfirmaConditionTransformer;
use Landingi\BookkeepingBundle\Wfirma\Contractor\Factory\ContractorFactory;
use Landingi\BookkeepingBundle\Wfirma\Contractor\WfirmaContractorBook;
use Throwable;

final class WfirmaContractorBookTest extends IntegrationTestCase
{
Expand Down Expand Up @@ -111,4 +113,34 @@ public function companies(): Generator
yield [$factory->getContractor($company)];
}
}

/**
* @dataProvider invalidCompanies
*
* @param Contractor $company
* @param class-string<Throwable> $exceptionClass
*/
public function testErrorResponseThrowsException(Contractor $company, string $exceptionClass): void
{
$this->expectException($exceptionClass);
$this->book->create($company);
}

/**
* @internal use only in testErrorResponseThrowsException function
*/
public function invalidCompanies(): Generator
{
$factory = new ContractorFactory(new MemoryIdentifierFactory());
$data = json_decode(
(string) file_get_contents(__DIR__ . '/Resources/companies_invalid.json'),
true,
512,
JSON_THROW_ON_ERROR
);

foreach ($data['companies'] as $company) {
yield [$factory->getContractor($company), InvalidVatIdException::class];
}
}
}

0 comments on commit 684cab5

Please sign in to comment.