From c374e46834566b8c61d0a120bf07f70037bc1625 Mon Sep 17 00:00:00 2001 From: JiaSheng Date: Wed, 13 Sep 2023 22:03:32 +0800 Subject: [PATCH 1/2] add functionality to get transactions from production when creating statement transactions owner --- .../General/Eloquent/Filters/AmountExceed.php | 19 ++++++ .../General/Eloquent/Filters/AmountShort.php | 19 ++++++ .../Eloquent/Filters/CreatedAfterOrEqual.php | 21 ++++++ .../Eloquent/Filters/CreatedBeforeOrEqual.php | 20 ++++++ ...ankStatementTransactionOwnersProcessor.php | 68 ++++++++++++++----- .../ListMappableTransactionsLogic.php | 49 +++++++++++++ .../ListMappableTransactionsController.php | 20 ++++++ app/Http/Kernel.php | 7 +- .../Middleware/TokenCheckerMiddleware.php | 56 +++++++++++++++ .../Resources/MappableTransactionResource.php | 37 ++++++++++ app/Models/PersonalAccessTokens.php | 9 +++ app/Providers/RouteServiceProvider.php | 17 +++++ ...41_create_personal_access_tokens_table.php | 36 ++++++++++ routes/apipub.php | 9 +++ 14 files changed, 370 insertions(+), 17 deletions(-) create mode 100644 app/Classes/General/Eloquent/Filters/AmountExceed.php create mode 100644 app/Classes/General/Eloquent/Filters/AmountShort.php create mode 100644 app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php create mode 100644 app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php create mode 100644 app/Classes/Modules/Transactions/ControllersLogic/ListMappableTransactionsLogic.php create mode 100644 app/Http/Controllers/Transactions/ListMappableTransactionsController.php create mode 100644 app/Http/Middleware/TokenCheckerMiddleware.php create mode 100644 app/Http/Resources/MappableTransactionResource.php create mode 100644 app/Models/PersonalAccessTokens.php create mode 100644 database/migrations/2023_09_13_161941_create_personal_access_tokens_table.php create mode 100644 routes/apipub.php diff --git a/app/Classes/General/Eloquent/Filters/AmountExceed.php b/app/Classes/General/Eloquent/Filters/AmountExceed.php new file mode 100644 index 00000000..a3e353fa --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/AmountExceed.php @@ -0,0 +1,19 @@ +where('amount', '>', $value); + } +} diff --git a/app/Classes/General/Eloquent/Filters/AmountShort.php b/app/Classes/General/Eloquent/Filters/AmountShort.php new file mode 100644 index 00000000..7406fc47 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/AmountShort.php @@ -0,0 +1,19 @@ +where('amount', '<', $value); + } +} diff --git a/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php b/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php new file mode 100644 index 00000000..7e563aee --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php @@ -0,0 +1,21 @@ +where('created_at', '>=', Carbon::parse($value)); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php b/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php new file mode 100644 index 00000000..ed97b48f --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php @@ -0,0 +1,20 @@ +where('created_at', '<=', Carbon::parse($value)); + } +} diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index 90dd7048..bcd430b1 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -13,6 +13,8 @@ use App\Models\StatementTransaction; use App\Models\Transaction; use App\Models\Wallet; use Carbon\Carbon; +use Illuminate\Support\Arr; +use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\Log; class CreateBankStatementTransactionOwnersProcessor @@ -190,25 +192,59 @@ class CreateBankStatementTransactionOwnersProcessor } private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $model = Transaction::class) { - $query = $model::whereIn('status', $statuses) - ->where(function ($query) use ($ownerType, $paymentMethod, $type) { - if ($ownerType) { - $query->where('owner_type', $ownerType); - } + if (App::environment(['production'])) { + $query = $model::whereIn('status', $statuses) + ->where(function ($query) use ($ownerType, $paymentMethod, $type) { + if ($ownerType) { + $query->where('owner_type', $ownerType); + } - if ($paymentMethod) { - $query->where('payment_method', '!=', $paymentMethod); - } + if ($paymentMethod) { + $query->where('payment_method', '!=', $paymentMethod); + } - if ($type) { - $query->where('type', $type); - } - }) - ->whereDate('created_at', $date->format('Y-m-d')) - ->where('amount', '>', ($amount - 0.01)) - ->where('amount', '<', ($amount + 0.01)); + if ($type) { + $query->where('type', $type); + } + }) + ->whereDate('created_at', $date->format('Y-m-d')) + ->where('amount', '>', ($amount - 0.01)) + ->where('amount', '<', ($amount + 0.01)); - return $query->get(); + return $query->get(); + } else { + $dateRange = $this->getDateRange($date); + $result = $this->getTransactionsFromExchange($amount, $dateRange, $type, $ownerType, $paymentMethod); + $transactionsId = Arr::pluck($result, 'owner_id'); + $query = $model::whereIn('id', $transactionsId); + + return $query->get(); + } + } + + private function getTransactionsFromExchange($amount, $dateRange, $type, $ownerType, $paymentMethod){ + $url = 'https://exchange.cief-malaysia.com/public/api/v1/transactions/mappable/query'; + return $this->getFromExchange($url, $amount, $dateRange, $type, $ownerType, $paymentMethod); + } + + private function getFromExchange($url, $amount, $dateRange, $type, $ownerType, $paymentMethod){ + $paymentMethodFilter = ""; + if ($paymentMethod) { + $paymentMethodFilter = ',"payment_method_not_in":['.$paymentMethod.']'; + } + $ownerType = addslashes($ownerType); + try{ + $client = new \GuzzleHttp\Client(['verify' => false]); + $response = $client->request('GET', $url.'?api-key=abc&filters={"order_by":{"column":"id","DESC":true},"status_in":[2,3],"owner_type":"'. $ownerType . '"' . $paymentMethodFilter.',"type":'.$type.',"created_after_or_equal":"'.$dateRange['start_date'].'","created_before_or_equal":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).'}'); + $body = $response->getBody(); + $data = json_decode($body, true); + $payload = $data['payload']; + $transactions2 = $payload['data']; + return $transactions2; + }catch(\Exception $exception){ + Log::error($exception); + return []; + } } private function getTransactionsFromShippingPortal($amount, $dateRange, $type){ diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ListMappableTransactionsLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ListMappableTransactionsLogic.php new file mode 100644 index 00000000..fe2e7909 --- /dev/null +++ b/app/Classes/Modules/Transactions/ControllersLogic/ListMappableTransactionsLogic.php @@ -0,0 +1,49 @@ + 'Retrieved Transactions', + 'message' => 'You have successfully retrieved a list of transactions' + ]; + } + + + /** @var ListsTransactions */ + private $listsTransactions; + + /** + * ListTransactionsLogic constructor. + * @param ListsTransactions $listsTransactions + */ + public function __construct(ListsTransactions $listsTransactions) + { + $this->listsTransactions = $listsTransactions; + } + + + + public function logic(Request $request) : JsonResponse + { + $query = $this->listsTransactions->execute($this->listsTransactions->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse(MappableTransactionResource::collection($query)); + } + + + +} diff --git a/app/Http/Controllers/Transactions/ListMappableTransactionsController.php b/app/Http/Controllers/Transactions/ListMappableTransactionsController.php new file mode 100644 index 00000000..abf83758 --- /dev/null +++ b/app/Http/Controllers/Transactions/ListMappableTransactionsController.php @@ -0,0 +1,20 @@ +execute($request); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 172d428b..93731db4 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -51,6 +51,10 @@ class Kernel extends HttpKernel 'throttle:300,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], + + 'apipub' => [ + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], ]; /** @@ -71,6 +75,7 @@ class Kernel extends HttpKernel 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, - 'valid.token' => ValidateToken::class + 'valid.token' => ValidateToken::class, + 'token.check' => \App\Http\Middleware\TokenCheckerMiddleware::class, ]; } diff --git a/app/Http/Middleware/TokenCheckerMiddleware.php b/app/Http/Middleware/TokenCheckerMiddleware.php new file mode 100644 index 00000000..480ea348 --- /dev/null +++ b/app/Http/Middleware/TokenCheckerMiddleware.php @@ -0,0 +1,56 @@ +query('api-key')) { + return response()->json(['message' => 'Invalid API key.'], 401); + } + + // Check if the api_key is valid + $apiKey = $request->query('api-key'); + $personalAccessToken = PersonalAccessTokens::where('token', $apiKey)->first(); + + if (!$personalAccessToken) { + return response()->json(['error' => 'Unauthorized'], 401); + } + return $next($request); + + //Method 2: Token pass via request header + /* + $authHeader = $request->header('Authorization'); + if (preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) { + $token = $matches[1]; + // validate the token here + + $personalAccessToken = PersonalAccessToken::where('token', $token)->first(); + + if (!$personalAccessToken) { + return response()->json(['error' => 'Unauthorized'], 401); + } + + + // if the token is valid, you can attach it to the request + $request->attributes->add(['bearerToken' => $token]); + return $next($request); + } + return response()->json(['error' => 'Unauthorized'], 401); + */ + } +} diff --git a/app/Http/Resources/MappableTransactionResource.php b/app/Http/Resources/MappableTransactionResource.php new file mode 100644 index 00000000..22104839 --- /dev/null +++ b/app/Http/Resources/MappableTransactionResource.php @@ -0,0 +1,37 @@ +type === TransactionType::TOP_UP) { + $reference = $this->owner->owner->reference; + } + + if($this->type === TransactionType::PAYMENT && $this->owner !== Wallet::class){ + $reference = $this->owner->marking; + } + + return [ + 'status' => 'success', + 'system' => 'EXCHANGE', + 'type' => $this->type, + 'owner_type' => $this->owner_type, + 'owner_id'=> $this->id, + 'owner_reference'=> $reference, + ]; + } +} diff --git a/app/Models/PersonalAccessTokens.php b/app/Models/PersonalAccessTokens.php new file mode 100644 index 00000000..5efc331d --- /dev/null +++ b/app/Models/PersonalAccessTokens.php @@ -0,0 +1,9 @@ +mapWebRoutes(); + $this->mapApiPubRoutes(); + // } @@ -77,4 +79,19 @@ class RouteServiceProvider extends ServiceProvider ->namespace($this->namespace) ->group(base_path('routes/api.php')); } + + /** + * Define the "apipub" routes for the application. + * + * These routes are typically stateless. + * + * @return void + */ + protected function mapApiPubRoutes() + { + Route::prefix('public/api') + ->middleware('apipub') + ->namespace($this->namespace) + ->group(base_path('routes/apipub.php')); + } } diff --git a/database/migrations/2023_09_13_161941_create_personal_access_tokens_table.php b/database/migrations/2023_09_13_161941_create_personal_access_tokens_table.php new file mode 100644 index 00000000..691a4bf8 --- /dev/null +++ b/database/migrations/2023_09_13_161941_create_personal_access_tokens_table.php @@ -0,0 +1,36 @@ +bigIncrements('id'); + // $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('personal_access_tokens'); + } +} diff --git a/routes/apipub.php b/routes/apipub.php new file mode 100644 index 00000000..b2a5e2ce --- /dev/null +++ b/routes/apipub.php @@ -0,0 +1,9 @@ + 'apipub', 'prefix' => 'v1', 'as' => 'apipub.'], function () { + Route::group(['middleware' => 'token.check'], function () { + Route::get('transactions/mappable/query', 'Transactions\ListMappableTransactionsController@list')->name('transaction.mappable.list'); + }); +}); From a8a22ca1c3aae51500dd6a8066d05b73cbaa0c4a Mon Sep 17 00:00:00 2001 From: JiaSheng Date: Thu, 14 Sep 2023 15:01:30 +0800 Subject: [PATCH 2/2] fix error when getting transaction from shipping portal due to mistake in filters string --- ...ankStatementTransactionOwnersProcessor.php | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index bcd430b1..0ba5646f 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -49,7 +49,7 @@ class CreateBankStatementTransactionOwnersProcessor // Shipping Portal Sales - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date), 2); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date), 2, PaymentMethodType::WALLET); foreach ($creditTransactions as $creditTransaction) { if($creditTransaction['owner_type'] === Wallet::class) continue; $transaction->owners()->firstOrCreate([ @@ -73,7 +73,7 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date), 5); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date), 5, null); foreach ($creditTransactions as $creditTransaction) { $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, @@ -247,21 +247,25 @@ class CreateBankStatementTransactionOwnersProcessor } } - private function getTransactionsFromShippingPortal($amount, $dateRange, $type){ + private function getTransactionsFromShippingPortal($amount, $dateRange, $type, $paymentMethod){ $url = 'https://izyim.cief-malaysia.com/public/api/v1/transactions/mappable/query'; - return $this->getFromShippingPortal($amount, $dateRange, $url, $type); + return $this->getFromShippingPortal($amount, $dateRange, $url, $type, $paymentMethod); } - private function getGroupsFromShippingPortal($amount, $dateRange, $type){ + private function getGroupsFromShippingPortal($amount, $dateRange, $type, $paymentMethod){ $url = 'https://izyim.cief-malaysia.com/public/api/v1/groups/query'; - return $this->getFromShippingPortal($amount, $dateRange, $url, $type); + return $this->getFromShippingPortal($amount, $dateRange, $url, $type, $paymentMethod); } - private function getFromShippingPortal($amount, $dateRange, $url, $type){ + private function getFromShippingPortal($amount, $dateRange, $url, $type, $paymentMethod){ + $paymentMethodFilter = ""; + if ($paymentMethod) { + $paymentMethodFilter = ',"payment_method_not_in":['.$paymentMethod.']'; + } try{ $client = new \GuzzleHttp\Client(['verify' => false]); - $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2],"type":2,"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in:"['.$type.']}'); + $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":['.$type.']}'); $body = $response->getBody(); $data = json_decode($body, true); $payload = $data['payload'];