mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-09 20:52:56 +01:00
first draft
This commit is contained in:
parent
e1fbbe4268
commit
8a8c3b85c3
41
app/Exceptions/NordigenApiException.php
Normal file
41
app/Exceptions/NordigenApiException.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class NordigenApiException extends Exception
|
||||
{
|
||||
/**
|
||||
* Report the exception.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function report()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the exception into an HTTP response.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return Response
|
||||
*/
|
||||
public function render($request)
|
||||
{
|
||||
|
||||
// $msg = 'Unable to refund the transaction';
|
||||
$msg = ctrans('texts.error');
|
||||
|
||||
if ($this->getMessage() && strlen($this->getMessage()) >= 1) {
|
||||
$msg = $this->getMessage();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => $msg,
|
||||
], 400);
|
||||
}
|
||||
}
|
126
app/Helpers/Bank/Nordigen/Nordigen.php
Normal file
126
app/Helpers/Bank/Nordigen/Nordigen.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Bank\Yodlee;
|
||||
|
||||
use App\Exceptions\NordigenApiException;
|
||||
use App\Helpers\Bank\Nordigen\Transformer\AccountTransformer;
|
||||
use App\Helpers\Bank\Nordigen\Transformer\IncomeTransformer;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
// Generate new access token. Token is valid for 24 hours
|
||||
// Token is automatically injected into every response
|
||||
$token = $client->createAccessToken();
|
||||
|
||||
// Get access token
|
||||
$accessToken = $client->getAccessToken();
|
||||
// Get refresh token
|
||||
$refreshToken = $client->getRefreshToken();
|
||||
|
||||
// Exchange refresh token for new access token
|
||||
$newToken = $client->refreshAccessToken($refreshToken);
|
||||
|
||||
// Get list of institutions by country. Country should be in ISO 3166 standard.
|
||||
$institutions = $client->institution->getInstitutionsByCountry("LV");
|
||||
|
||||
// Institution id can be gathered from getInstitutions response.
|
||||
// Example Revolut ID
|
||||
$institutionId = "REVOLUT_REVOGB21";
|
||||
$redirectUri = "https://nordigen.com";
|
||||
|
||||
// Initialize new bank connection session
|
||||
$session = $client->initSession($institutionId, $redirectUri);
|
||||
|
||||
// Get link to authorize in the bank
|
||||
// Authorize with your bank via this link, to gain access to account data
|
||||
$link = $session["link"];
|
||||
// requisition id is needed to get accountId in the next step
|
||||
$requisitionId = $session["requisition_id"];
|
||||
|
||||
class Nordigen
|
||||
{
|
||||
public bool $test_mode = false;
|
||||
|
||||
protected \Nordigen\NordigenPHP\API\NordigenClient $client;
|
||||
|
||||
protected string $secret_id;
|
||||
|
||||
protected string $secret_key;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->secret_id = config('ninja.nordigen.secret_id');
|
||||
|
||||
$this->secret_key = config('ninja.nordigen.secret_key');
|
||||
|
||||
$this->client = new \Nordigen\NordigenPHP\API\NordigenClient($this->secret_id, $this->secret_key);
|
||||
}
|
||||
|
||||
public function getInstitutions()
|
||||
{
|
||||
return $this->client->institution->getInstitutions();
|
||||
}
|
||||
|
||||
public function getValidAccounts()
|
||||
{
|
||||
|
||||
// get all valid requisitions
|
||||
$requisitions = $this->client->requisition->getRequisitions();
|
||||
|
||||
// fetch all valid accounts for activated requisitions
|
||||
$accounts = [];
|
||||
foreach ($requisitions as $requisition) {
|
||||
foreach ($requisition->accounts as $account) {
|
||||
$account = $account = $this->client->account($account);
|
||||
|
||||
array_push($accounts, $account);
|
||||
}
|
||||
}
|
||||
|
||||
return $accounts;
|
||||
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$requisitions = $this->client->requisition->getRequisitions();
|
||||
|
||||
// TODO: filter to older than 2 days created AND (no accounts or invalid)
|
||||
|
||||
foreach ($requisitions as $requisition) {
|
||||
$this->client->requisition->deleteRequisition($requisition->id);
|
||||
}
|
||||
}
|
||||
|
||||
// account-section: these methods should be used to get data of connected accounts
|
||||
|
||||
public function getAccountMetaData(string $account_id)
|
||||
{
|
||||
return $this->client->account($account_id)->getAccountMetaData();
|
||||
}
|
||||
|
||||
public function getAccountDetails(string $account_id)
|
||||
{
|
||||
return $this->client->account($account_id)->getAccountDetails();
|
||||
}
|
||||
|
||||
public function getAccountBalances(string $account_id)
|
||||
{
|
||||
return $this->client->account($account_id)->getAccountBalances();
|
||||
}
|
||||
|
||||
public function getAccountTransactions(string $account_id)
|
||||
{
|
||||
return $this->client->account($account_id)->getAccountTransactions();
|
||||
}
|
||||
|
||||
}
|
104
app/Helpers/Bank/Nordigen/Transformer/AccountTransformer.php
Normal file
104
app/Helpers/Bank/Nordigen/Transformer/AccountTransformer.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Bank\Yodlee\Transformer;
|
||||
|
||||
use App\Helpers\Bank\AccountTransformerInterface;
|
||||
|
||||
/**
|
||||
[0] => stdClass Object
|
||||
(
|
||||
[CONTAINER] => bank
|
||||
[providerAccountId] => 11308693
|
||||
[accountName] => My CD - 8878
|
||||
[accountStatus] => ACTIVE
|
||||
[accountNumber] => xxxx8878
|
||||
[aggregationSource] => USER
|
||||
[isAsset] => 1
|
||||
[balance] => stdClass Object
|
||||
(
|
||||
[currency] => USD
|
||||
[amount] => 49778.07
|
||||
)
|
||||
|
||||
[id] => 12331861
|
||||
[includeInNetWorth] => 1
|
||||
[providerId] => 18769
|
||||
[providerName] => Dag Site Captcha
|
||||
[isManual] =>
|
||||
[currentBalance] => stdClass Object
|
||||
(
|
||||
[currency] => USD
|
||||
[amount] => 49778.07
|
||||
)
|
||||
|
||||
[accountType] => CD
|
||||
[displayedName] => LORETTA
|
||||
[createdDate] => 2022-07-28T06:55:33Z
|
||||
[lastUpdated] => 2022-07-28T06:56:09Z
|
||||
[dataset] => Array
|
||||
(
|
||||
[0] => stdClass Object
|
||||
(
|
||||
[name] => BASIC_AGG_DATA
|
||||
[additionalStatus] => AVAILABLE_DATA_RETRIEVED
|
||||
[updateEligibility] => ALLOW_UPDATE
|
||||
[lastUpdated] => 2022-07-28T06:55:50Z
|
||||
[lastUpdateAttempt] => 2022-07-28T06:55:50Z
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
*/
|
||||
|
||||
|
||||
class AccountTransformer implements AccountTransformerInterface
|
||||
{
|
||||
|
||||
public function transform($yodlee_account)
|
||||
{
|
||||
|
||||
$data = [];
|
||||
|
||||
if(!property_exists($yodlee_account, 'account'))
|
||||
return $data;
|
||||
|
||||
foreach($yodlee_account->account as $account)
|
||||
{
|
||||
$data[] = $this->transformAccount($account);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function transformAccount($account)
|
||||
{
|
||||
|
||||
return [
|
||||
'id' => $account->id,
|
||||
'account_type' => $account->CONTAINER,
|
||||
// 'account_name' => $account->accountName,
|
||||
'account_name' => property_exists($account, 'accountName') ? $account->accountName : $account->nickname,
|
||||
'account_status' => $account->accountStatus,
|
||||
'account_number' => property_exists($account, 'accountNumber') ? '**** ' . substr($account?->accountNumber, -7) : '',
|
||||
'provider_account_id' => $account->providerAccountId,
|
||||
'provider_id' => $account->providerId,
|
||||
'provider_name' => $account->providerName,
|
||||
'nickname' => property_exists($account, 'nickname') ? $account->nickname : '',
|
||||
'current_balance' => property_exists($account, 'currentBalance') ? $account->currentBalance->amount : 0,
|
||||
'account_currency' => property_exists($account, 'currency') ? $account->currentBalance->currency : '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
80
app/Helpers/Bank/Nordigen/Transformer/ExpenseTransformer.php
Normal file
80
app/Helpers/Bank/Nordigen/Transformer/ExpenseTransformer.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Bank\Yodlee\Transformer;
|
||||
|
||||
/**
|
||||
"date": "string",
|
||||
"sourceId": "string",
|
||||
"symbol": "string",
|
||||
"cusipNumber": "string",
|
||||
"highLevelCategoryId": 0,
|
||||
"detailCategoryId": 0,
|
||||
"description": {},
|
||||
"memo": "string",
|
||||
"settleDate": "string",
|
||||
"type": "string",
|
||||
"intermediary": [],
|
||||
"baseType": "CREDIT",
|
||||
"categorySource": "SYSTEM",
|
||||
"principal": {},
|
||||
"lastUpdated": "string",
|
||||
"interest": {},
|
||||
"price": {},
|
||||
"commission": {},
|
||||
"id": 0,
|
||||
"merchantType": "string",
|
||||
"amount": {
|
||||
"amount": 0,
|
||||
"convertedAmount": 0,
|
||||
"currency": "USD",
|
||||
"convertedCurrency": "USD"
|
||||
},
|
||||
"checkNumber": "string",
|
||||
"isPhysical": true,
|
||||
"quantity": 0,
|
||||
"valoren": "string",
|
||||
"isManual": true,
|
||||
"merchant": {
|
||||
"website": "string",
|
||||
"address": {},
|
||||
"contact": {},
|
||||
"categoryLabel": [],
|
||||
"coordinates": {},
|
||||
"name": "string",
|
||||
"id": "string",
|
||||
"source": "YODLEE",
|
||||
"logoURL": "string"
|
||||
},
|
||||
"sedol": "string",
|
||||
"transactionDate": "string",
|
||||
"categoryType": "TRANSFER",
|
||||
"accountId": 0,
|
||||
"createdDate": "string",
|
||||
"sourceType": "AGGREGATED",
|
||||
"CONTAINER": "bank",
|
||||
"postDate": "string",
|
||||
"parentCategoryId": 0,
|
||||
"subType": "OVERDRAFT_CHARGE",
|
||||
"category": "string",
|
||||
"runningBalance": {},
|
||||
"categoryId": 0,
|
||||
"holdingDescription": "string",
|
||||
"isin": "string",
|
||||
"status": "POSTED"
|
||||
*/
|
||||
|
||||
class ExpenseTransformer
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
187
app/Helpers/Bank/Nordigen/Transformer/IncomeTransformer.php
Normal file
187
app/Helpers/Bank/Nordigen/Transformer/IncomeTransformer.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Helpers\Bank\Yodlee\Transformer;
|
||||
|
||||
use App\Helpers\Bank\BankRevenueInterface;
|
||||
use App\Utils\Traits\AppSetup;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
/**
|
||||
"date": "string",
|
||||
"sourceId": "string",
|
||||
"symbol": "string",
|
||||
"cusipNumber": "string",
|
||||
"highLevelCategoryId": 0,
|
||||
"detailCategoryId": 0,
|
||||
"description": {},
|
||||
"memo": "string",
|
||||
"settleDate": "string",
|
||||
"type": "string",
|
||||
"intermediary": [],
|
||||
"baseType": "CREDIT",
|
||||
"categorySource": "SYSTEM",
|
||||
"principal": {},
|
||||
"lastUpdated": "string",
|
||||
"interest": {},
|
||||
"price": {},
|
||||
"commission": {},
|
||||
"id": 0,
|
||||
"merchantType": "string",
|
||||
"amount": {
|
||||
"amount": 0,
|
||||
"convertedAmount": 0,
|
||||
"currency": "USD",
|
||||
"convertedCurrency": "USD"
|
||||
},
|
||||
"checkNumber": "string",
|
||||
"isPhysical": true,
|
||||
"quantity": 0,
|
||||
"valoren": "string",
|
||||
"isManual": true,
|
||||
"merchant": {
|
||||
"website": "string",
|
||||
"address": {},
|
||||
"contact": {},
|
||||
"categoryLabel": [],
|
||||
"coordinates": {},
|
||||
"name": "string",
|
||||
"id": "string",
|
||||
"source": "YODLEE",
|
||||
"logoURL": "string"
|
||||
},
|
||||
"sedol": "string",
|
||||
"transactionDate": "string",
|
||||
"categoryType": "TRANSFER",
|
||||
"accountId": 0,
|
||||
"createdDate": "string",
|
||||
"sourceType": "AGGREGATED",
|
||||
"CONTAINER": "bank",
|
||||
"postDate": "string",
|
||||
"parentCategoryId": 0,
|
||||
"subType": "OVERDRAFT_CHARGE",
|
||||
"category": "string",
|
||||
"runningBalance": {},
|
||||
"categoryId": 0,
|
||||
"holdingDescription": "string",
|
||||
"isin": "string",
|
||||
"status": "POSTED"
|
||||
|
||||
(
|
||||
[CONTAINER] => bank
|
||||
[id] => 103953585
|
||||
[amount] => stdClass Object
|
||||
(
|
||||
[amount] => 480.66
|
||||
[currency] => USD
|
||||
)
|
||||
|
||||
[categoryType] => UNCATEGORIZE
|
||||
[categoryId] => 1
|
||||
[category] => Uncategorized
|
||||
[categorySource] => SYSTEM
|
||||
[highLevelCategoryId] => 10000017
|
||||
[createdDate] => 2022-08-04T21:50:17Z
|
||||
[lastUpdated] => 2022-08-04T21:50:17Z
|
||||
[description] => stdClass Object
|
||||
(
|
||||
[original] => CHEROKEE NATION TAX TA TAHLEQUAH OK
|
||||
)
|
||||
|
||||
[isManual] =>
|
||||
[sourceType] => AGGREGATED
|
||||
[date] => 2022-08-03
|
||||
[transactionDate] => 2022-08-03
|
||||
[postDate] => 2022-08-03
|
||||
[status] => POSTED
|
||||
[accountId] => 12331794
|
||||
[runningBalance] => stdClass Object
|
||||
(
|
||||
[amount] => 480.66
|
||||
[currency] => USD
|
||||
)
|
||||
|
||||
[checkNumber] => 998
|
||||
)
|
||||
*/
|
||||
|
||||
class IncomeTransformer implements BankRevenueInterface
|
||||
{
|
||||
use AppSetup;
|
||||
|
||||
public function transform($transaction)
|
||||
{
|
||||
|
||||
$data = [];
|
||||
|
||||
if(!property_exists($transaction, 'transaction'))
|
||||
return $data;
|
||||
|
||||
foreach($transaction->transaction as $transaction)
|
||||
{
|
||||
$data[] = $this->transformTransaction($transaction);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function transformTransaction($transaction)
|
||||
{
|
||||
|
||||
return [
|
||||
'transaction_id' => $transaction->id,
|
||||
'amount' => $transaction->amount->amount,
|
||||
'currency_id' => $this->convertCurrency($transaction->amount->currency),
|
||||
'account_type' => $transaction->CONTAINER,
|
||||
'category_id' => $transaction->highLevelCategoryId,
|
||||
'category_type' => $transaction->categoryType,
|
||||
'date' => $transaction->date,
|
||||
'bank_account_id' => $transaction->accountId,
|
||||
'description' => $transaction->description->original,
|
||||
'base_type' => property_exists($transaction, 'baseType') ? $transaction->baseType : $this->calculateBaseType($transaction),
|
||||
];
|
||||
}
|
||||
|
||||
private function calculateBaseType($transaction)
|
||||
{
|
||||
//CREDIT / DEBIT
|
||||
|
||||
if(property_exists($transaction, 'highLevelCategoryId') && $transaction->highLevelCategoryId == 10000012)
|
||||
return 'CREDIT';
|
||||
|
||||
return 'DEBIT';
|
||||
|
||||
}
|
||||
|
||||
private function convertCurrency(string $code)
|
||||
{
|
||||
|
||||
$currencies = Cache::get('currencies');
|
||||
|
||||
if (! $currencies) {
|
||||
$this->buildCache(true);
|
||||
}
|
||||
|
||||
$currency = $currencies->filter(function ($item) use($code){
|
||||
return $item->code == $code;
|
||||
})->first();
|
||||
|
||||
if($currency)
|
||||
return $currency->id;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
301
app/Http/Controllers/Bank/NordigenController.php
Normal file
301
app/Http/Controllers/Bank/NordigenController.php
Normal file
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers\Bank;
|
||||
|
||||
use App\Helpers\Bank\Nordigen\Nordigen;
|
||||
use App\Http\Controllers\BaseController;
|
||||
use App\Http\Requests\Yodlee\YodleeAuthRequest;
|
||||
use App\Jobs\Bank\ProcessBankTransactions;
|
||||
use App\Models\BankIntegration;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class YodleeController extends BaseController
|
||||
{
|
||||
|
||||
public function auth(YodleeAuthRequest $request)
|
||||
{
|
||||
|
||||
// create a user at this point
|
||||
// use the one time token here to pull in the actual user
|
||||
// store the user_account_id on the accounts table
|
||||
|
||||
$nordigen = new Nordigen();
|
||||
|
||||
$company = $request->getCompany();
|
||||
|
||||
|
||||
//ensure user is enterprise!!
|
||||
|
||||
if ($company->account->bank_integration_account_id) {
|
||||
|
||||
$flow = 'edit';
|
||||
|
||||
$token = $company->account->bank_integration_account_id;
|
||||
|
||||
} else {
|
||||
|
||||
$flow = 'add';
|
||||
|
||||
$response = $yodlee->createUser($company);
|
||||
|
||||
$token = $response->user->loginName;
|
||||
|
||||
$company->account->bank_integration_account_id = $token;
|
||||
|
||||
$company->push();
|
||||
|
||||
}
|
||||
|
||||
$yodlee = new Yodlee($token);
|
||||
|
||||
if ($request->has('window_closed') && $request->input("window_closed") == "true")
|
||||
$this->getAccounts($company, $token);
|
||||
|
||||
$data = [
|
||||
'access_token' => $yodlee->getAccessToken(),
|
||||
'fasttrack_url' => $yodlee->getFastTrackUrl(),
|
||||
'config_name' => config('ninja.yodlee.config_name'),
|
||||
'flow' => $flow,
|
||||
'company' => $company,
|
||||
'account' => $company->account,
|
||||
'completed' => $request->has('window_closed') ? true : false,
|
||||
];
|
||||
|
||||
return view('bank.yodlee.auth', $data);
|
||||
|
||||
}
|
||||
|
||||
private function getAccounts($company, $token)
|
||||
{
|
||||
$nordigen = new Nordigen($token);
|
||||
|
||||
$accounts = $nordigen->getAccounts();
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
|
||||
if (!BankIntegration::where('bank_account_id', $account['id'])->where('company_id', $company->id)->exists()) {
|
||||
$bank_integration = new BankIntegration();
|
||||
$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 = $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'];
|
||||
$bank_integration->from_date = now()->subYear();
|
||||
|
||||
$bank_integration->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
$company->account->bank_integrations->each(function ($bank_integration) use ($company) {
|
||||
|
||||
ProcessBankTransactions::dispatch($company->account->bank_integration_account_id, $bank_integration);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process Yodlee Refresh Webhook.
|
||||
*
|
||||
*
|
||||
* @OA\Post(
|
||||
* path="/api/v1/yodlee/refresh",
|
||||
* operationId="yodleeRefreshWebhook",
|
||||
* tags={"yodlee"},
|
||||
* summary="Processing webhooks from Yodlee",
|
||||
* description="Notifies the system when a data point can be refreshed",
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="",
|
||||
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||
* @OA\JsonContent(ref="#/components/schemas/Credit"),
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response=422,
|
||||
* description="Validation error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||
*
|
||||
* ),
|
||||
* @OA\Response(
|
||||
* response="default",
|
||||
* description="Unexpected Error",
|
||||
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||
* ),
|
||||
* )
|
||||
*/
|
||||
|
||||
/*
|
||||
{
|
||||
"event":{
|
||||
"info":"REFRESH.PROCESS_COMPLETED",
|
||||
"loginName":"fri21",
|
||||
"data":{
|
||||
"providerAccount":[
|
||||
{
|
||||
"id":10995860,
|
||||
"providerId":16441,
|
||||
"isManual":false,
|
||||
"createdDate":"2017-12-22T05:47:35Z",
|
||||
"aggregationSource":"USER",
|
||||
"status":"SUCCESS",
|
||||
"requestId":"NSyMGo+R4dktywIu3hBIkc3PgWA=",
|
||||
"dataset":[
|
||||
{
|
||||
"name":"BASIC_AGG_DATA",
|
||||
"additionalStatus":"AVAILABLE_DATA_RETRIEVED",
|
||||
"updateEligibility":"ALLOW_UPDATE",
|
||||
"lastUpdated":"2017-12-22T05:48:16Z",
|
||||
"lastUpdateAttempt":"2017-12-22T05:48:16Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}*/
|
||||
public function refreshWebhook(Request $request)
|
||||
{
|
||||
//we should ignore this one
|
||||
nlog("yodlee refresh");
|
||||
nlog($request->all());
|
||||
|
||||
return response()->json(['message' => 'Success'], 200);
|
||||
|
||||
//
|
||||
|
||||
// return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"event":{
|
||||
"notificationId":"63c73475-4db5-49ef-8553-8303337ca7c3",
|
||||
"info":"LATEST_BALANCE_UPDATES",
|
||||
"loginName":"user1",
|
||||
"data":{
|
||||
"providerAccountId":658552,
|
||||
"latestBalanceEvent":[
|
||||
{
|
||||
"accountId":12345,
|
||||
"status":"SUCCESS"
|
||||
},
|
||||
{
|
||||
"accountId":12346,
|
||||
"status":"FAILED"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
public function balanceWebhook(Request $request)
|
||||
{
|
||||
|
||||
nlog("yodlee refresh");
|
||||
nlog($request->all());
|
||||
|
||||
return response()->json(['message' => 'Success'], 200);
|
||||
|
||||
//
|
||||
|
||||
// return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
/*
|
||||
{
|
||||
"event":{
|
||||
"data":[
|
||||
{
|
||||
"autoRefresh":{
|
||||
"additionalStatus":"SCHEDULED",
|
||||
"status":"ENABLED"
|
||||
},
|
||||
"accountIds":[
|
||||
1112645899,
|
||||
1112645898
|
||||
],
|
||||
"loginName":"YSL1555332811628",
|
||||
"providerAccountId":11381459
|
||||
}
|
||||
],
|
||||
"notificationTime":"2019-06-14T04:49:39Z",
|
||||
"notificationId":"4e672150-156048777",
|
||||
"info":"AUTO_REFRESH_UPDATES"
|
||||
}
|
||||
}
|
||||
*/
|
||||
public function refreshUpdatesWebhook(Request $request)
|
||||
{
|
||||
//notifies a user if there are problems with yodlee accessing the data
|
||||
nlog("update refresh");
|
||||
nlog($request->all());
|
||||
|
||||
return response()->json(['message' => 'Success'], 200);
|
||||
|
||||
//
|
||||
|
||||
// return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
"event": {
|
||||
"notificationId": "64b7ed1a-1530523285",
|
||||
"info": "DATA_UPDATES.USER_DATA",
|
||||
"data": {
|
||||
"userCount": 1,
|
||||
"fromDate": "2017-11-10T10:18:44Z",
|
||||
"toDate": "2017-11-10T11:18:43Z",
|
||||
"userData": [{
|
||||
"user": {
|
||||
"loginName": "YSL1484052178554"
|
||||
},
|
||||
"links": [{
|
||||
"methodType": "GET",
|
||||
"rel": "getUserData",
|
||||
"href": "dataExtracts/userData?fromDate=2017-11-10T10:18:44Z&toDate=2017-11-10T11:18:43Z&loginName=YSL1484052178554"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
*/
|
||||
public function dataUpdatesWebhook(Request $request)
|
||||
{
|
||||
//this is the main hook we use for notifications
|
||||
|
||||
nlog("data refresh");
|
||||
nlog($request->all());
|
||||
|
||||
return response()->json(['message' => 'Success'], 200);
|
||||
|
||||
//
|
||||
|
||||
// return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
}
|
@ -20,8 +20,9 @@ class BankIntegration extends BaseModel
|
||||
use SoftDeletes;
|
||||
use Filterable;
|
||||
use Excludable;
|
||||
|
||||
|
||||
protected $fillable = [
|
||||
'integration_type',
|
||||
'bank_account_name',
|
||||
'provider_name',
|
||||
'bank_account_number',
|
||||
@ -36,6 +37,12 @@ class BankIntegration extends BaseModel
|
||||
protected $dates = [
|
||||
];
|
||||
|
||||
const INTEGRATION_TYPE_NONE = null;
|
||||
|
||||
const INTEGRATION_TYPE_YODLEE = 'YODLEE';
|
||||
|
||||
const INTEGRATION_TYPE_NORDIGEN = 'NORDIGEN';
|
||||
|
||||
public function getEntityType()
|
||||
{
|
||||
return self::class;
|
||||
@ -61,4 +68,4 @@ class BankIntegration extends BaseModel
|
||||
return $this->hasMany(BankTransaction::class)->withTrashed();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -70,11 +70,11 @@
|
||||
"microsoft/microsoft-graph": "^1.69",
|
||||
"mollie/mollie-api-php": "^2.36",
|
||||
"nelexa/zip": "^4.0",
|
||||
"nordigen/nordigen-php": "^1.1",
|
||||
"nwidart/laravel-modules": "8.3",
|
||||
"omnipay/paypal": "^3.0",
|
||||
"payfast/payfast-php-sdk": "^1.1",
|
||||
"pragmarx/google2fa": "^8.0",
|
||||
"turbo124/predis": "^1.1",
|
||||
"razorpay/razorpay": "2.*",
|
||||
"sentry/sentry-laravel": "^3",
|
||||
"setasign/fpdf": "^1.8",
|
||||
@ -89,6 +89,7 @@
|
||||
"symfony/postmark-mailer": "^6.1",
|
||||
"tijsverkoyen/css-to-inline-styles": "^2.2",
|
||||
"turbo124/beacon": "^1.3",
|
||||
"turbo124/predis": "^1.1",
|
||||
"twilio/sdk": "^6.40",
|
||||
"webpatser/laravel-countries": "dev-master#75992ad",
|
||||
"wepay/php-sdk": "^0.3"
|
||||
@ -157,7 +158,10 @@
|
||||
"config": {
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"optimize-autoloader": true
|
||||
"optimize-autoloader": true,
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": true
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
|
3005
composer.lock
generated
3005
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use App\Models\BankIntegration;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('bank_integration', function (Blueprint $table) {
|
||||
$table->string('integration_type')->nullable();
|
||||
});
|
||||
|
||||
// migrate old account to be used with yodlee
|
||||
BankIntegration::query()->whereNull('integration_type')->cursor()->each(function ($bank_integration) {
|
||||
$bank_integration->integration_type = BankIntegration::INTEGRATION_TYPE_YODLEE;
|
||||
$bank_integration->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('bank_integration', function (Blueprint $table) {
|
||||
$table->dropColumn('integration_id');
|
||||
});
|
||||
}
|
||||
};
|
@ -1,49 +1,49 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=7b6124b74168ccb1cc7da22f7a2bc9ed",
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js?id=b6723e0b8ea33f1f50617fa5f289a9d3",
|
||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js?id=faf4828cc6b3b73b69c53d3046661884",
|
||||
"/js/clients/payments/forte-credit-card-payment.js": "/js/clients/payments/forte-credit-card-payment.js?id=f42dd0caddb3603e71db061924c4b172",
|
||||
"/js/clients/payments/forte-ach-payment.js": "/js/clients/payments/forte-ach-payment.js?id=b8173c7c0dee76bf9ae6312a963ae0e4",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=207f218c44553470287f35f33a7eb154",
|
||||
"/js/clients/payments/stripe-klarna.js": "/js/clients/payments/stripe-klarna.js?id=7268f9282c6bb3b04d19d11a7b0c1681",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=404b7ee18e420de0e73f5402b7e39122",
|
||||
"/js/clients/purchase_orders/action-selectors.js": "/js/clients/purchase_orders/action-selectors.js?id=2f0c4e3bab30a98e33ac768255113174",
|
||||
"/js/clients/purchase_orders/accept.js": "/js/clients/purchase_orders/accept.js?id=9bb483a89a887f753e49c0b635d6276a",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=752e2bb6390f1a422e31868cf2a2bf67",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js?id=4fc5dec1bc4fc21b9e32b1b490c3e7ae",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js?id=018ecad3a1bcc1ecc47f76754a573ff2",
|
||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=7cb96275b3eb4901054564c654fb60e3",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=3a4c5cfac7dd4c9218be55945c3c8e85",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=1e58e219878ce3f3ee4d313346ad5f68",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=6e7c8ab039a239727317ae8622de10db",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js?id=8cab3339ef48418e1fb2e7a9259d51ca",
|
||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=cf50b5ba1fcd1d184bf0c10d710672c8",
|
||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=682de6347049b32c9488f39c78a68ace",
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js?id=d3c404bb646f1aeaf2382a8c57ab8e1a",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=e1c0599d6f7dc163b549a6df0b3490b4",
|
||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js?id=8b036822abaa4ceb379008fc14208dc2",
|
||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=de0b1d0c6da7ff509bef3aee8d09e7f8",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js?id=92ef8632637d335cd0e4bc29a05b7df8",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js?id=af85b3f6d53c55b5d0e3a80ef58ce0de",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=3869bc6d80acc83f81d9afe8efaae728",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=7cd5a1d95d33ada211ce185ad6e4bb33",
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=27274d334aed0824ce4654fa22132f7f",
|
||||
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=f85ebb6a77002afd350086d1274b6af5",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=238e7001420a22b001856193689a1e70",
|
||||
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=13e043123f1e58409394458a70461d63",
|
||||
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=494f58d2fd8984792833ba7d3055de08",
|
||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=77d4e397d193196e482af80737bff64a",
|
||||
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js?id=659c4287fb8ef1c458071c206c4d965d",
|
||||
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js?id=852a9abf5f3a29f5d7d2f989cbeab374",
|
||||
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js?id=447c587a5eeb0c1de3091c8358db7ad7",
|
||||
"/js/clients/payments/stripe-bancontact.js": "/js/clients/payments/stripe-bancontact.js?id=f694d3f9f01e4550cb5a3eb6cb43c12d",
|
||||
"/js/clients/payments/stripe-becs.js": "/js/clients/payments/stripe-becs.js?id=97ea3555a8504662eda5fce9c9115e5a",
|
||||
"/js/clients/payments/stripe-eps.js": "/js/clients/payments/stripe-eps.js?id=749cba1332a29baa444b37cee2ade2d7",
|
||||
"/js/clients/payments/stripe-ideal.js": "/js/clients/payments/stripe-ideal.js?id=34cf4ee3f189427fb69d0df8f5a4b766",
|
||||
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js?id=448b197a1d94b4408e130b5b8b1c2e53",
|
||||
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js?id=7015e43eb5f9f9f2f45f54b41b5780a0",
|
||||
"/js/clients/payments/stripe-fpx.js": "/js/clients/payments/stripe-fpx.js?id=243c2929386b10c6a0c49ca3bcabfb2d",
|
||||
"/css/app.css": "/css/app.css?id=0cb847167b91d8db2ca50d30e0d691ae",
|
||||
"/css/card-js.min.css": "/css/card-js.min.css?id=62afeb675235451543ada60afcedcb7c",
|
||||
"/vendor/clipboard.min.js": "/vendor/clipboard.min.js?id=15f52a1ee547f2bdd46e56747332ca2d"
|
||||
"/js/app.js": "/js/app.js",
|
||||
"/js/clients/payment_methods/authorize-authorize-card.js": "/js/clients/payment_methods/authorize-authorize-card.js",
|
||||
"/js/clients/payments/authorize-credit-card-payment.js": "/js/clients/payments/authorize-credit-card-payment.js",
|
||||
"/js/clients/payments/forte-credit-card-payment.js": "/js/clients/payments/forte-credit-card-payment.js",
|
||||
"/js/clients/payments/forte-ach-payment.js": "/js/clients/payments/forte-ach-payment.js",
|
||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js",
|
||||
"/js/clients/payments/stripe-klarna.js": "/js/clients/payments/stripe-klarna.js",
|
||||
"/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js",
|
||||
"/js/clients/purchase_orders/action-selectors.js": "/js/clients/purchase_orders/action-selectors.js",
|
||||
"/js/clients/purchase_orders/accept.js": "/js/clients/purchase_orders/accept.js",
|
||||
"/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js",
|
||||
"/js/clients/payments/stripe-sofort.js": "/js/clients/payments/stripe-sofort.js",
|
||||
"/js/clients/payments/stripe-alipay.js": "/js/clients/payments/stripe-alipay.js",
|
||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js",
|
||||
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js",
|
||||
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js",
|
||||
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js",
|
||||
"/js/setup/setup.js": "/js/setup/setup.js",
|
||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js",
|
||||
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js",
|
||||
"/js/clients/shared/multiple-downloads.js": "/js/clients/shared/multiple-downloads.js",
|
||||
"/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js",
|
||||
"/js/clients/payments/braintree-credit-card.js": "/js/clients/payments/braintree-credit-card.js",
|
||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js",
|
||||
"/js/clients/payments/wepay-credit-card.js": "/js/clients/payments/wepay-credit-card.js",
|
||||
"/js/clients/payment_methods/wepay-bank-account.js": "/js/clients/payment_methods/wepay-bank-account.js",
|
||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js",
|
||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js",
|
||||
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js",
|
||||
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js",
|
||||
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js",
|
||||
"/js/clients/statements/view.js": "/js/clients/statements/view.js",
|
||||
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js",
|
||||
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js",
|
||||
"/js/clients/payment_methods/authorize-checkout-card.js": "/js/clients/payment_methods/authorize-checkout-card.js",
|
||||
"/js/clients/payments/stripe-giropay.js": "/js/clients/payments/stripe-giropay.js",
|
||||
"/js/clients/payments/stripe-acss.js": "/js/clients/payments/stripe-acss.js",
|
||||
"/js/clients/payments/stripe-bancontact.js": "/js/clients/payments/stripe-bancontact.js",
|
||||
"/js/clients/payments/stripe-becs.js": "/js/clients/payments/stripe-becs.js",
|
||||
"/js/clients/payments/stripe-eps.js": "/js/clients/payments/stripe-eps.js",
|
||||
"/js/clients/payments/stripe-ideal.js": "/js/clients/payments/stripe-ideal.js",
|
||||
"/js/clients/payments/stripe-przelewy24.js": "/js/clients/payments/stripe-przelewy24.js",
|
||||
"/js/clients/payments/stripe-browserpay.js": "/js/clients/payments/stripe-browserpay.js",
|
||||
"/js/clients/payments/stripe-fpx.js": "/js/clients/payments/stripe-fpx.js",
|
||||
"/css/app.css": "/css/app.css",
|
||||
"/css/card-js.min.css": "/css/card-js.min.css",
|
||||
"/vendor/clipboard.min.js": "/vendor/clipboard.min.js"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user