|
@@ -2,22 +2,28 @@
|
|
|
|
|
|
|
|
namespace Controllers;
|
|
namespace Controllers;
|
|
|
|
|
|
|
|
|
|
+use Libs\BashExecutor;
|
|
|
use Libs\ResponseLib;
|
|
use Libs\ResponseLib;
|
|
|
use Models\CprModel;
|
|
use Models\CprModel;
|
|
|
use Models\StatusModel;
|
|
use Models\StatusModel;
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
use Respect\Validation\Exceptions\ValidationException;
|
|
use Respect\Validation\Exceptions\ValidationException;
|
|
|
use Respect\Validation\Validator as val;
|
|
use Respect\Validation\Validator as val;
|
|
|
|
|
+use Services\PaymentService;
|
|
|
|
|
|
|
|
class RegisterCprController
|
|
class RegisterCprController
|
|
|
{
|
|
{
|
|
|
private CprModel $cprModel;
|
|
private CprModel $cprModel;
|
|
|
private StatusModel $statusModel;
|
|
private StatusModel $statusModel;
|
|
|
|
|
+ private PaymentService $paymentService;
|
|
|
|
|
+
|
|
|
|
|
+ private const PIX_VALUE = '1000.00';
|
|
|
|
|
|
|
|
public function __construct()
|
|
public function __construct()
|
|
|
{
|
|
{
|
|
|
$this->cprModel = new CprModel();
|
|
$this->cprModel = new CprModel();
|
|
|
$this->statusModel = new StatusModel();
|
|
$this->statusModel = new StatusModel();
|
|
|
|
|
+ $this->paymentService = new PaymentService();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function __invoke(ServerRequestInterface $request)
|
|
public function __invoke(ServerRequestInterface $request)
|
|
@@ -35,19 +41,90 @@ class RegisterCprController
|
|
|
)->withStatus(400);
|
|
)->withStatus(400);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ $userId = (int)($request->getAttribute('api_user_id') ?? 0);
|
|
|
|
|
+ if ($userId <= 0) {
|
|
|
|
|
+ return ResponseLib::sendFail('Authenticated user not found', [], 'E_VALIDATE')->withStatus(401);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
$statusId = $this->statusModel->getIdByStatus('pending');
|
|
$statusId = $this->statusModel->getIdByStatus('pending');
|
|
|
if ($statusId === null) {
|
|
if ($statusId === null) {
|
|
|
return ResponseLib::sendFail('Pending status not found', [], 'E_DATABASE')->withStatus(500);
|
|
return ResponseLib::sendFail('Pending status not found', [], 'E_DATABASE')->withStatus(500);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- $record = $this->cprModel->create($body, $statusId);
|
|
|
|
|
|
|
+ $pixData = $this->generateDynamicQrcode();
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ return ResponseLib::sendFail('Failed to generate PIX QR Code: ' . $e->getMessage(), [], 'E_INTERNAL')->withStatus(500);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ $paymentId = $this->paymentService->createPendingPayment($pixData['item_id'], $statusId, $userId);
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ return ResponseLib::sendFail('Failed to create payment record: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ $record = $this->cprModel->create($body, $statusId, $paymentId);
|
|
|
} catch (\InvalidArgumentException $e) {
|
|
} catch (\InvalidArgumentException $e) {
|
|
|
return ResponseLib::sendFail($e->getMessage(), [], 'E_VALIDATE')->withStatus(400);
|
|
return ResponseLib::sendFail($e->getMessage(), [], 'E_VALIDATE')->withStatus(400);
|
|
|
} catch (\Throwable $e) {
|
|
} catch (\Throwable $e) {
|
|
|
return ResponseLib::sendFail('Failed to create CPR: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
|
|
return ResponseLib::sendFail('Failed to create CPR: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return ResponseLib::sendOk($record, 'S_CREATED');
|
|
|
|
|
|
|
+ return ResponseLib::sendOk([
|
|
|
|
|
+ 'cpr' => $record,
|
|
|
|
|
+ 'payment' => [
|
|
|
|
|
+ 'payment_id' => $paymentId,
|
|
|
|
|
+ 'payment_external_id' => $pixData['item_id'],
|
|
|
|
|
+ 'status_id' => $statusId,
|
|
|
|
|
+ ],
|
|
|
|
|
+ 'pix' => [
|
|
|
|
|
+ 'qrcode_url' => $pixData['qrcode_url'],
|
|
|
|
|
+ ]
|
|
|
|
|
+ ], 'S_CREATED');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function generateDynamicQrcode(): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $cliPath = dirname(__DIR__) . '/bin/genial-cli/genial-cli';
|
|
|
|
|
+ if (!is_file($cliPath) || !is_executable($cliPath)) {
|
|
|
|
|
+ throw new \RuntimeException('genial-cli executable not found or not executable');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $amount = self::PIX_VALUE;
|
|
|
|
|
+ $command = sprintf('%s qrcodedynamic %s', escapeshellarg($cliPath), escapeshellarg($amount));
|
|
|
|
|
+ $result = BashExecutor::run($command, 60);
|
|
|
|
|
+
|
|
|
|
|
+ if (($result['exitCode'] ?? 1) !== 0) {
|
|
|
|
|
+ $message = $result['error'] ?: $result['output'] ?: 'Unknown error';
|
|
|
|
|
+ throw new \RuntimeException($message);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $output = $result['output'] ?? '';
|
|
|
|
|
+ $itemId = $this->extractCliValue('itemId', $output);
|
|
|
|
|
+ $qrcodeUrl = $this->extractCliValue('qrcodeURL', $output);
|
|
|
|
|
+
|
|
|
|
|
+ if (!$itemId || !$qrcodeUrl) {
|
|
|
|
|
+ throw new \RuntimeException('Unable to parse itemId or qrcodeURL from genial-cli output');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'item_id' => $itemId,
|
|
|
|
|
+ 'qrcode_url' => $qrcodeUrl,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function extractCliValue(string $key, string $content): ?string
|
|
|
|
|
+ {
|
|
|
|
|
+ $pattern = sprintf('#%s\s*[:=]\s*(?:"([^"]+)"|\' . "'" . '([^\' . "'" . ']+)\' . "'" . '|([^\s,{}]+))#i', preg_quote($key, '#'));
|
|
|
|
|
+ if (preg_match($pattern, $content, $matches)) {
|
|
|
|
|
+ foreach (array_slice($matches, 1) as $match) {
|
|
|
|
|
+ if ($match !== '' && $match !== null) {
|
|
|
|
|
+ return trim($match);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return null;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|