mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
A new endpoint that allows you to search for transfers.
This commit is contained in:
parent
6823adc976
commit
8b11afb83f
116
app/Api/V1/Controllers/Search/TransferController.php
Normal file
116
app/Api/V1/Controllers/Search/TransferController.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferController.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Search;
|
||||
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Search\TransferRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Support\Search\TransferSearch;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
|
||||
/**
|
||||
* Class TransferController
|
||||
*/
|
||||
class TransferController extends Controller
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
*
|
||||
* @return JsonResponse|Response
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function search(TransferRequest $request)
|
||||
{
|
||||
// configure transfer search to search for a > b
|
||||
$search = app(TransferSearch::class);
|
||||
$search->setSource($request->get('source'));
|
||||
$search->setDestination($request->get('destination'));
|
||||
$search->setAmount($request->get('amount'));
|
||||
$search->setDescription($request->get('description'));
|
||||
$search->setDate($request->get('date'));
|
||||
|
||||
$left = $search->search();
|
||||
|
||||
// configure transfer search to search for b > a
|
||||
$search->setSource($request->get('destination'));
|
||||
$search->setDestination($request->get('source'));
|
||||
$search->setAmount($request->get('amount'));
|
||||
$search->setDescription($request->get('description'));
|
||||
$search->setDate($request->get('date'));
|
||||
|
||||
$right = $search->search();
|
||||
|
||||
// add parameters to URL:
|
||||
$this->parameters->set('source', $request->get('source'));
|
||||
$this->parameters->set('destination', $request->get('destination'));
|
||||
$this->parameters->set('amount', $request->get('amount'));
|
||||
$this->parameters->set('description', $request->get('description'));
|
||||
$this->parameters->set('date', $request->get('date'));
|
||||
|
||||
// get all journal ID's.
|
||||
$total = $left->merge($right)->unique('id')->pluck('id')->toArray();
|
||||
if (0 === count($total)) {
|
||||
// forces search to be empty.
|
||||
$total = [-1];
|
||||
}
|
||||
|
||||
// collector to return results.
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$manager = $this->getManager();
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector
|
||||
->setUser($admin)
|
||||
// all info needed for the API:
|
||||
->withAPIInformation()
|
||||
// set page size:
|
||||
->setLimit($pageSize)
|
||||
// set page to retrieve
|
||||
->setPage(1)
|
||||
->setJournalIds($total);
|
||||
|
||||
$paginator = $collector->getPaginatedGroups();
|
||||
$paginator->setPath(route('api.v1.search.transfers') . $this->buildParams());
|
||||
$transactions = $paginator->getCollection();
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
}
|
58
app/Api/V1/Requests/Search/TransferRequest.php
Normal file
58
app/Api/V1/Requests/Search/TransferRequest.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferRequest.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Search;
|
||||
|
||||
|
||||
use FireflyIII\Api\V1\Requests\Request;
|
||||
use FireflyIII\Rules\IsTransferAccount;
|
||||
|
||||
/**
|
||||
* Class TransferRequest
|
||||
*/
|
||||
class TransferRequest extends Request
|
||||
{
|
||||
/**
|
||||
* Authorize logged in users.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'source' => ['required', new IsTransferAccount],
|
||||
'destination' => ['required', new IsTransferAccount],
|
||||
'amount' => 'required|numeric|more:0',
|
||||
'description' => 'required|min:1',
|
||||
'date' => 'required|date',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
73
app/Rules/IsTransferAccount.php
Normal file
73
app/Rules/IsTransferAccount.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* IsTransferAccount.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Rules;
|
||||
|
||||
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Validation\AccountValidator;
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class IsTransferAccount
|
||||
*/
|
||||
class IsTransferAccount implements Rule
|
||||
{
|
||||
/**
|
||||
* Get the validation error message.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function message(): string
|
||||
{
|
||||
return (string)trans('validation.not_transfer_account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value): bool
|
||||
{
|
||||
Log::debug(sprintf('Now in %s(%s)', __METHOD__, $value));
|
||||
/** @var AccountValidator $validator */
|
||||
$validator = app(AccountValidator::class);
|
||||
$validator->setTransactionType(TransactionType::TRANSFER);
|
||||
$validator->setUser(auth()->user());
|
||||
|
||||
$validAccount = $validator->validateSource(null, (string)$value);
|
||||
if (true === $validAccount) {
|
||||
Log::debug('Found account based on name. Return true.');
|
||||
|
||||
// found by name, use repos to return.
|
||||
return true;
|
||||
}
|
||||
$validAccount = $validator->validateSource((int)$value, null);
|
||||
Log::debug(sprintf('Search by id (%d), result is %s.', (int)$value, var_export($validAccount, true)));
|
||||
|
||||
return !(false === $validAccount);
|
||||
}
|
||||
}
|
@ -22,7 +22,16 @@
|
||||
namespace FireflyIII\Support\Search;
|
||||
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* Interface GenericSearchInterface
|
||||
*/
|
||||
interface GenericSearchInterface
|
||||
{
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function search(): Collection;
|
||||
|
||||
}
|
147
app/Support/Search/TransferSearch.php
Normal file
147
app/Support/Search/TransferSearch.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* TransferSearch.php
|
||||
* Copyright (c) 2019 thegrumpydictator@gmail.com
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Support\Search;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Collection;
|
||||
use InvalidArgumentException;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class TransferSearch
|
||||
*/
|
||||
class TransferSearch implements GenericSearchInterface
|
||||
{
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepository;
|
||||
/** @var string */
|
||||
private $amount;
|
||||
/** @var Carbon */
|
||||
private $date;
|
||||
/** @var string */
|
||||
private $description;
|
||||
/** @var Account */
|
||||
private $destination;
|
||||
/** @var Account */
|
||||
private $source;
|
||||
/** @var array */
|
||||
private $types;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$this->types = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function search(): Collection
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
|
||||
$query = $user->transactionJournals()
|
||||
->leftJoin(
|
||||
'transactions as source', static function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'source.transaction_journal_id');
|
||||
$join->where('source.amount', '<', '0');
|
||||
}
|
||||
)
|
||||
->leftJoin(
|
||||
'transactions as destination', static function (JoinClause $join) {
|
||||
$join->on('transaction_journals.id', '=', 'destination.transaction_journal_id');
|
||||
$join->where('destination.amount', '>', '0');
|
||||
}
|
||||
)
|
||||
->where('source.account_id', $this->source->id)
|
||||
->where('destination.account_id', $this->destination->id)
|
||||
->where('transaction_journals.description', $this->description)
|
||||
->where('destination.amount', $this->amount)
|
||||
->where('transaction_journals.date', $this->date->format('Y-m-d 00:00:00'))
|
||||
;
|
||||
|
||||
return $query->get(['transaction_journals.id', 'transaction_journals.transaction_group_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $amount
|
||||
*/
|
||||
public function setAmount(string $amount): void
|
||||
{
|
||||
$this->amount = $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $date
|
||||
*/
|
||||
public function setDate(string $date): void
|
||||
{
|
||||
try {
|
||||
$carbon = Carbon::createFromFormat('Y-m-d', $date);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$carbon = Carbon::now();
|
||||
}
|
||||
$this->date = $carbon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $description
|
||||
*/
|
||||
public function setDescription(string $description): void
|
||||
{
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $destination
|
||||
*/
|
||||
public function setDestination(string $destination): void
|
||||
{
|
||||
if (is_numeric($destination)) {
|
||||
$this->destination = $this->accountRepository->findNull((int)$destination);
|
||||
}
|
||||
if (null === $this->destination) {
|
||||
$this->destination = $this->accountRepository->findByName($destination, $this->types);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $source
|
||||
*/
|
||||
public function setSource(string $source): void
|
||||
{
|
||||
if (is_numeric($source)) {
|
||||
$this->source = $this->accountRepository->findNull((int)$source);
|
||||
}
|
||||
if (null === $this->source) {
|
||||
$this->source = $this->accountRepository->findByName($source, $this->types);
|
||||
}
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ return [
|
||||
'at_least_one_repetition' => 'Need at least one repetition.',
|
||||
'require_repeat_until' => 'Require either a number of repetitions, or an end date (repeat_until). Not both.',
|
||||
'require_currency_info' => 'The content of this field is invalid without currency information.',
|
||||
'not_transfer_account' => 'This account is not an account that can be used for transfers.',
|
||||
'require_currency_amount' => 'The content of this field is invalid without foreign amount information.',
|
||||
'equal_description' => 'Transaction description should not equal global description.',
|
||||
'file_invalid_mime' => 'File ":name" is of type ":mime" which is not accepted as a new upload.',
|
||||
|
@ -342,6 +342,7 @@ Route::group(
|
||||
// Attachment API routes:
|
||||
Route::get('transactions', ['uses' => 'TransactionController@search', 'as' => 'transactions']);
|
||||
Route::get('accounts', ['uses' => 'AccountController@search', 'as' => 'accounts']);
|
||||
Route::get('transfers', ['uses' => 'TransferController@search', 'as' => 'transfers']);
|
||||
}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user