From cd4dbb897f8074104462475d3231cf39d5674503 Mon Sep 17 00:00:00 2001 From: paulwer Date: Mon, 11 Dec 2023 09:15:41 +0100 Subject: [PATCH] dev-workaround for storing accountId + updates to transaction jobs + local fonts --- .../Controllers/Bank/NordigenController.php | 6 +- .../Controllers/BankIntegrationController.php | 68 ++++++----------- .../ConnectNordigenBankIntegrationRequest.php | 5 +- .../Bank/ProcessBankTransactionsNordigen.php | 74 +++++++++++++++---- app/Models/BankIntegration.php | 1 + composer.lock | 48 ++++++------ ...3_11_26_082959_add_bank_integration_id.php | 1 + .../views/bank/nordigen/connect.blade.php | 8 +- 8 files changed, 119 insertions(+), 92 deletions(-) diff --git a/app/Http/Controllers/Bank/NordigenController.php b/app/Http/Controllers/Bank/NordigenController.php index 1e10f3ae8c2c..149b822ac7ec 100644 --- a/app/Http/Controllers/Bank/NordigenController.php +++ b/app/Http/Controllers/Bank/NordigenController.php @@ -49,7 +49,6 @@ class NordigenController extends BaseController 'institutions' => $nordigen->getInstitutions(), 'company' => $company, 'account' => $company->account, - 'redirect' => config('ninja.app_url') . '/nordigen/connect', ]; return view('bank.nordigen.connect', $data); @@ -187,12 +186,13 @@ class NordigenController extends BaseController $bank_integration->company_id = $company->id; $bank_integration->account_id = $company->account_id; $bank_integration->user_id = $company->owner()->id; - $bank_integration->bank_account_id = $nordigen_account['id']; + // $bank_integration->bank_account_id = $nordigen_account['id']; // TODO $bank_integration->bank_account_type = $nordigen_account['account_type']; $bank_integration->bank_account_name = $nordigen_account['account_name']; $bank_integration->bank_account_status = $nordigen_account['account_status']; $bank_integration->bank_account_number = $nordigen_account['account_number']; - $bank_integration->provider_id = $nordigen_account['provider_id']; + // $bank_integration->provider_id = $nordigen_account['provider_id']; // TODO + $bank_integration->nordigen_meta = (string) $nordigen_account['id'] . "," . $nordigen_account['provider_id']; // TODO: maybe move to bank_account_id and provider_id $bank_integration->provider_name = $nordigen_account['provider_name']; $bank_integration->nickname = $nordigen_account['nickname']; $bank_integration->balance = $nordigen_account['current_balance']; diff --git a/app/Http/Controllers/BankIntegrationController.php b/app/Http/Controllers/BankIntegrationController.php index 5a837f687c20..6a1e2fdcc381 100644 --- a/app/Http/Controllers/BankIntegrationController.php +++ b/app/Http/Controllers/BankIntegrationController.php @@ -206,17 +206,19 @@ class BankIntegrationController extends BaseController return response()->json(BankIntegration::query()->company(), 200); // Processing transactions for each bank account - $user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->each(function ($bank_integration) use ($user_account) { + if (!$user->account->bank_integration_yodlee_account_id) + $user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_YODLEE)->each(function ($bank_integration) use ($user_account) { - ProcessBankTransactionsYodlee::dispatch($user_account, $bank_integration); + ProcessBankTransactionsYodlee::dispatch($user_account, $bank_integration); - }); + }); - $user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->each(function ($bank_integration) use ($user_account) { + if (!$user->account->bank_integration_nordigen_secret_id || !$user->account->bank_integration_nordigen_secret_key) + $user_account->bank_integrations->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->each(function ($bank_integration) use ($user_account) { - ProcessBankTransactionsNordigen::dispatch($user_account, $bank_integration); + ProcessBankTransactionsNordigen::dispatch($user_account, $bank_integration); - }); + }); Cache::put("throttle_polling:{$user_account->key}", true, 300); @@ -225,9 +227,8 @@ class BankIntegrationController extends BaseController private function refreshAccountsYodlee(User $user) { - if (!$user->account->bank_integration_yodlee_account_id) { - return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400); - } + if (!$user->account->bank_integration_yodlee_account_id) + return; $yodlee = new Yodlee($user->account->bank_integration_yodlee_account_id); @@ -263,36 +264,26 @@ class BankIntegrationController extends BaseController private function refreshAccountsNordigen(User $user) { if (!$user->account->bank_integration_nordigen_secret_id || !$user->account->bank_integration_nordigen_secret_key) - return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400); + return; $nordigen = new Nordigen($user->account->bank_integration_nordigen_secret_id, $user->account->bank_integration_nordigen_secret_key); - $accounts = $nordigen->getAccounts(); // TODO?! + BankIntegration::withTrashed()->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->each(function (BankIntegration $bank_integration) use ($nordigen, $user) { + $account = $nordigen->getAccount(explode(',', $bank_integration->nordigen_meta)[0]); - foreach ($accounts as $account) { - if ($bi = BankIntegration::withTrashed()->where("integration_type", BankIntegration::INTEGRATION_TYPE_NORDIGEN)->where('bank_account_id', $account['id'])->where('company_id', $user->company()->id)->first()) { - $bi->balance = $account['current_balance']; - $bi->currency = $account['account_currency']; - $bi->save(); - } else { - $bank_integration = new BankIntegration(); - $bank_integration->company_id = $user->company()->id; - $bank_integration->account_id = $user->account_id; - $bank_integration->user_id = $user->id; - $bank_integration->bank_account_id = $account['id']; - $bank_integration->bank_account_type = $account['account_type']; - $bank_integration->bank_account_name = $account['account_name']; - $bank_integration->bank_account_status = $account['account_status']; - $bank_integration->bank_account_number = $account['account_number']; - $bank_integration->provider_id = $account['provider_id']; - $bank_integration->provider_name = $account['provider_name']; - $bank_integration->nickname = $account['nickname']; - $bank_integration->balance = $account['current_balance']; - $bank_integration->currency = $account['account_currency']; + if (!$account) { + $bank_integration->disabled_upstream = true; $bank_integration->save(); + return; } - } + + $bank_integration->bank_account_status = $account['account_status']; + $bank_integration->balance = $account['current_balance']; + $bank_integration->currency = $account['account_currency']; + + $bank_integration->save(); + }); } /** @@ -314,8 +305,7 @@ class BankIntegrationController extends BaseController if ($bank_integration->integration_type == BankIntegration::INTEGRATION_TYPE_YODLEE) $this->removeAccountYodlee($account, $bank_integration); - else if ($bank_integration->integration_type == BankIntegration::INTEGRATION_TYPE_NORDIGEN) - $this->removeAccountNordigen($account, $bank_integration); + // we dont remove Accounts from nordigen, because they could be used within other companies $this->bank_integration_repo->delete($bank_integration); @@ -332,16 +322,6 @@ class BankIntegrationController extends BaseController $yodlee->deleteAccount($bank_integration->bank_account_id); } - private function removeAccountNordigen(Account $account, BankIntegration $bank_integration) - { - if (!$account->bank_integration_nordigen_secret_id || !$account->bank_integration_nordigen_secret_key) - return response()->json(['message' => 'Not yet authenticated with Bank Integration service'], 400); - - $nordigen = new Nordigen($account->bank_integration_nordigen_secret_id, $account->bank_integration_nordigen_secret_key); - $nordigen->deleteAccount($bank_integration->bank_account_id); - } - - /** * Return the remote list of accounts stored on the third party provider * and update our local cache. diff --git a/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php b/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php index 36fc055c655f..b68b1d76ce16 100644 --- a/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php +++ b/app/Http/Requests/Nordigen/ConnectNordigenBankIntegrationRequest.php @@ -51,10 +51,7 @@ class ConnectNordigenBankIntegrationRequest extends Request if (!array_key_exists('redirect', $input)) { $context = $this->getTokenContent(); - if ($context && array_key_exists('is_react', $context)) - $input["redirect"] = $context["is_react"] ? config("ninja.react_url") : config("ninja.app_url"); - else - $input["redirect"] = config("ninja.app_url"); + $input["redirect"] = isset($context['is_react']) && $context['is_react'] ? config('ninja.react_url') : config('ninja.app_url'); $this->replace($input); diff --git a/app/Jobs/Bank/ProcessBankTransactionsNordigen.php b/app/Jobs/Bank/ProcessBankTransactionsNordigen.php index b976030dff9f..a85247f3ef30 100644 --- a/app/Jobs/Bank/ProcessBankTransactionsNordigen.php +++ b/app/Jobs/Bank/ProcessBankTransactionsNordigen.php @@ -17,6 +17,7 @@ use App\Models\Account; use App\Models\BankIntegration; use App\Models\BankTransaction; use App\Models\Company; +use App\Notifications\Ninja\GenericNinjaAdminNotification; use App\Services\Bank\BankMatchingService; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -39,6 +40,8 @@ class ProcessBankTransactionsNordigen implements ShouldQueue private int $skip = 0; public Company $company; + public Nordigen $nordigen; + public $nordigen_account; /** * Create a new job instance. @@ -53,6 +56,8 @@ class ProcessBankTransactionsNordigen implements ShouldQueue if ($this->bank_integration->integration_type != BankIntegration::INTEGRATION_TYPE_NORDIGEN) throw new \Exception("Invalid BankIntegration Type"); + $this->nordigen = new Nordigen($this->account->bank_integration_nordigen_secret_id, $this->account->bank_integration_nordigen_secret_key); + } /** @@ -69,12 +74,39 @@ class ProcessBankTransactionsNordigen implements ShouldQueue //Loop through everything until we are up to date $this->from_date = $this->from_date ?: '2021-01-01'; + // UPDATE ACCOUNT + try { + $this->updateAccount(); + } catch (\Exception $e) { + nlog("{$this->account->bank_integration_nordigen_secret_id} - exited abnormally => " . $e->getMessage()); + + $content = [ + "Processing transactions for account: {$this->bank_integration->account->key} failed", + "Exception Details => ", + $e->getMessage(), + ]; + + $this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja(); + return; + } + if (!$this->nordigen_account) + return; + + // UPDATE TRANSACTIONS do { try { $this->processTransactions(); } catch (\Exception $e) { nlog("{$this->account->bank_integration_nordigen_secret_id} - exited abnormally => " . $e->getMessage()); + + $content = [ + "Processing transactions for account: {$this->bank_integration->account->key} failed", + "Exception Details => ", + $e->getMessage(), + ]; + + $this->bank_integration->company->notification(new GenericNinjaAdminNotification($content))->ninja(); return; } @@ -85,13 +117,12 @@ class ProcessBankTransactionsNordigen implements ShouldQueue } - - private function processTransactions() + private function updateAccount() { - $nordigen = new Nordigen($this->account->bank_integration_nordigen_secret_id, $this->account->bank_integration_nordigen_secret_key); // TODO: maybe implement credentials + $bank_account_id = explode(',', $this->bank_integration->nordigen_meta)[0]; // maybe replace it later with bank_account_id - if (!$nordigen->isAccountActive($this->bank_integration->bank_account_id)) { + if (!$this->nordigen->isAccountActive($bank_account_id)) { $this->bank_integration->disabled_upstream = true; $this->bank_integration->save(); $this->stop_loop = false; @@ -99,8 +130,21 @@ class ProcessBankTransactionsNordigen implements ShouldQueue return; } + $this->nordigen_account = $this->nordigen->getAccount($bank_account_id); + + $this->bank_integration->bank_account_status = $this->nordigen_account['account_status']; + $this->bank_integration->balance = $this->nordigen_account['current_balance']; + $this->bank_integration->currency = $this->nordigen_account['account_currency']; + + $this->bank_integration->save(); + + } + + private function processTransactions() + { + //Get transaction count object - $transactions = $nordigen->getTransactions($this->bank_integration->bank_account_id, $this->from_date); + $transactions = $this->nordigen->getTransactions($this->nordigen_account["id"], $this->from_date); //Get int count $count = sizeof($transactions); @@ -108,7 +152,7 @@ class ProcessBankTransactionsNordigen implements ShouldQueue //if no transactions, update the from_date and move on if (count($transactions) == 0) { - $this->bank_integration->from_date = now()->subDays(2); + $this->bank_integration->from_date = now()->subDays(5); $this->bank_integration->disabled_upstream = false; $this->bank_integration->save(); $this->stop_loop = false; @@ -133,7 +177,7 @@ class ProcessBankTransactionsNordigen implements ShouldQueue continue; //this should be much faster to insert than using ::create() - $bt = \DB::table('bank_transactions')->insert( + \DB::table('bank_transactions')->insert( array_merge($transaction, [ 'company_id' => $this->company->id, 'user_id' => $user_id, @@ -146,14 +190,18 @@ class ProcessBankTransactionsNordigen implements ShouldQueue } - $this->skip = $this->skip + 500; + // $this->skip = $this->skip + 500; - if ($count < 500) { - $this->stop_loop = false; - $this->bank_integration->from_date = now()->subDays(2); - $this->bank_integration->save(); + // if ($count < 500) { + // $this->stop_loop = false; + // $this->bank_integration->from_date = now()->subDays(5); + // $this->bank_integration->save(); - } + // } + + $this->stop_loop = false; + $this->bank_integration->from_date = now()->subDays(5); + $this->bank_integration->save(); } } diff --git a/app/Models/BankIntegration.php b/app/Models/BankIntegration.php index 04e5bc9245a9..613e6f1dc210 100644 --- a/app/Models/BankIntegration.php +++ b/app/Models/BankIntegration.php @@ -30,6 +30,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property float $balance * @property int|null $currency * @property string $nickname + * @property string $nordigen_meta // TODO: maybe move to bank_account_id and provider_id * @property string|null $from_date * @property bool $is_deleted * @property int|null $created_at diff --git a/composer.lock b/composer.lock index b57c5b4170a0..3d5ee32d34aa 100644 --- a/composer.lock +++ b/composer.lock @@ -2617,16 +2617,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.326.1", + "version": "v0.327.0", "source": { "type": "git", "url": "https://github.com/googleapis/google-api-php-client-services.git", - "reference": "4e89c28c499f87eb517679e13356469896a119c6" + "reference": "51a11d4ff70dd9f60334525e71bf4cf592e6d282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/4e89c28c499f87eb517679e13356469896a119c6", - "reference": "4e89c28c499f87eb517679e13356469896a119c6", + "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/51a11d4ff70dd9f60334525e71bf4cf592e6d282", + "reference": "51a11d4ff70dd9f60334525e71bf4cf592e6d282", "shasum": "" }, "require": { @@ -2655,9 +2655,9 @@ ], "support": { "issues": "https://github.com/googleapis/google-api-php-client-services/issues", - "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.326.1" + "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.327.0" }, - "time": "2023-12-04T01:18:18+00:00" + "time": "2023-12-11T00:52:16+00:00" }, { "name": "google/auth", @@ -6831,16 +6831,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.17.1", + "version": "v4.18.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", - "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", "shasum": "" }, "require": { @@ -6881,9 +6881,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" }, - "time": "2023-08-13T19:53:39+00:00" + "time": "2023-12-10T21:03:43+00:00" }, { "name": "nordigen/nordigen-php", @@ -15318,16 +15318,16 @@ }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.41.0", + "version": "v3.41.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "7d8d18e19095a939b8a3b8046f57108feaad6134" + "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/7d8d18e19095a939b8a3b8046f57108feaad6134", - "reference": "7d8d18e19095a939b8a3b8046f57108feaad6134", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/8b6ae8dcbaf23f09680643ab832a4a3a260265f6", + "reference": "8b6ae8dcbaf23f09680643ab832a4a3a260265f6", "shasum": "" }, "require": { @@ -15397,7 +15397,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.41.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.41.1" }, "funding": [ { @@ -15405,7 +15405,7 @@ "type": "github" } ], - "time": "2023-12-08T22:54:33+00:00" + "time": "2023-12-10T19:59:27+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -16184,16 +16184,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "10.1.9", + "version": "10.1.10", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735" + "reference": "599109c8ca6bae97b23482d557d2874c25a65e59" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/a56a9ab2f680246adcf3db43f38ddf1765774735", - "reference": "a56a9ab2f680246adcf3db43f38ddf1765774735", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/599109c8ca6bae97b23482d557d2874c25a65e59", + "reference": "599109c8ca6bae97b23482d557d2874c25a65e59", "shasum": "" }, "require": { @@ -16250,7 +16250,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.9" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.10" }, "funding": [ { @@ -16258,7 +16258,7 @@ "type": "github" } ], - "time": "2023-11-23T12:23:20+00:00" + "time": "2023-12-11T06:28:43+00:00" }, { "name": "phpunit/php-file-iterator", diff --git a/database/migrations/2023_11_26_082959_add_bank_integration_id.php b/database/migrations/2023_11_26_082959_add_bank_integration_id.php index 6189012da8de..13ead010801d 100644 --- a/database/migrations/2023_11_26_082959_add_bank_integration_id.php +++ b/database/migrations/2023_11_26_082959_add_bank_integration_id.php @@ -16,6 +16,7 @@ return new class extends Migration { { Schema::table('bank_integrations', function (Blueprint $table) { $table->string('integration_type')->nullable(); + $table->string('nordigen_meta')->nullable(); // accountId,institutionId @todo: maybe replace with the following below // $table->string('provider_id'); // migrate to string, because nordigen provides a string like: SANDBOXFINANCE_SFIN0000 // $table->string('bank_account_id'); // migrate to string, because nordigen uses uuid() strings }); diff --git a/resources/views/bank/nordigen/connect.blade.php b/resources/views/bank/nordigen/connect.blade.php index 2009feb2bddf..a823726d99e2 100644 --- a/resources/views/bank/nordigen/connect.blade.php +++ b/resources/views/bank/nordigen/connect.blade.php @@ -22,8 +22,8 @@ // Pass your redirect link after user has been authorized in institution const config = { - // Text that will be displayed on the left side under the logo. Text is limited to 100 characters, and rest will be truncated. - text: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean mavdvd", + // Text that will be displayed on the left side under the logo. Text is limited to 100 characters, and rest will be truncated. @turbo124 replace with a translated version like ctrans() + text: "{{ $account && !$account->isPaid() ? 'Invoice Ninja' : (isset($company) && !is_null($company) ? $company->name : '') }} will gain access for your selected bank account. After selecting your institution you are redirected to theire front-page to complete the request with your account credentials.", // Logo URL that will be shown below the modal form. logoUrl: "{{ $account && !$account->isPaid() ? asset('images/invoiceninja-black-logo-2.png') : (isset($company) && !is_null($company) ? $company->present()->logo() : '') }}", // Will display country list with corresponding institutions. When `countryFilter` is set to `false`, only list of institutions will be shown. @@ -32,7 +32,7 @@ styles: { // Primary // Link to google font - fontFamily: '/assets/fonts/Roboto-Regular.ttf', + fontFamily: new URL("assets/fonts/Roboto-Regular.ttf", window.location.origin).href, fontSize: '15', backgroundColor: '#F2F2F2', textColor: '#222', @@ -58,7 +58,7 @@ const institutionId = institution.getAttribute('data-institution'); const url = new URL(window.location.href); url.searchParams.set('institution_id', institutionId); - window.location.href = url.href; + w.location.href = url.href; }); });