diff --git a/VERSION.txt b/VERSION.txt index 3494ba2930..6561a1f63f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.12.10 \ No newline at end of file +5.12.11 \ No newline at end of file diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 93cbfa986c..92584017b5 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -85,10 +85,10 @@ class Kernel extends ConsoleKernel // Run for 26 hours starting from UTC 10:00 on last day of month // This covers the transition period when timezones move to next month - if ($now->isLastOfMonth()) { + if ($now->isSameDay($now->copy()->endOfMonth())) { // Start at UTC 10:00 (when UTC+14 moves to next day) return $hour >= 10; - } elseif ($now->isFirstOfMonth()) { + } elseif ($now->isSameDay($now->copy()->startOfMonth())) { // Continue until UTC 12:00 (when UTC-12 moves to next day) return $hour <= 12; } diff --git a/app/Helpers/Bank/Nordigen/Http/Client.php b/app/Helpers/Bank/Nordigen/Http/NordigenClient.php similarity index 92% rename from app/Helpers/Bank/Nordigen/Http/Client.php rename to app/Helpers/Bank/Nordigen/Http/NordigenClient.php index df51cb660e..075dd9a4be 100644 --- a/app/Helpers/Bank/Nordigen/Http/Client.php +++ b/app/Helpers/Bank/Nordigen/Http/NordigenClient.php @@ -8,15 +8,14 @@ use Illuminate\Support\Collection; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; -class Client +class NordigenClient { - private string $baseUrl; - private string $accessToken; + private string $baseUrl = 'https://bankaccountdata.gocardless.com/api/v2'; + private PendingRequest $httpClient; - public function __construct(string $baseUrl, string $accessToken) + public function __construct(private string $accessToken) { - $this->baseUrl = rtrim($baseUrl, '/'); $this->accessToken = $accessToken; $this->httpClient = Http::withHeaders([ 'Authorization' => "Bearer {$this->accessToken}", @@ -39,7 +38,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/requisitions/", $params); - return $this->handlePaginatedResponse($response, 'requisitions'); + return $this->handlePaginatedResponse($response); } /** @@ -94,6 +93,7 @@ class Client do { $requisitions = $this->getRequisitions($limit, $offset); + nlog($requisitions); if ($requisitions->isEmpty()) { break; } @@ -122,7 +122,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/agreements/", $params); - return $this->handlePaginatedResponse($response, 'agreements'); + return $this->handlePaginatedResponse($response); } /** @@ -198,14 +198,11 @@ class Client */ public function getInstitutions(int $limit = 100, ?string $offset = null): Collection { - $params = ['limit' => $limit]; - if ($offset) { - $params['offset'] = $offset; - } + $params = []; $response = $this->httpClient->get("{$this->baseUrl}/institutions/", $params); - return $this->handlePaginatedResponse($response, 'institutions'); + return $this->handlePaginatedResponse($response); } /** @@ -230,7 +227,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/institutions/", $params); - return $this->handlePaginatedResponse($response, 'institutions'); + return $this->handlePaginatedResponse($response); } /** @@ -273,7 +270,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/enduser-agreements/", $params); - return $this->handlePaginatedResponse($response, 'enduser_agreements'); + return $this->handlePaginatedResponse($response); } /** @@ -330,7 +327,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/accounts/", $params); - return $this->handlePaginatedResponse($response, 'accounts'); + return $this->handlePaginatedResponse($response); } /** @@ -447,7 +444,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/accounts/{$accountId}/transactions/", $params); - return $this->handlePaginatedResponse($response, 'transactions'); + return $this->handlePaginatedResponse($response); } /** @@ -475,7 +472,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/transactions/", $params); - return $this->handlePaginatedResponse($response, 'transactions'); + return $this->handlePaginatedResponse($response); } /** @@ -527,7 +524,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/accounts/{$accountId}/transactions/", $params); - return $this->handlePaginatedResponse($response, 'transactions'); + return $this->handlePaginatedResponse($response); } /** @@ -550,7 +547,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/accounts/{$accountId}/transactions/", $params); - return $this->handlePaginatedResponse($response, 'transactions'); + return $this->handlePaginatedResponse($response); } /** @@ -573,7 +570,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/accounts/{$accountId}/transactions/", $params); - return $this->handlePaginatedResponse($response, 'transactions'); + return $this->handlePaginatedResponse($response); } /** @@ -598,7 +595,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/accounts/{$accountId}/transactions/", $params); - return $this->handlePaginatedResponse($response, 'transactions'); + return $this->handlePaginatedResponse($response); } // ==================== PAYMENTS ==================== @@ -615,7 +612,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/payments/", $params); - return $this->handlePaginatedResponse($response, 'payments'); + return $this->handlePaginatedResponse($response); } /** @@ -672,7 +669,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/mandates/", $params); - return $this->handlePaginatedResponse($response, 'mandates'); + return $this->handlePaginatedResponse($response); } /** @@ -729,7 +726,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/refunds/", $params); - return $this->handlePaginatedResponse($response, 'refunds'); + return $this->handlePaginatedResponse($response); } /** @@ -766,7 +763,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/events/", $params); - return $this->handlePaginatedResponse($response, 'events'); + return $this->handlePaginatedResponse($response); } /** @@ -793,7 +790,7 @@ class Client $response = $this->httpClient->get("{$this->baseUrl}/webhooks/", $params); - return $this->handlePaginatedResponse($response, 'webhooks'); + return $this->handlePaginatedResponse($response); } /** @@ -841,20 +838,16 @@ class Client /** * Handle paginated response */ - private function handlePaginatedResponse(Response $response, string $dataKey): Collection + private function handlePaginatedResponse(Response $response): Collection { if (!$response->successful()) { $this->logError('Paginated request failed', $response); return collect(); } - $data = $response->json(); - - if (!isset($data[$dataKey])) { - return collect(); - } - - return collect($data[$dataKey]); + $data = $response->json()['results']; + + return collect($data); } /** @@ -875,7 +868,8 @@ class Client */ private function logError(string $message, Response $response): void { - Log::error($message, [ + nlog([ + 'message' => $message, 'status' => $response->status(), 'body' => $response->body(), 'headers' => $response->headers() diff --git a/app/Helpers/Bank/Nordigen/Nordigen.php b/app/Helpers/Bank/Nordigen/Nordigen.php index 4f185b0c43..1dfb02a83f 100644 --- a/app/Helpers/Bank/Nordigen/Nordigen.php +++ b/app/Helpers/Bank/Nordigen/Nordigen.php @@ -177,6 +177,21 @@ class Nordigen ); } + + public function validAgreement($institution_id, $_accounts) + { + + $nc = new \App\Helpers\Bank\Nordigen\Http\NordigenClient($this->client->getAccessToken()); + $requisitions = $nc->getAllRequisitions(); + + $requisitions->filter(function($requisition) use ($institution_id, $_accounts){ + if($requisition['institution_id'] == $institution_id && !empty(array_intersect($requisition['accounts'], $_accounts))){ + return $requisition; + } + }); + + } + public function getRequisition(string $requisitionId) { try { @@ -196,11 +211,30 @@ class Nordigen try { $out = new \stdClass(); - $out->data = $this->client->account($account_id)->getAccountDetails()['account']; $out->metadata = $this->client->account($account_id)->getAccountMetaData(); - $out->balances = $this->client->account($account_id)->getAccountBalances()['balances']; $out->institution = $this->client->institution->getInstitution($out->metadata['institution_id']); + if($out->metadata['status'] == 'READY'){ + $out->data = $this->client->account($account_id)->getAccountDetails()['account']; + $out->balances = $this->client->account($account_id)->getAccountBalances()['balances']; + } + else{ + + $out->data = [ + 'iban' => $out->metadata['iban'], + 'ownerName' => $out->metadata['owner_name'], + ]; + $out->balances = [ + [ + 'balanceType' => '', + 'balanceAmount' => [ + 'amount' => 0, + 'currency' => '', + ], + ], + ]; + } + $it = new AccountTransformer(); return $it->transform($out); diff --git a/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php b/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php index f06279a9f7..d8b8227a90 100644 --- a/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php +++ b/app/Helpers/Bank/Nordigen/Transformer/TransactionTransformer.php @@ -139,7 +139,7 @@ class TransactionTransformer implements BankRevenueInterface (array_key_exists('creditorName', $transaction) ? $transaction['creditorName'] : null); - return [ + $data = [ 'transaction_id' => 0, 'nordigen_transaction_id' => $transactionId, 'amount' => abs($amount), @@ -153,8 +153,16 @@ class TransactionTransformer implements BankRevenueInterface 'base_type' => $base_type, ]; + // $data['currency_code'] = $this->makeHash($data); + + return $data; } + // private function makeHash($data) + // { + // return hash('sha1', $data['amount'].$data['date'].$data['description'].$data['participant'].$data['participant_name'].$data['base_type']); + // } + private function convertCurrency(string $code) { diff --git a/app/Http/Controllers/Bank/NordigenV2Controller.php b/app/Http/Controllers/Bank/NordigenV2Controller.php deleted file mode 100644 index eaf11d117f..0000000000 --- a/app/Http/Controllers/Bank/NordigenV2Controller.php +++ /dev/null @@ -1,63 +0,0 @@ -json(['message' => 'Not yet authenticated with Nordigen Bank Integration service'], 400); - } - - $nordigen = new Nordigen(); - - return response()->json($nordigen->getInstitutions()); - } - -} \ No newline at end of file diff --git a/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php b/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php index 9adb5104b7..78f02caf7c 100644 --- a/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php +++ b/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php @@ -46,6 +46,10 @@ class ConnectNordigenBankIntegrationRequest extends Request $input['institution_id'] = $context['institution_id']; } + if(isset($context['bank_account_id'])){ + $input['bank_account_id'] = $context['bank_account_id']; + } + $input['redirect'] = ($context['is_react'] ?? false) ? config('ninja.react_url') . '/#/settings/bank_accounts' : config('ninja.app_url'); diff --git a/app/Models/BankTransaction.php b/app/Models/BankTransaction.php index ceab4dd8dc..72e691a7b1 100644 --- a/app/Models/BankTransaction.php +++ b/app/Models/BankTransaction.php @@ -90,7 +90,8 @@ class BankTransaction extends BaseModel 'vendor_id', 'amount', 'participant', - 'participant_name' + 'participant_name', + 'currency_code' ]; diff --git a/composer.lock b/composer.lock index 8836d8c3e0..40457422c7 100644 --- a/composer.lock +++ b/composer.lock @@ -2552,20 +2552,20 @@ }, { "name": "elasticsearch/elasticsearch", - "version": "v8.18.0", + "version": "v8.19.0", "source": { "type": "git", "url": "https://github.com/elastic/elasticsearch-php.git", - "reference": "df8ee73046c688ee9ce2d69cb5c54a03ca38cc5c" + "reference": "1771284cb43a7b653634d418b6f5f0ec84ff8a6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/df8ee73046c688ee9ce2d69cb5c54a03ca38cc5c", - "reference": "df8ee73046c688ee9ce2d69cb5c54a03ca38cc5c", + "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/1771284cb43a7b653634d418b6f5f0ec84ff8a6d", + "reference": "1771284cb43a7b653634d418b6f5f0ec84ff8a6d", "shasum": "" }, "require": { - "elastic/transport": "^8.10", + "elastic/transport": "^8.11", "guzzlehttp/guzzle": "^7.0", "php": "^7.4 || ^8.0", "psr/http-client": "^1.0", @@ -2603,9 +2603,9 @@ ], "support": { "issues": "https://github.com/elastic/elasticsearch-php/issues", - "source": "https://github.com/elastic/elasticsearch-php/tree/v8.18.0" + "source": "https://github.com/elastic/elasticsearch-php/tree/v8.19.0" }, - "time": "2025-05-02T10:38:56+00:00" + "time": "2025-08-06T16:58:06+00:00" }, { "name": "endroid/qr-code", @@ -5534,16 +5534,16 @@ }, { "name": "laravel/octane", - "version": "v2.12.0", + "version": "v2.12.1", "source": { "type": "git", "url": "https://github.com/laravel/octane.git", - "reference": "d606f3dffc785032f11c23a017334c99800f2e40" + "reference": "4ca38b90d76f31b8c1e27873316c2db34450151c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/octane/zipball/d606f3dffc785032f11c23a017334c99800f2e40", - "reference": "d606f3dffc785032f11c23a017334c99800f2e40", + "url": "https://api.github.com/repos/laravel/octane/zipball/4ca38b90d76f31b8c1e27873316c2db34450151c", + "reference": "4ca38b90d76f31b8c1e27873316c2db34450151c", "shasum": "" }, "require": { @@ -5620,7 +5620,7 @@ "issues": "https://github.com/laravel/octane/issues", "source": "https://github.com/laravel/octane" }, - "time": "2025-07-18T15:50:14+00:00" + "time": "2025-07-25T15:03:05+00:00" }, { "name": "laravel/prompts", @@ -8300,29 +8300,29 @@ }, { "name": "nette/utils", - "version": "v4.0.7", + "version": "v4.0.8", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", "shasum": "" }, "require": { - "php": "8.0 - 8.4" + "php": "8.0 - 8.5" }, "conflict": { "nette/finder": "<3", "nette/schema": "<1.2.2" }, "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", + "jetbrains/phpstorm-attributes": "^1.2", "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -8340,6 +8340,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -8380,9 +8383,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.7" + "source": "https://github.com/nette/utils/tree/v4.0.8" }, - "time": "2025-06-03T04:55:08+00:00" + "time": "2025-08-06T21:43:34+00:00" }, { "name": "nikic/php-parser", @@ -8823,16 +8826,16 @@ }, { "name": "open-telemetry/context", - "version": "1.2.1", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/context.git", - "reference": "1eb2b837ee9362db064a6b65d5ecce15a9f9f020" + "reference": "4d5d98f1d4311a55b8d07e3d4c06d2430b4e6efc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/1eb2b837ee9362db064a6b65d5ecce15a9f9f020", - "reference": "1eb2b837ee9362db064a6b65d5ecce15a9f9f020", + "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/4d5d98f1d4311a55b8d07e3d4c06d2430b4e6efc", + "reference": "4d5d98f1d4311a55b8d07e3d4c06d2430b4e6efc", "shasum": "" }, "require": { @@ -8878,7 +8881,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-07T23:36:50+00:00" + "time": "2025-08-04T03:25:06+00:00" }, { "name": "paragonie/constant_time_encoding", diff --git a/config/ninja.php b/config/ninja.php index bb82b8acbf..71b2c3a217 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -17,8 +17,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => env('APP_VERSION', '5.12.10'), - 'app_tag' => env('APP_TAG', '5.12.10'), + 'app_version' => env('APP_VERSION', '5.12.11'), + 'app_tag' => env('APP_TAG', '5.12.11'), 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', false),