gdias 1 mese fa
parent
commit
dad5df5278

+ 20 - 43
controllers/B3CprRegisterController.php

@@ -5,12 +5,14 @@ namespace Controllers;
 use Libs\ResponseLib;
 use Psr\Http\Message\ServerRequestInterface;
 use Models\CprModel;
+use Models\DiscountModel;
 use Models\StatusModel;
 use Services\PaymentService;
 
 class B3CprRegisterController
 {
     private CprModel $cprModel;
+    private DiscountModel $discountModel;
     private StatusModel $statusModel;
     private PaymentService $paymentService;
 
@@ -19,6 +21,7 @@ class B3CprRegisterController
     public function __construct()
     {
         $this->cprModel = new CprModel();
+        $this->discountModel = new DiscountModel();
         $this->statusModel = new StatusModel();
         $this->paymentService = new PaymentService();
     }
@@ -59,53 +62,27 @@ class B3CprRegisterController
             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) {
+        $normalized = trim($discountCode);
+        if ($normalized === '') {
             return $baseValue;
         }
 
-        $multiplier = max(0, (100 - $discountPercent)) / 100;
-        $discountedValue = (int) round($baseValue * $multiplier);
+        try {
+            $row = $this->discountModel->findByCode($normalized);
+        } catch (\Throwable $e) {
+            return $baseValue;
+        }
+
+        if (!$row) {
+            return $baseValue;
+        }
+
+        $value = (int)($row['discount_value'] ?? 0);
+        if ($value <= 0) {
+            return $baseValue;
+        }
 
-        return max(0, $discountedValue);
+        return $value;
     }
 
     public function __invoke(ServerRequestInterface $request)

+ 57 - 0
controllers/DiscountCreateController.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace Controllers;
+
+use Libs\ResponseLib;
+use Models\DiscountModel;
+use Psr\Http\Message\ServerRequestInterface;
+use Respect\Validation\Exceptions\ValidationException;
+use Respect\Validation\Validator as val;
+
+class DiscountCreateController
+{
+    private DiscountModel $model;
+
+    public function __construct()
+    {
+        $this->model = new DiscountModel();
+    }
+
+    public function __invoke(ServerRequestInterface $request)
+    {
+        $body = json_decode((string)$request->getBody(), true) ?? [];
+
+        try {
+            val::key('discount_value', val::intType()->positive())
+                ->key('discount_code', val::stringType()->notEmpty()->length(1, 255))
+                ->assert($body);
+        } catch (ValidationException $e) {
+            return ResponseLib::sendFail('Validation failed: ' . $e->getFullMessage(), [], 'E_VALIDATE')->withStatus(400);
+        }
+
+        $discountValue = (int)$body['discount_value'];
+        $discountCode = trim((string)$body['discount_code']);
+
+        if ($discountCode === '') {
+            return ResponseLib::sendFail('Validation failed: discount_code must not be empty', [], 'E_VALIDATE')->withStatus(400);
+        }
+
+        $discountValue = $discountValue * 100;
+        if ($discountValue <= 0) {
+            return ResponseLib::sendFail('Validation failed: discount_value must be greater than zero', [], 'E_VALIDATE')->withStatus(400);
+        }
+
+        try {
+            $created = $this->model->create($discountValue, $discountCode);
+        } catch (\PDOException $e) {
+            if (($e->getCode() ?? '') === '23505') {
+                return ResponseLib::sendFail('Discount code already exists', [], 'E_DUPLICATE')->withStatus(409);
+            }
+            return ResponseLib::sendFail('Failed to create discount: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
+        } catch (\Throwable $e) {
+            return ResponseLib::sendFail('Failed to create discount: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
+        }
+
+        return ResponseLib::sendOk($created, 'S_CREATED');
+    }
+}

+ 43 - 0
controllers/DiscountDeleteController.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Controllers;
+
+use Libs\ResponseLib;
+use Models\DiscountModel;
+use Psr\Http\Message\ServerRequestInterface;
+use Respect\Validation\Exceptions\ValidationException;
+use Respect\Validation\Validator as val;
+
+class DiscountDeleteController
+{
+    private DiscountModel $model;
+
+    public function __construct()
+    {
+        $this->model = new DiscountModel();
+    }
+
+    public function __invoke(ServerRequestInterface $request)
+    {
+        $body = json_decode((string)$request->getBody(), true) ?? [];
+
+        try {
+            val::key('discount_id', val::intType()->positive())
+                ->assert($body);
+        } catch (ValidationException $e) {
+            return ResponseLib::sendFail('Validation failed: ' . $e->getFullMessage(), [], 'E_VALIDATE')->withStatus(400);
+        }
+
+        $discountId = (int)$body['discount_id'];
+
+        try {
+            $deleted = $this->model->delete($discountId);
+        } catch (\Throwable $e) {
+            return ResponseLib::sendFail('Failed to delete discount: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
+        }
+
+        return $deleted
+            ? ResponseLib::sendOk(['deleted' => true], 'S_DELETED')
+            : ResponseLib::sendFail('Discount Not Found', [], 'E_DATABASE')->withStatus(204);
+    }
+}

+ 32 - 0
controllers/DiscountGetController.php

@@ -0,0 +1,32 @@
+<?php
+
+namespace Controllers;
+
+use Libs\ResponseLib;
+use Models\DiscountModel;
+use Psr\Http\Message\ServerRequestInterface;
+
+class DiscountGetController
+{
+    private DiscountModel $model;
+
+    public function __construct()
+    {
+        $this->model = new DiscountModel();
+    }
+
+    public function __invoke(ServerRequestInterface $request)
+    {
+        try {
+            $rows = $this->model->getAll();
+        } catch (\Throwable $e) {
+            return ResponseLib::sendFail('Failed to fetch discounts: ' . $e->getMessage(), [], 'E_DATABASE')->withStatus(500);
+        }
+
+        if (!$rows) {
+            return ResponseLib::sendFail('Discounts Not Found', [], 'E_DATABASE')->withStatus(204);
+        }
+
+        return ResponseLib::sendOk($rows, 'S_DISCOUNTS');
+    }
+}

+ 24 - 0
controllers/SuperAdminGetController.php

@@ -0,0 +1,24 @@
+<?php
+
+namespace Controllers;
+
+use Libs\ResponseLib;
+use Psr\Http\Message\ServerRequestInterface;
+
+class SuperAdminGetController
+{
+    public function __invoke(ServerRequestInterface $request)
+    {
+        $companyId = (int)($request->getAttribute('api_company_id') ?? 0);
+        if ($companyId <= 0) {
+            return ResponseLib::sendFail('Authenticated company not found', [], 'E_VALIDATE')->withStatus(401);
+        }
+
+        $isSuperAdmin = ($companyId === 1 || $companyId === 2);
+
+        return ResponseLib::sendOk([
+            'superadmin' => $isSuperAdmin,
+            'company_id' => $companyId,
+        ], 'S_SUPERADMIN');
+    }
+}

+ 28 - 0
migrations/20260207_add_discount_table.sql

@@ -0,0 +1,28 @@
+BEGIN;
+
+CREATE TABLE IF NOT EXISTS "discount" (
+  "discount_id" SERIAL PRIMARY KEY,
+  "discount_value" INTEGER NOT NULL,
+  "discount_code" TEXT NOT NULL UNIQUE
+);
+
+INSERT INTO "discount" (discount_value, discount_code)
+VALUES
+  (900000, 'A7K2M'),
+  (800000, 'Z19QX8'),
+  (700000, 'N4T8B3W'),
+  (600000, 'P6R1D9L0'),
+  (500000, 'H2V9C'),
+  (400000, 'M8J3S7Q'),
+  (300000, 'X5A0N2K9'),
+  (200000, 'B7F4T1'),
+  (100000, 'Q3W9E1R8T')
+ON CONFLICT (discount_code) DO UPDATE
+SET discount_value = EXCLUDED.discount_value;
+
+SELECT setval(
+  pg_get_serial_sequence('"discount"', 'discount_id'),
+  GREATEST((SELECT COALESCE(MAX(discount_id), 0) FROM "discount"), 1)
+);
+
+COMMIT;

+ 55 - 0
models/DiscountModel.php

@@ -0,0 +1,55 @@
+<?php
+
+namespace Models;
+
+class DiscountModel
+{
+    private \PDO $pdo;
+
+    public function __construct()
+    {
+        if (isset($GLOBALS['pdo']) && $GLOBALS['pdo'] instanceof \PDO) {
+            $this->pdo = $GLOBALS['pdo'];
+            return;
+        }
+
+        throw new \RuntimeException('Global PDO connection not initialized');
+    }
+
+    public function getAll(): array
+    {
+        $stmt = $this->pdo->query('SELECT discount_id, discount_value, discount_code FROM "discount" ORDER BY discount_id');
+        return $stmt->fetchAll(\PDO::FETCH_ASSOC);
+    }
+
+    public function findByCode(string $code): ?array
+    {
+        $stmt = $this->pdo->prepare('SELECT discount_id, discount_value, discount_code FROM "discount" WHERE discount_code = :code LIMIT 1');
+        $stmt->execute(['code' => $code]);
+        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+        return $row ?: null;
+    }
+
+    public function create(int $discountValue, string $discountCode): array
+    {
+        $stmt = $this->pdo->prepare('INSERT INTO "discount" (discount_value, discount_code) VALUES (:value, :code) RETURNING discount_id');
+        $stmt->execute([
+            'value' => $discountValue,
+            'code' => $discountCode,
+        ]);
+        $id = (int)$stmt->fetchColumn();
+
+        return [
+            'discount_id' => $id,
+            'discount_value' => $discountValue,
+            'discount_code' => $discountCode,
+        ];
+    }
+
+    public function delete(int $discountId): bool
+    {
+        $stmt = $this->pdo->prepare('DELETE FROM "discount" WHERE discount_id = :id');
+        $stmt->execute(['id' => $discountId]);
+        return $stmt->rowCount() > 0;
+    }
+}

+ 17 - 1
public/index.php

@@ -3,8 +3,10 @@
 require __DIR__ . '/../vendor/autoload.php';
 
 use FrameworkX\App;
+use Libs\ResponseLib;
 use Middlewares\CorsMiddleware;
 use Middlewares\JwtAuthMiddleware;
+use Psr\Http\Message\ServerRequestInterface;
 
 $requestUri = $_SERVER['REQUEST_URI'] ?? null;
 $path = $requestUri !== null ? parse_url($requestUri, PHP_URL_PATH) : '/';
@@ -40,10 +42,20 @@ $globalMiddleware = $corsEnabled ? [CorsMiddleware::class] : [];
 $app = new App(...$globalMiddleware);
 $authJwt = new JwtAuthMiddleware();
 
+$onlyCompany1Or2 = function (ServerRequestInterface $request, callable $next) {
+    $companyId = (int)($request->getAttribute('api_company_id') ?? 0);
+    if ($companyId !== 1 && $companyId !== 2) {
+        return ResponseLib::sendFail('Forbidden', [], 'E_FORBIDDEN')->withStatus(403);
+    }
+
+    return $next($request);
+};
+
 $app->post('/verify/jwt', $authJwt,\Controllers\HelloController::class);
 
 $app->post('/login', \Controllers\LoginController::class);
 $app->post('/register', $authJwt, \Controllers\RegisterController::class);
+$app->post('/auth/superadmin', $authJwt, \Controllers\SuperAdminGetController::class);
 $app->post('/user/get', $authJwt, \Controllers\UserGetController::class);
 $app->post('/user/info', $authJwt, \Controllers\UserInfoController::class);
 $app->post('/user/delete', $authJwt, \Controllers\UserDeleteController::class);
@@ -79,8 +91,12 @@ $app->post('/orderbook/cancel', $authJwt, \Controllers\OrderbookUpdateStatusCont
 $app->post('/orderbook/transfer', $authJwt, \Controllers\OrderbookTransferController::class);
 $app->post('/harvest/list', $authJwt, \Controllers\HarvestListController::class);
 
+$app->post('/discount/get', $authJwt, $onlyCompany1Or2, \Controllers\DiscountGetController::class);
+$app->post('/discount/create', $authJwt, $onlyCompany1Or2, \Controllers\DiscountCreateController::class);
+$app->post('/discount/delete', $authJwt, $onlyCompany1Or2, \Controllers\DiscountDeleteController::class);
+
 $app->post('/b3/token', \Controllers\B3TokenController::class);
-$app->post('/b3/cpr/register', $authJwt, \Controllers\B3CprRegisterController::class);
+$app->post('/b3/cpr/register', $authJwt, $onlyCompany1Or2, \Controllers\B3CprRegisterController::class);
 $app->post('/b3/payment/confirm', $authJwt, \Controllers\PaymentConfirmController::class);
 $app->post('/cpr/fast-track', \Controllers\CprFastTrackController::class);