mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Finish up bunq import routine.
This commit is contained in:
parent
3c9b7c07af
commit
6a6482dc7f
@ -162,9 +162,14 @@ class AccountFactory
|
||||
if ($accountTypeId > 0) {
|
||||
return AccountType::find($accountTypeId);
|
||||
}
|
||||
$type = config('firefly.accountTypeByIdentifier.' . strval($accountType));
|
||||
$type = config('firefly.accountTypeByIdentifier.' . strval($accountType));
|
||||
$result = AccountType::whereType($type)->first();
|
||||
if (is_null($result) && !is_null($accountType)) {
|
||||
// try as full name:
|
||||
$result = AccountType::whereType($accountType)->first();
|
||||
}
|
||||
|
||||
return AccountType::whereType($type)->first();
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class TransactionJournalFactory
|
||||
|
||||
// store date meta fields (if present):
|
||||
$fields = ['sepa-cc', 'sepa-ct-op', 'sepa-ct-id', 'sepa-db', 'sepa-country', 'sepa-ep', 'sepa-ci', 'interest_date', 'book_date', 'process_date',
|
||||
'due_date', 'payment_date', 'invoice_date', 'internal_reference',];
|
||||
'due_date', 'payment_date', 'invoice_date', 'internal_reference','bunq_payment_id'];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$this->storeMeta($journal, $data, $field);
|
||||
|
@ -56,7 +56,7 @@ class TransactionJournalMetaFactory
|
||||
if ($data['data'] instanceof Carbon) {
|
||||
$value = $data['data']->toW3cString();
|
||||
}
|
||||
if (strlen($value) === 0) {
|
||||
if (strlen(strval($value)) === 0) {
|
||||
// don't store blank strings.
|
||||
if (!is_null($entry)) {
|
||||
try {
|
||||
|
@ -26,6 +26,7 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Models\ImportJob;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class StatusController
|
||||
@ -117,6 +118,7 @@ class StatusController extends Controller
|
||||
$result['running'] = true;
|
||||
}
|
||||
$result['percentage'] = $result['percentage'] > 100 ? 100 : $result['percentage'];
|
||||
Log::debug(sprintf('JOB STATUS: %d/%d', $result['done'], $result['steps']));
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ class Installer
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
Log::debug(sprintf('URL is %s, will run installer middleware', $url));
|
||||
// Log::debug(sprintf('URL is %s, will run installer middleware', $url));
|
||||
|
||||
// no tables present?
|
||||
try {
|
||||
|
@ -193,7 +193,7 @@ class BunqConfigurator implements ConfiguratorInterface
|
||||
|
||||
// set default extended status:
|
||||
$extendedStatus = $this->repository->getExtendedStatus($job);
|
||||
$extendedStatus['steps'] = 6;
|
||||
$extendedStatus['steps'] = 8;
|
||||
|
||||
// save to job:
|
||||
$job = $this->repository->setConfiguration($job, $finalConfig);
|
||||
|
@ -23,13 +23,25 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Import\Routine;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\AccountFactory;
|
||||
use FireflyIII\Factory\TransactionJournalFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\ImportJob;
|
||||
use FireflyIII\Models\TransactionJournalMeta;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Services\Bunq\Id\DeviceServerId;
|
||||
use FireflyIII\Services\Bunq\Object\DeviceServer;
|
||||
use FireflyIII\Services\Bunq\Object\LabelMonetaryAccount;
|
||||
use FireflyIII\Services\Bunq\Object\MonetaryAccountBank;
|
||||
use FireflyIII\Services\Bunq\Object\Payment;
|
||||
use FireflyIII\Services\Bunq\Object\ServerPublicKey;
|
||||
use FireflyIII\Services\Bunq\Object\UserCompany;
|
||||
use FireflyIII\Services\Bunq\Object\UserPerson;
|
||||
@ -80,9 +92,14 @@ class BunqRoutine implements RoutineInterface
|
||||
public $journals;
|
||||
/** @var int */
|
||||
public $lines = 0;
|
||||
/** @var AccountFactory */
|
||||
private $accountFactory;
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepository;
|
||||
/** @var ImportJob */
|
||||
private $job;
|
||||
|
||||
/** @var TransactionJournalFactory */
|
||||
private $journalFactory;
|
||||
/** @var ImportJobRepositoryInterface */
|
||||
private $repository;
|
||||
|
||||
@ -140,9 +157,15 @@ class BunqRoutine implements RoutineInterface
|
||||
*/
|
||||
public function setJob(ImportJob $job)
|
||||
{
|
||||
$this->job = $job;
|
||||
$this->repository = app(ImportJobRepositoryInterface::class);
|
||||
$this->job = $job;
|
||||
$this->repository = app(ImportJobRepositoryInterface::class);
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$this->accountFactory = app(AccountFactory::class);
|
||||
$this->journalFactory = app(TransactionJournalFactory::class);
|
||||
$this->repository->setUser($job->user);
|
||||
$this->accountRepository->setUser($job->user);
|
||||
$this->accountFactory->setUser($job->user);
|
||||
$this->journalFactory->setUser($job->user);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,27 +199,13 @@ class BunqRoutine implements RoutineInterface
|
||||
// do nothing in this stage. Job should revert to config routine.
|
||||
break;
|
||||
case 'have-account-mapping':
|
||||
$this->setStatus('running');
|
||||
$this->runStageHaveAccountMapping();
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new FireflyException(sprintf('No action for stage %s!', $stage));
|
||||
break;
|
||||
// case 'has-token':
|
||||
|
||||
// // import routine does nothing at this point:
|
||||
// break;
|
||||
// case 'user-logged-in':
|
||||
// $this->runStageLoggedIn();
|
||||
// break;
|
||||
// case 'have-account-mapping':
|
||||
// $this->runStageHaveMapping();
|
||||
// break;
|
||||
// default:
|
||||
// throw new FireflyException(sprintf('Cannot handle stage %s', $stage));
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,17 +214,18 @@ class BunqRoutine implements RoutineInterface
|
||||
*/
|
||||
protected function runStageInitial()
|
||||
{
|
||||
$this->addStep();
|
||||
Log::debug('In runStageInitial()');
|
||||
$this->setStatus('running');
|
||||
|
||||
// register the device at Bunq:
|
||||
$serverId = $this->registerDevice();
|
||||
$this->addStep();
|
||||
Log::debug(sprintf('Found device server with id %d', $serverId->getId()));
|
||||
|
||||
$config = $this->getConfig();
|
||||
$config['stage'] = 'registered';
|
||||
$this->setConfig($config);
|
||||
$this->addStep();
|
||||
|
||||
return;
|
||||
}
|
||||
@ -227,6 +237,7 @@ class BunqRoutine implements RoutineInterface
|
||||
*/
|
||||
protected function runStageRegistered(): void
|
||||
{
|
||||
$this->addStep();
|
||||
Log::debug('Now in runStageRegistered()');
|
||||
$apiKey = Preferences::getForUser($this->job->user, 'bunq_api_key')->data;
|
||||
$serverPublicKey = Preferences::getForUser($this->job->user, 'bunq_server_public_key')->data;
|
||||
@ -239,7 +250,8 @@ class BunqRoutine implements RoutineInterface
|
||||
$request->call();
|
||||
$this->addStep();
|
||||
|
||||
// todo store objects in job!
|
||||
Log::debug('Requested new session.');
|
||||
|
||||
$deviceSession = $request->getDeviceSessionId();
|
||||
$userPerson = $request->getUserPerson();
|
||||
$userCompany = $request->getUserCompany();
|
||||
@ -254,6 +266,8 @@ class BunqRoutine implements RoutineInterface
|
||||
$this->setConfig($config);
|
||||
$this->addStep();
|
||||
|
||||
Log::debug('Session stored in job.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -262,7 +276,17 @@ class BunqRoutine implements RoutineInterface
|
||||
*/
|
||||
private function addStep()
|
||||
{
|
||||
$this->repository->addStepsDone($this->job, 1);
|
||||
$this->addSteps(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shorthand method.
|
||||
*
|
||||
* @param int $count
|
||||
*/
|
||||
private function addSteps(int $count)
|
||||
{
|
||||
$this->repository->addStepsDone($this->job, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -275,6 +299,71 @@ class BunqRoutine implements RoutineInterface
|
||||
$this->repository->addTotalSteps($this->job, $steps);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $paymentId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function alreadyImported(int $paymentId): bool
|
||||
{
|
||||
$count = TransactionJournalMeta::where('name', 'bunq_payment_id')
|
||||
->where('data', json_encode($paymentId))->count();
|
||||
|
||||
Log::debug(sprintf('Transaction #%d is %d time(s) in the database.', $paymentId, $count));
|
||||
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LabelMonetaryAccount $party
|
||||
* @param string $expectedType
|
||||
*
|
||||
* @return Account
|
||||
*/
|
||||
private function convertToAccount(LabelMonetaryAccount $party, string $expectedType): Account
|
||||
{
|
||||
Log::debug('in convertToAccount()');
|
||||
// find opposing party by IBAN first.
|
||||
$result = $this->accountRepository->findByIbanNull($party->getIban(), [$expectedType]);
|
||||
if (!is_null($result)) {
|
||||
Log::debug(sprintf('Search for %s resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// try to find asset account just in case:
|
||||
if ($expectedType !== AccountType::ASSET) {
|
||||
$result = $this->accountRepository->findByIbanNull($party->getIban(), [AccountType::ASSET]);
|
||||
if (!is_null($result)) {
|
||||
Log::debug(sprintf('Search for Asset "%s" resulted in account %s (#%d)', $party->getIban(), $result->name, $result->id));
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
// create new account:
|
||||
$data = [
|
||||
'user_id' => $this->job->user_id,
|
||||
'iban' => $party->getIban(),
|
||||
'name' => $party->getLabelUser()->getDisplayName(),
|
||||
'account_type_id' => null,
|
||||
'accountType' => $expectedType,
|
||||
'virtualBalance' => null,
|
||||
'active' => true,
|
||||
|
||||
];
|
||||
$account = $this->accountFactory->create($data);
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Converted label monetary account %s to %s account %s (#%d)',
|
||||
$party->getLabelUser()->getDisplayName(),
|
||||
$expectedType,
|
||||
$account->name, $account->id
|
||||
)
|
||||
);
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a new public/private keypair for the user. This isn't really secure, since the key is generated on the fly with
|
||||
* no regards for HSM's, smart cards or other things. It would require some low level programming to get this right. But the private key
|
||||
@ -498,6 +587,144 @@ class BunqRoutine implements RoutineInterface
|
||||
return $this->repository->getStatus($this->job);
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the transactions that were found.
|
||||
*
|
||||
* @param array $payments
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function importPayments(array $payments): void
|
||||
{
|
||||
Log::debug('Going to run importPayments()');
|
||||
$journals = new Collection;
|
||||
$config = $this->getConfig();
|
||||
foreach ($payments as $accountId => $data) {
|
||||
Log::debug(sprintf('Now running for bunq account #%d with %d payment(s).', $accountId, count($data['payments'])));
|
||||
/** @var Payment $payment */
|
||||
foreach ($data['payments'] as $index => $payment) {
|
||||
Log::debug(sprintf('Now at payment #%d with ID #%d', $index, $payment->getId()));
|
||||
// store or find counter party:
|
||||
$counterParty = $payment->getCounterParty();
|
||||
$amount = $payment->getAmount();
|
||||
$paymentId = $payment->getId();
|
||||
if ($this->alreadyImported($paymentId)) {
|
||||
Log::error(sprintf('Already imported bunq payment with id #%d', $paymentId));
|
||||
|
||||
// add three steps to keep up
|
||||
$this->addSteps(3);
|
||||
continue;
|
||||
}
|
||||
Log::debug(sprintf('Amount is %s %s', $amount->getCurrency(), $amount->getValue()));
|
||||
$expected = AccountType::EXPENSE;
|
||||
if (bccomp($amount->getValue(), '0') === 1) {
|
||||
// amount + means that its a deposit.
|
||||
$expected = AccountType::REVENUE;
|
||||
Log::debug('Will make opposing account revenue.');
|
||||
}
|
||||
$opposing = $this->convertToAccount($counterParty, $expected);
|
||||
$account = $this->accountRepository->findNull($config['accounts-mapped'][$accountId]);
|
||||
$type = TransactionType::WITHDRAWAL;
|
||||
|
||||
$this->addStep();
|
||||
|
||||
Log::debug(sprintf('Will store withdrawal between "%s" (%d) and "%s" (%d)', $account->name, $account->id, $opposing->name, $opposing->id));
|
||||
|
||||
// start storing stuff:
|
||||
$source = $account;
|
||||
$destination = $opposing;
|
||||
if (bccomp($amount->getValue(), '0') === 1) {
|
||||
// its a deposit:
|
||||
$source = $opposing;
|
||||
$destination = $account;
|
||||
$type = TransactionType::DEPOSIT;
|
||||
Log::debug('Will make it a deposit.');
|
||||
}
|
||||
if ($account->accountType->type === AccountType::ASSET && $opposing->accountType->type === AccountType::ASSET) {
|
||||
$type = TransactionType::TRANSFER;
|
||||
Log::debug('Both are assets, will make transfer.');
|
||||
}
|
||||
|
||||
$storeData = [
|
||||
'user' => $this->job->user_id,
|
||||
'type' => $type,
|
||||
'date' => $payment->getCreated(),
|
||||
'description' => $payment->getDescription(),
|
||||
'piggy_bank_id' => null,
|
||||
'piggy_bank_name' => null,
|
||||
'bill_id' => null,
|
||||
'bill_name' => null,
|
||||
'tags' => [$payment->getType(), $payment->getSubType()],
|
||||
'internal_reference' => $payment->getId(),
|
||||
'notes' => null,
|
||||
'bunq_payment_id' => $payment->getId(),
|
||||
'transactions' => [
|
||||
// single transaction:
|
||||
[
|
||||
'description' => null,
|
||||
'amount' => $amount->getValue(),
|
||||
'currency_id' => null,
|
||||
'currency_code' => $amount->getCurrency(),
|
||||
'foreign_amount' => null,
|
||||
'foreign_currency_id' => null,
|
||||
'foreign_currency_code' => null,
|
||||
'budget_id' => null,
|
||||
'budget_name' => null,
|
||||
'category_id' => null,
|
||||
'category_name' => null,
|
||||
'source_id' => $source->id,
|
||||
'source_name' => null,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_name' => null,
|
||||
'reconciled' => false,
|
||||
'identifier' => 0,
|
||||
],
|
||||
],
|
||||
];
|
||||
$journal = $this->journalFactory->create($storeData);
|
||||
Log::debug(sprintf('Stored journal with ID #%d', $journal->id));
|
||||
$this->addStep();
|
||||
$journals->push($journal);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// link to tag
|
||||
/** @var TagRepositoryInterface $repository */
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
$repository->setUser($this->job->user);
|
||||
$data = [
|
||||
'tag' => trans('import.import_with_key', ['key' => $this->job->key]),
|
||||
'date' => new Carbon,
|
||||
'description' => null,
|
||||
'latitude' => null,
|
||||
'longitude' => null,
|
||||
'zoomLevel' => null,
|
||||
'tagMode' => 'nothing',
|
||||
];
|
||||
$tag = $repository->store($data);
|
||||
$extended = $this->getExtendedStatus();
|
||||
$extended['tag'] = $tag->id;
|
||||
$this->setExtendedStatus($extended);
|
||||
|
||||
Log::debug(sprintf('Created tag #%d ("%s")', $tag->id, $tag->tag));
|
||||
Log::debug('Looping journals...');
|
||||
$tagId = $tag->id;
|
||||
|
||||
foreach ($journals as $journal) {
|
||||
Log::debug(sprintf('Linking journal #%d to tag #%d...', $journal->id, $tagId));
|
||||
DB::table('tag_transaction_journal')->insert(['transaction_journal_id' => $journal->id, 'tag_id' => $tagId]);
|
||||
$this->addStep();
|
||||
}
|
||||
Log::info(sprintf('Linked %d journals to tag #%d ("%s")', $journals->count(), $tag->id, $tag->tag));
|
||||
|
||||
// set status to "finished"?
|
||||
// update job:
|
||||
$this->setStatus('finished');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* To install Firefly III as a new device:
|
||||
* - Send an installation token request.
|
||||
@ -576,13 +803,17 @@ class BunqRoutine implements RoutineInterface
|
||||
$count = 0;
|
||||
if (0 === $user->getId()) {
|
||||
$user = new UserCompany($config['user_company']);
|
||||
Log::debug(sprintf('Will try to get transactions for company #%d', $user->getId()));
|
||||
}
|
||||
|
||||
$this->addTotalSteps(count($config['accounts']) * 2);
|
||||
|
||||
foreach ($config['accounts'] as $accountData) {
|
||||
$this->addStep();
|
||||
$account = new MonetaryAccountBank($accountData);
|
||||
$importId = $account->getId();
|
||||
if (1 === $mapping[$importId]) {
|
||||
// grab all transactions
|
||||
Log::debug(sprintf('Will grab payments for account %s', $account->getDescription()));
|
||||
$request = new ListPaymentRequest();
|
||||
$request->setPrivateKey($this->getPrivateKey());
|
||||
$request->setServerPublicKey($this->getServerPublicKey());
|
||||
@ -590,22 +821,24 @@ class BunqRoutine implements RoutineInterface
|
||||
$request->setUserId($user->getId());
|
||||
$request->setAccount($account);
|
||||
$request->call();
|
||||
|
||||
exit;
|
||||
$payments = $request->getPayments();
|
||||
|
||||
// store in array
|
||||
$all[$account->getId()] = [
|
||||
'account' => $account,
|
||||
'import_id' => $importId,
|
||||
'transactions' => $transactions,
|
||||
'account' => $account,
|
||||
'import_id' => $importId,
|
||||
'payments' => $payments,
|
||||
];
|
||||
$count += count($transactions);
|
||||
$count += count($payments);
|
||||
}
|
||||
Log::debug(sprintf('Total number of transactions: %d', $count));
|
||||
Log::debug(sprintf('Total number of payments: %d', $count));
|
||||
$this->addStep();
|
||||
//$this->importTransactions($all);
|
||||
// add steps for import:
|
||||
$this->addTotalSteps($count * 3);
|
||||
$this->importPayments($all);
|
||||
}
|
||||
exit;
|
||||
|
||||
// update job to be complete, I think?
|
||||
}
|
||||
|
||||
/**
|
||||
@ -613,6 +846,7 @@ class BunqRoutine implements RoutineInterface
|
||||
*/
|
||||
private function runStageLoggedIn(): void
|
||||
{
|
||||
$this->addStep();
|
||||
// grab new session token:
|
||||
$config = $this->getConfig();
|
||||
$token = new SessionToken($config['session_token']);
|
||||
@ -631,6 +865,7 @@ class BunqRoutine implements RoutineInterface
|
||||
$accounts = $request->getMonetaryAccounts();
|
||||
$arr = [];
|
||||
Log::debug(sprintf('Get monetary accounts, found %d accounts.', $accounts->count()));
|
||||
$this->addStep();
|
||||
|
||||
/** @var MonetaryAccountBank $account */
|
||||
foreach ($accounts as $account) {
|
||||
@ -645,6 +880,7 @@ class BunqRoutine implements RoutineInterface
|
||||
// once the accounts are stored, go to configuring stage:
|
||||
// update job, set status to "configuring".
|
||||
$this->setStatus('configuring');
|
||||
$this->addStep();
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -302,4 +302,5 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ interface AccountRepositoryInterface
|
||||
* @param string $number
|
||||
* @param array $types
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
public function findByAccountNumber(string $number, array $types): Account;
|
||||
@ -74,14 +75,24 @@ interface AccountRepositoryInterface
|
||||
* @param string $iban
|
||||
* @param array $types
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
public function findByIban(string $iban, array $types): Account;
|
||||
|
||||
/**
|
||||
* @param string $iban
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByIbanNull(string $iban, array $types): ?Account;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $types
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByName(string $name, array $types): ?Account;
|
||||
|
@ -41,6 +41,7 @@ trait FindAccountsTrait
|
||||
/**
|
||||
* @param $accountId
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
public function find(int $accountId): Account
|
||||
@ -58,6 +59,7 @@ trait FindAccountsTrait
|
||||
* @param string $number
|
||||
* @param array $types
|
||||
*
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account
|
||||
*/
|
||||
@ -109,10 +111,37 @@ trait FindAccountsTrait
|
||||
return new Account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $iban
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByIbanNull(string $iban, array $types): ?Account
|
||||
{
|
||||
$query = $this->user->accounts()->where('iban', '!=', '')->whereNotNull('iban');
|
||||
|
||||
if (count($types) > 0) {
|
||||
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$query->whereIn('account_types.type', $types);
|
||||
}
|
||||
|
||||
$accounts = $query->get(['accounts.*']);
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
if ($account->iban === $iban) {
|
||||
return $account;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $types
|
||||
*
|
||||
* @deprecated
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByName(string $name, array $types): ?Account
|
||||
|
@ -311,19 +311,11 @@ class ImportJobRepository implements ImportJobRepositoryInterface
|
||||
*/
|
||||
public function setExtendedStatus(ImportJob $job, array $array): ImportJob
|
||||
{
|
||||
// remove 'errors' because it gets larger and larger and larger...
|
||||
$display = $array;
|
||||
unset($display['errors']);
|
||||
Log::debug(sprintf('Incoming extended status for job "%s" is (except errors): ', $job->key), $display);
|
||||
$currentStatus = $job->extended_status;
|
||||
$newStatus = array_merge($currentStatus, $array);
|
||||
$job->extended_status = $newStatus;
|
||||
$job->save();
|
||||
|
||||
// remove 'errors' because it gets larger and larger and larger...
|
||||
unset($newStatus['errors']);
|
||||
Log::debug(sprintf('Set extended status of job "%s" to (except errors): ', $job->key), $newStatus);
|
||||
|
||||
return $job;
|
||||
}
|
||||
|
||||
|
@ -27,4 +27,30 @@ namespace FireflyIII\Services\Bunq\Object;
|
||||
*/
|
||||
class Avatar extends BunqObject
|
||||
{
|
||||
/** @var string */
|
||||
private $anchorUuid;
|
||||
/** @var Image */
|
||||
private $image;
|
||||
/** @var string */
|
||||
private $uuid;
|
||||
|
||||
/**
|
||||
* Avatar constructor.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->uuid = $data['uuid'];
|
||||
$this->anchorUuid = $data['anchor_uuid'];
|
||||
$this->image = new Image($data['image']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,12 @@ namespace FireflyIII\Services\Bunq\Object;
|
||||
/**
|
||||
* Class BunqObject.
|
||||
*/
|
||||
class BunqObject
|
||||
abstract class BunqObject
|
||||
{
|
||||
/**
|
||||
* Convert this object to array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function toArray(): array;
|
||||
}
|
||||
|
@ -75,4 +75,12 @@ class DeviceServer extends BunqObject
|
||||
{
|
||||
return $this->ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
62
app/Services/Bunq/Object/Image.php
Normal file
62
app/Services/Bunq/Object/Image.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Image.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Services\Bunq\Object;
|
||||
|
||||
|
||||
/**
|
||||
* Class Image
|
||||
*/
|
||||
class Image extends BunqObject
|
||||
{
|
||||
/** @var string */
|
||||
private $attachmentPublicUuid;
|
||||
/** @var string */
|
||||
private $contentType;
|
||||
/** @var int */
|
||||
private $height;
|
||||
/** @var int */
|
||||
private $width;
|
||||
|
||||
/**
|
||||
* Image constructor.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->attachmentPublicUuid = $data['attachment_public_uuid'] ?? null;
|
||||
$this->height = $data['height'] ?? null;
|
||||
$this->width = $data['width'] ?? null;
|
||||
$this->contentType = $data['content_type'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
|
||||
}
|
@ -29,5 +29,54 @@ namespace FireflyIII\Services\Bunq\Object;
|
||||
*/
|
||||
class LabelMonetaryAccount extends BunqObject
|
||||
{
|
||||
/** @var Avatar */
|
||||
private $avatar;
|
||||
/** @var string */
|
||||
private $country;
|
||||
/** @var string */
|
||||
private $iban;
|
||||
/** @var bool */
|
||||
private $isLight;
|
||||
/** @var LabelUser */
|
||||
private $labelUser;
|
||||
|
||||
/**
|
||||
* @return LabelUser
|
||||
*/
|
||||
public function getLabelUser(): LabelUser
|
||||
{
|
||||
return $this->labelUser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* LabelMonetaryAccount constructor.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->iban = $data['iban'];
|
||||
$this->isLight = $data['is_light'];
|
||||
$this->avatar = new Avatar($data['avatar']);
|
||||
$this->labelUser = new LabelUser($data['label_user']);
|
||||
$this->country = $data['country'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIban(): string
|
||||
{
|
||||
return $this->iban;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
|
||||
}
|
||||
|
90
app/Services/Bunq/Object/LabelUser.php
Normal file
90
app/Services/Bunq/Object/LabelUser.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* LabelUser.php
|
||||
* Copyright (c) 2018 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III.
|
||||
*
|
||||
* Firefly III is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Firefly III is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Services\Bunq\Object;
|
||||
|
||||
|
||||
/**
|
||||
* Class LabelUser
|
||||
*/
|
||||
class LabelUser extends BunqObject
|
||||
{
|
||||
/** @var Avatar */
|
||||
private $avatar;
|
||||
/** @var string */
|
||||
private $country;
|
||||
/** @var string */
|
||||
private $displayName;
|
||||
/** @var string */
|
||||
private $publicNickName;
|
||||
/** @var string */
|
||||
private $uuid;
|
||||
|
||||
/**
|
||||
* @return Avatar
|
||||
*/
|
||||
public function getAvatar(): Avatar
|
||||
{
|
||||
return $this->avatar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
return $this->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPublicNickName(): string
|
||||
{
|
||||
return $this->publicNickName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* LabelUser constructor.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->uuid = $data['uuid'];
|
||||
$this->displayName = $data['display_name'];
|
||||
$this->country = $data['country'];
|
||||
$this->publicNickName = $data['public_nick_name'];
|
||||
$this->avatar = new Avatar($data['avatar']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Services\Bunq\Object;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
||||
|
||||
@ -30,28 +31,30 @@ use Carbon\Carbon;
|
||||
*/
|
||||
class Payment extends BunqObject
|
||||
{
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var Carbon */
|
||||
private $created;
|
||||
/** @var Carbon */
|
||||
private $updated;
|
||||
/** @var int */
|
||||
private $monetaryAccountId;
|
||||
/** @var LabelMonetaryAccount */
|
||||
private $alias;
|
||||
/** @var Amount */
|
||||
private $amount;
|
||||
/** @var string */
|
||||
private $description;
|
||||
/** @var string */
|
||||
private $type;
|
||||
/** @var string */
|
||||
private $merchantReference;
|
||||
/** @var LabelMonetaryAccount */
|
||||
private $counterParty;
|
||||
/** @var array */
|
||||
private $attachments = [];
|
||||
/** @var LabelMonetaryAccount */
|
||||
private $counterParty;
|
||||
/** @var Carbon */
|
||||
private $created;
|
||||
/** @var string */
|
||||
private $description;
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var string */
|
||||
private $merchantReference;
|
||||
/** @var int */
|
||||
private $monetaryAccountId;
|
||||
/** @var string */
|
||||
private $subType;
|
||||
/** @var string */
|
||||
private $type;
|
||||
/** @var Carbon */
|
||||
private $updated;
|
||||
|
||||
/**
|
||||
* Payment constructor.
|
||||
@ -60,11 +63,81 @@ class Payment extends BunqObject
|
||||
*/
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->id = $data['id'];
|
||||
$this->created = new Carbon();
|
||||
$this->id = $data['id'];
|
||||
$this->created = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['created']);
|
||||
$this->updated = Carbon::createFromFormat('Y-m-d H:i:s.u', $data['updated']);
|
||||
$this->monetaryAccountId = (int)$data['monetary_account_id'];
|
||||
$this->amount = new Amount($data['amount']);
|
||||
$this->description = $data['description'];
|
||||
$this->type = $data['type'];
|
||||
$this->merchantReference = $data['merchant_reference'];
|
||||
$this->alias = new LabelMonetaryAccount($data['alias']);
|
||||
$this->counterParty = new LabelMonetaryAccount($data['counterparty_alias']);
|
||||
$this->subType = $data['sub_type'];
|
||||
}
|
||||
|
||||
var_dump($data);
|
||||
exit;
|
||||
/**
|
||||
* @return Amount
|
||||
*/
|
||||
public function getAmount(): Amount
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return LabelMonetaryAccount|null
|
||||
*/
|
||||
public function getCounterParty(): ?LabelMonetaryAccount
|
||||
{
|
||||
return $this->counterParty;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Carbon
|
||||
*/
|
||||
public function getCreated(): Carbon
|
||||
{
|
||||
return $this->created;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getId(): int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSubType(): string
|
||||
{
|
||||
return $this->subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,4 +55,12 @@ class ServerPublicKey extends BunqObject
|
||||
{
|
||||
$this->publicKey = $publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
@ -74,4 +74,12 @@ class UserLight extends BunqObject
|
||||
$this->legalName = $data['legal_name'];
|
||||
// aliases
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
die(sprintf('Cannot convert %s to array.', get_class($this)));
|
||||
}
|
||||
}
|
||||
|
@ -48,14 +48,9 @@ class DeviceServerRequest extends BunqRequest
|
||||
Log::debug('Now in DeviceServerRequest::call()');
|
||||
$uri = 'device-server';
|
||||
$data = ['description' => $this->description, 'secret' => $this->secret, 'permitted_ips' => $this->permittedIps];
|
||||
|
||||
Log::debug('Data we send along: ', $data);
|
||||
|
||||
$headers = $this->getDefaultHeaders();
|
||||
$headers['X-Bunq-Client-Authentication'] = $this->installationToken->getToken();
|
||||
|
||||
Log::debug('Headers we send along: ', $headers);
|
||||
|
||||
$response = $this->sendSignedBunqPost($uri, $data, $headers);
|
||||
$deviceServerId = new DeviceServerId;
|
||||
$deviceServerId->setId(intval($response['Response'][0]['Id']['id']));
|
||||
|
@ -51,24 +51,36 @@ class ListPaymentRequest extends BunqRequest
|
||||
*/
|
||||
public function call(): void
|
||||
{
|
||||
$break = false;
|
||||
$this->payments = new Collection;
|
||||
$uri = sprintf('user/%d/monetary-account/%d/payment', $this->userId, $this->account->getId());
|
||||
$data = [];
|
||||
$headers = $this->getDefaultHeaders();
|
||||
$headers['X-Bunq-Client-Authentication'] = $this->sessionToken->getToken();
|
||||
$response = $this->sendSignedBunqGet($uri, $data, $headers);
|
||||
while ($break === false) {
|
||||
$response = $this->sendSignedBunqGet($uri, [], $headers);
|
||||
$uri = str_replace('/v1/', '', $response['Pagination']['future_url']);
|
||||
$break = true;
|
||||
|
||||
// create payment objects:
|
||||
$raw = $this->getArrayFromResponse('Payment', $response);
|
||||
foreach ($raw as $entry) {
|
||||
$account = new Payment($entry);
|
||||
$this->payments->push($account);
|
||||
// create payment objects:
|
||||
$raw = $this->getArrayFromResponse('Payment', $response);
|
||||
foreach ($raw as $entry) {
|
||||
$payment = new Payment($entry);
|
||||
$this->payments->push($payment);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPayments(): Collection
|
||||
{
|
||||
return $this->payments;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param MonetaryAccountBank $account
|
||||
*/
|
||||
|
@ -163,6 +163,9 @@ return [
|
||||
// bunq
|
||||
'bunq_prerequisites_title' => 'Prerequisites for an import from bunq',
|
||||
'bunq_prerequisites_text' => 'In order to import from bunq, you need to obtain an API key. You can do this through the app.',
|
||||
'bunq_do_import' => 'Yes, import from this account',
|
||||
'bunq_accounts_title' => 'Bunq accounts',
|
||||
'bunq_accounts_text' => 'These are the accounts associated with your bunq account. Please select the accounts from which you want to import, and in which account the transactions must be imported.',
|
||||
|
||||
// Spectre
|
||||
'spectre_title' => 'Import using Spectre',
|
||||
|
@ -110,4 +110,5 @@ return [
|
||||
'sepa-cc' => 'SEPA Clearing Code',
|
||||
'sepa-ep' => 'SEPA External Purpose',
|
||||
'sepa-ci' => 'SEPA Creditor Identifier',
|
||||
'account_at_bunq' => 'Account with bunq',
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user