Sfoglia il codice sorgente

feat: discount mechanic for cpr registration

Fernando 1 mese fa
parent
commit
71dd0984e0

+ 61 - 2
controllers/B3CprRegisterController.php

@@ -14,7 +14,7 @@ class B3CprRegisterController
     private StatusModel $statusModel;
     private PaymentService $paymentService;
 
-    private const PAYMENT_VALUE = 100;
+    private const PAYMENT_VALUE = 1000000;
 
     public function __construct()
     {
@@ -52,6 +52,62 @@ class B3CprRegisterController
         return $cpr;
     }
 
+    private function calculatePaymentValue(?string $discountCode): int
+    {
+        $baseValue = self::PAYMENT_VALUE;
+        if ($discountCode === null) {
+            return $baseValue;
+        }
+
+        $normalized = strtoupper(trim($discountCode));
+        $normalized = str_replace('%', '', $normalized);
+
+        $discountPercent = 0;
+        switch ($normalized) {
+            case '00000000 00000000 00000000 01001100 01100101 01101111':
+                $discountPercent = 10;
+                break;
+            case '00000000 01000100 01101001 01101111 01100111 01101111':
+                $discountPercent = 20;
+                break;
+            case '00000000 00000000 00000000 01011010 01100101 01110000':
+                $discountPercent = 30;
+                break;
+            case '00000000 00000000 00000000 01000111 01110101 01110011':
+                $discountPercent = 40;
+                break;
+            case '00000000 01001101 01100101 01101110 01100111 01101111':
+                $discountPercent = 50;
+                break;
+            case '00000000 00000000 00000000 00000000 01000100 01110101':
+                $discountPercent = 60;
+                break;
+            case '01000001 01101100 01110110 01100001 01110010 01101111':
+                $discountPercent = 70;
+                break;
+            case '00000000 00000000 01000010 01101001 01100101 01101100':
+                $discountPercent = 80;
+                break;
+            case '00000000 01000001 01101100 01101100 01100001 01101110':
+                $discountPercent = 90;
+                break;
+            case '00000000 01001100 01110101 01110110 01100001 01110011':
+                $discountPercent = 100;
+                break;
+            default:
+                $discountPercent = 0;
+        }
+
+        if ($discountPercent <= 0) {
+            return $baseValue;
+        }
+
+        $multiplier = max(0, (100 - $discountPercent)) / 100;
+        $discountedValue = (int) round($baseValue * $multiplier);
+
+        return max(0, $discountedValue);
+    }
+
     public function __invoke(ServerRequestInterface $request)
     {
         $timezone = $_ENV['APP_TIMEZONE'] ?? 'America/Sao_Paulo';
@@ -114,8 +170,11 @@ class B3CprRegisterController
             return ResponseLib::sendFail('Pending status not found', [], 'E_DATABASE')->withStatus(500);
         }
 
+        $discountCode = isset($body['discount']) ? (string)$body['discount'] : null;
+        $paymentValue = $this->calculatePaymentValue($discountCode);
+
         try {
-            $paymentData = $this->paymentService->initiatePayment(self::PAYMENT_VALUE);
+            $paymentData = $this->paymentService->initiatePayment($paymentValue);
         } catch (\Throwable $e) {
             return ResponseLib::sendFail('Failed to initiate payment: ' . $e->getMessage(), [], 'E_INTERNAL')->withStatus(500);
         }

+ 9 - 0
controllers/OrderbookFilterController.php

@@ -46,6 +46,8 @@ class OrderbookFilterController
             )->withStatus(500);
         }
 
+        $companyId = (int)($request->getAttribute('api_company_id') ?? 0);
+
         if (!$orders) {
             return ResponseLib::sendOk(
                 [
@@ -57,6 +59,13 @@ class OrderbookFilterController
             );
         }
 
+        $orders = array_map(static function (array $order) use ($companyId) {
+            $orderCompanyId = isset($order['company_id']) ? (int)$order['company_id'] : null;
+            $order['editable'] = $companyId > 0 && $orderCompanyId === $companyId;
+            unset($order['company_id']);
+            return $order;
+        }, $orders);
+
         return ResponseLib::sendOk([
             'state' => $state,
             'commodity_type' => $commodityType,

+ 0 - 192
controllers/RegisterCprController.php

@@ -1,192 +0,0 @@
-<?php
-
-namespace Controllers;
-
-use Libs\BashExecutor;
-use Libs\ResponseLib;
-use Models\CprModel;
-use Models\StatusModel;
-use Psr\Http\Message\ServerRequestInterface;
-use Respect\Validation\Exceptions\ValidationException;
-use Respect\Validation\Validator as val;
-use Services\PaymentService;
-
-class RegisterCprController
-{
-    private CprModel $cprModel;
-    private StatusModel $statusModel;
-    private PaymentService $paymentService;
-
-    private const PIX_VALUE = '1000.00';
-
-    public function __construct()
-    {
-        $this->cprModel = new CprModel();
-        $this->statusModel = new StatusModel();
-        $this->paymentService = new PaymentService();
-    }
-
-    public function __invoke(ServerRequestInterface $request)
-    {
-        $body = json_decode((string)$request->getBody(), true) ?? [];
-
-        try {
-            val::key('cpr_children_codes', val::arrayType()->notEmpty()->each(val::stringType()->notEmpty()))
-                ->assert($body);
-        } catch (ValidationException $e) {
-            return ResponseLib::sendFail(
-                'Validation failed: ' . $e->getFullMessage(),
-                [],
-                'E_VALIDATE'
-            )->withStatus(400);
-        }
-
-        $userId = (int)($request->getAttribute('api_user_id') ?? 0);
-        if ($userId <= 0) {
-            return ResponseLib::sendFail('Authenticated user not found', [], 'E_VALIDATE')->withStatus(401);
-        }
-
-        $companyId = (int)($request->getAttribute('api_company_id') ?? 0);
-        if ($companyId <= 0) {
-            return ResponseLib::sendFail('Authenticated company not found', [], 'E_VALIDATE')->withStatus(401);
-        }
-
-        $statusId = $this->statusModel->getIdByStatus('pending');
-        if ($statusId === null) {
-            return ResponseLib::sendFail('Pending status not found', [], 'E_DATABASE')->withStatus(500);
-        }
-
-        try {
-            $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, $userId, $companyId);
-        } catch (\InvalidArgumentException $e) {
-            return ResponseLib::sendFail($e->getMessage(), [], 'E_VALIDATE')->withStatus(400);
-        } catch (\Throwable $e) {
-            return ResponseLib::sendFail('Failed to create CPR: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
-        }
-
-        return ResponseLib::sendOk([
-            'cpr' => $record,
-            'pix' => [
-                'qrcode_url' => $pixData['qrcode_url'],
-            ]
-        ], 'S_CREATED');
-    }
-
-    private function generateDynamicQrcode(): array
-    {
-        $cliPath = dirname(__DIR__) . '/bin/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) {
-            $this->logCliResult($result, 'genial-cli non-zero exit');
-            $message = $result['error'] ?: $result['output'] ?: 'Unknown error';
-            throw new \RuntimeException($message);
-        }
-
-        $output = $result['output'] ?? '';
-
-        try {
-            $parsed = $this->decodeCliOutput($output);
-        } catch (\Throwable $e) {
-            $this->logCliResult($result, 'genial-cli parse failure');
-            throw $e;
-        }
-
-        $items = $parsed['data']['items'] ?? null;
-        if (!is_array($items) || empty($items) || !is_array($items[0])) {
-            throw new \RuntimeException('genial-cli output is missing items array');
-        }
-
-        $firstItem = $items[0];
-        $itemId = $firstItem['itemId'] ?? null;
-        $qrcodeUrl = $firstItem['data']['qrcodeURL'] ?? null;
-
-        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 decodeCliOutput(string $content): array
-    {
-        $clean = trim($content);
-        if ($clean === '') {
-            throw new \RuntimeException('genial-cli returned empty output');
-        }
-
-        $decoded = json_decode($clean, true);
-        if (json_last_error() === JSON_ERROR_NONE) {
-            return $decoded;
-        }
-
-        $normalized = $this->normalizeCliOutput($clean);
-        $decoded = json_decode($normalized, true);
-        if (json_last_error() !== JSON_ERROR_NONE) {
-            throw new \RuntimeException('Failed to decode genial-cli output: ' . json_last_error_msg());
-        }
-
-        return $decoded;
-    }
-
-    private function normalizeCliOutput(string $content): string
-    {
-        // Strip ANSI escape codes, just in case
-        $normalized = preg_replace('/\e\[[\d;]*m/', '', $content);
-
-        // Convert single-quoted strings to JSON-compatible double-quoted ones
-        $normalized = preg_replace_callback(
-            "/'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'/",
-            static function (array $matches): string {
-                $inner = str_replace(['\\', '"'], ['\\\\', '\\"'], $matches[1]);
-                return '"' . $inner . '"';
-            },
-            $normalized
-        );
-
-        // Quote object keys so json_decode can understand them
-        $normalized = preg_replace(
-            '/(?<=\{|\[|,|\n)\s*([A-Za-z_][A-Za-z0-9_]*)\s*:/',
-            '"$1":',
-            $normalized
-        );
-
-        return $normalized;
-    }
-
-    private function logCliResult(array $result, string $context): void
-    {
-        $exitCode = $result['exitCode'] ?? 'null';
-        $stdout = trim($result['output'] ?? '');
-        $stderr = trim($result['error'] ?? '');
-
-        error_log(sprintf(
-            '[RegisterCprController] %s | exitCode: %s | stdout: %s | stderr: %s',
-            $context,
-            (string)$exitCode,
-            $stdout === '' ? '<empty>' : $stdout,
-            $stderr === '' ? '<empty>' : $stderr
-        ));
-    }
-}