-
-
Notifications
You must be signed in to change notification settings - Fork 739
There is a false-positive related to the Exception #9679
Copy link
Copy link
Closed
rectorphp/rector-src
#7919Description
Reproducible example: https://getrector.com/demo/e35f58d3-1734-41a0-a56f-f28fbf3350c7
Rector Version: 44a8dfcfbc50eab152582d466b3df5eceff009d7
Rector Output
1 file with changes
===================
1) src/Taxes/Fiscalization/ReceiptGeneratorService.php:80
---------- begin diff ----------
@@ @@
try {
$this->shiftService->maybeStartShift($jwt);
} catch (ShiftStartException $e) {
- throw new ReceiptCreateException(isClearLock: true, message: $e->getMessage(), previous: $e);
+ throw new ReceiptCreateException(isClearLock: true, message: $e->getMessage(), previous: $e, previous: $e);
}
$payload = new ReceiptSellPayload();
$this->payloadService->fillDelivery($payload, $bill);
@@ @@
$text .= ': '.$detail[0]->getMsg();
}
}
- throw new ReceiptCreateException(isClearLock: true, message: $text, previous: $e);
+ throw new ReceiptCreateException(isClearLock: true, message: $text, previous: $e, previous: $e);
} catch (Throwable $exception) {
- throw new ReceiptCreateException(isClearLock: false, message: $exception->getMessage(), previous: $exception);
+ throw new ReceiptCreateException(isClearLock: false, message: $exception->getMessage(), previous: $exception, previous: $exception);
}
assert($result instanceof ReceiptModel);
----------- end diff -----------
Applied rules:
* ThrowWithPreviousExceptionRector
[OK] 1 file would have been changed (dry-run) by Rector
Original file
<?php
declare(strict_types=1);
namespace App\Taxes\Fiscalization;
use App\CheckboxUAClientInterface;
use App\Entity\PaymentGatewayFiscalizationCredentials;
use App\Entity\ShopPaymentBill;
use App\Entity\ShopPaymentBillFiscalizationError;
use App\Entity\ShopPaymentBillFiscalizationLock;
use App\Entity\ShopPaymentBillFiscalReceipt;
use App\Service\EntityManagerService;
use App\Taxes\Fiscalization\Exception\ReceiptCreateException;
use App\Taxes\Fiscalization\Exception\ShiftStartException;
use Grisaia\Time\Timestamp;
use RevoTale\CheckboxUA\Exception\CreateReceiptApiV1ReceiptsSellPostUnprocessableEntityException;
use RevoTale\CheckboxUA\Exception\UnexpectedStatusCodeException;
use RevoTale\CheckboxUA\Model\ReceiptModel;
use RevoTale\CheckboxUA\Model\ReceiptSellPayload;
use Throwable;
use function assert;
final readonly class ReceiptGeneratorService
{
public function __construct(
private ShiftService $shiftService,
private JWTService $jwtService,
private EntityManagerService $manager,
private CheckboxPayloadAdapterService $payloadService,
private ReceiptFiscalizationLockService $lockService,
private CheckboxUAClientInterface $clientService,
) {
}
/**
* @throws ReceiptCreateException
* @throws Throwable
*/
public function createReceipt(ShopPaymentBill $bill): ReceiptModel
{
if ($this->lockService->isLocked($bill)) {
throw new ReceiptCreateException(isClearLock: false, message: 'Bill processing is locked.');
}
$billLock = $this->lockService->lockBill($bill); // Prevent duplicate api calls
$rateLimit = 2; // Rate limit defined by Checkbox
try {
$result = $this->handleReceipt($bill);
sleep($rateLimit);
$this->lockService->removeLock($billLock);
return $result;
} catch (ReceiptCreateException $exception) {
$this->handleError(bill: $bill, exception: $exception, lock: $billLock);
sleep($rateLimit);
throw $exception;
} catch (Throwable $exception) {
sleep($rateLimit);
throw $exception;
}
}
/**
* @throws ReceiptCreateException
*/
private function handleReceipt(ShopPaymentBill $bill): ReceiptModel
{
$this->manager->registry->getManager()->refresh($bill);
$this->validate($bill);
$org = $bill->getPaymentGateway()->getOrganization();
if (null === $org) {
throw new ReceiptCreateException(isClearLock: true, message: 'No organization related');
}
$jwt = $this->jwtService->resolveCredentials($org);
if (null === $jwt) {
throw new ReceiptCreateException(isClearLock: true, message: 'JWT does not exist');
}
try {
$this->shiftService->maybeStartShift($jwt);
} catch (ShiftStartException $e) {
throw new ReceiptCreateException(isClearLock: true, message: $e->getMessage(), previous: $e);
}
$payload = new ReceiptSellPayload();
$this->payloadService->fillDelivery($payload, $bill);
$this->payloadService->fillPayload($bill, $payload);
$this->validate($bill); // Double validate in case if bad locks
$result = $this->fetchCreateReceipt(credentials: $jwt, payload: $payload);
$receipt = new ShopPaymentBillFiscalReceipt(
bill: $bill, fiscalReceiptId: $result->getId()
);
$this->manager->persistAndFlush($receipt);
return $result;
}
private function handleError(ShopPaymentBill $bill, ReceiptCreateException $exception, ShopPaymentBillFiscalizationLock $lock): void
{
$errorEntity = new ShopPaymentBillFiscalizationError(bill: $bill, message: $exception->getMessage(), context: $exception->getTraceAsString());
$this->manager->persist($errorEntity);
if ($exception->isClearLock()) {
$this->lockService->removeLock($lock);
}
$this->manager->flush();
}
/**
* @throws ReceiptCreateException
*/
private function validate(ShopPaymentBill $bill): void
{
if (null !== $bill->getFiscalReceipt() || null !== $this->manager->registry->getRepository(ShopPaymentBillFiscalReceipt::class)->findOneBy([
'bill' => $bill,
])) {
throw new ReceiptCreateException(isClearLock: true, message: 'Receipt already exists for bill');
}
if (!$bill->getAmountPaid()->isEqual($bill->getAmountToPay())) {
throw new ReceiptCreateException(isClearLock: true, message: 'Bill is not paid');
}
if ($bill->getCreatedAt()->earlierThan(
Timestamp::fromUnix(ShopPaymentBillFiscalReceipt::FISCALIZE_TIME_FROM)
)) {
throw new ReceiptCreateException(isClearLock: true, message: 'Bill is too old to fiscalize');
}
}
/**
* @throws ReceiptCreateException
*/
private function fetchCreateReceipt(PaymentGatewayFiscalizationCredentials $credentials, ReceiptSellPayload $payload): ReceiptModel
{
$client = $this->clientService->createClient($credentials->getJwtToken());
try {
$result = $client->createReceiptApiV1ReceiptsSellPost($payload);
} catch (CreateReceiptApiV1ReceiptsSellPostUnprocessableEntityException|UnexpectedStatusCodeException $e) {
$text = 'Receipt api error: '.$e->getMessage();
if ($e instanceof CreateReceiptApiV1ReceiptsSellPostUnprocessableEntityException) {
$detail = $e->getHTTPValidationError()->getDetail();
if ([] !== $detail) {
$text .= ': '.$detail[0]->getMsg();
}
}
throw new ReceiptCreateException(isClearLock: true, message: $text, previous: $e);
} catch (Throwable $exception) {
throw new ReceiptCreateException(isClearLock: false, message: $exception->getMessage(), previous: $exception);
}
assert($result instanceof ReceiptModel);
return $result;
}
}
Rector config
<?php
declare(strict_types=1);
use Rector\Config\RectorConfig;
use Rector\Symfony\Bridge\Symfony\Routing\SymfonyRoutesProvider;
use Rector\Symfony\CodeQuality\Rector\Class_\ControllerMethodInjectionToConstructorRector;
use Rector\Symfony\Contract\Bridge\Symfony\Routing\SymfonyRoutesProviderInterface;
return RectorConfig::configure()
->withSymfonyContainerXml(__DIR__.'/var/cache/dev/App_KernelDevDebugContainer.xml')
->registerService(SymfonyRoutesProvider::class, SymfonyRoutesProviderInterface::class)
->withPaths([__DIR__.'/src', __DIR__.'/tests'])
->withSkip([
Rector\CodeQuality\Rector\Identical\FlipTypeControlToUseExclusiveTypeRector::class,
ControllerMethodInjectionToConstructorRector::class, // System error: "Cannot assign PhpParser\Node\Expr\PropertyFetch to property PhpParser\Node\ClosureUse::$var of type PhpParser\Node\Expr\Variable"
])
->withPreparedSets(
deadCode: true,
codeQuality: true, typeDeclarations: true,
doctrineCodeQuality: true,
symfonyCodeQuality: true,
);
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels