mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-01-23 23:13:18 -06:00
Expand API for recurring transactions.
This commit is contained in:
parent
8e4092e7d7
commit
f0de469053
@ -24,9 +24,17 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\RecurrenceRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||
use FireflyIII\Helpers\Filter\InternalTransferFilter;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Cronjobs\RecurringCronjob;
|
||||
use FireflyIII\Support\Http\Api\Transactions;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\Transformers\TransactionTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@ -36,12 +44,14 @@ use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection as FractalCollection;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\JsonApiSerializer;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class RecurrenceController
|
||||
*/
|
||||
class RecurrenceController extends Controller
|
||||
{
|
||||
use Transactions;
|
||||
/** @var RecurringRepositoryInterface The recurring transaction repository */
|
||||
private $repository;
|
||||
|
||||
@ -156,6 +166,79 @@ class RecurrenceController extends Controller
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show transactions for this recurrence.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function transactions(Request $request, Recurrence $recurrence): JsonResponse
|
||||
{
|
||||
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
|
||||
$type = $request->get('type') ?? 'default';
|
||||
$this->parameters->set('type', $type);
|
||||
|
||||
$types = $this->mapTypes($this->parameters->get('type'));
|
||||
$manager = new Manager();
|
||||
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
|
||||
$manager->setSerializer(new JsonApiSerializer($baseUrl));
|
||||
|
||||
// whatever is returned by the query, it must be part of these journals:
|
||||
$journalIds = $this->repository->getJournalIds($recurrence);
|
||||
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
/** @var TransactionCollectorInterface $collector */
|
||||
$collector = app(TransactionCollectorInterface::class);
|
||||
$collector->setUser($admin);
|
||||
$collector->withOpposingAccount()->withCategoryInformation()->withBudgetInformation();
|
||||
$collector->setAllAssetAccounts();
|
||||
$collector->setJournalIds($journalIds);
|
||||
|
||||
if (\in_array(TransactionType::TRANSFER, $types, true)) {
|
||||
$collector->removeFilter(InternalTransferFilter::class);
|
||||
}
|
||||
|
||||
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
|
||||
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
|
||||
}
|
||||
$collector->setLimit($pageSize)->setPage($this->parameters->get('page'));
|
||||
$collector->setTypes($types);
|
||||
$paginator = $collector->getPaginatedTransactions();
|
||||
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
|
||||
$transactions = $paginator->getCollection();
|
||||
$repository = app(JournalRepositoryInterface::class);
|
||||
|
||||
$resource = new FractalCollection($transactions, new TransactionTransformer($this->parameters, $repository), 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function trigger(): JsonResponse
|
||||
{
|
||||
$recurring = new RecurringCronjob;
|
||||
try {
|
||||
$result = $recurring->fire();
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
throw new FireflyException('Could not fire recurring cron job.');
|
||||
}
|
||||
if (false === $result) {
|
||||
return response()->json([], 204);
|
||||
}
|
||||
if (true === $result) {
|
||||
return response()->json([], 200);
|
||||
}
|
||||
throw new FireflyException('Could not fire recurring cron job.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update single recurrence.
|
||||
*
|
||||
|
@ -25,6 +25,7 @@ namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Rules\BelongsUser;
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Validation\RecurrenceValidation;
|
||||
use FireflyIII\Validation\TransactionValidation;
|
||||
use Illuminate\Validation\Validator;
|
||||
@ -54,6 +55,14 @@ class RecurrenceRequest extends Request
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$active = true;
|
||||
$applyRules = true;
|
||||
if (null !== $this->get('active')) {
|
||||
$active = $this->boolean('active');
|
||||
}
|
||||
if (null !== $this->get('apply_rules')) {
|
||||
$applyRules = $this->boolean('apply_rules');
|
||||
}
|
||||
$return = [
|
||||
'recurrence' => [
|
||||
'type' => $this->string('type'),
|
||||
@ -62,8 +71,8 @@ class RecurrenceRequest extends Request
|
||||
'first_date' => $this->date('first_date'),
|
||||
'repeat_until' => $this->date('repeat_until'),
|
||||
'repetitions' => $this->integer('nr_of_repetitions'),
|
||||
'apply_rules' => $this->boolean('apply_rules'),
|
||||
'active' => $this->boolean('active'),
|
||||
'apply_rules' => $applyRules,
|
||||
'active' => $active,
|
||||
],
|
||||
'meta' => [
|
||||
'piggy_bank_id' => $this->integer('piggy_bank_id'),
|
||||
@ -93,8 +102,8 @@ class RecurrenceRequest extends Request
|
||||
'first_date' => sprintf('required|date|after:%s', $today->format('Y-m-d')),
|
||||
'repeat_until' => sprintf('date|after:%s', $today->format('Y-m-d')),
|
||||
'nr_of_repetitions' => 'numeric|between:1,31',
|
||||
'apply_rules' => 'required|boolean',
|
||||
'active' => 'required|boolean',
|
||||
'apply_rules' => [new IsBoolean],
|
||||
'active' => [new IsBoolean],
|
||||
'tags' => 'between:1,64000',
|
||||
'piggy_bank_id' => 'numeric',
|
||||
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
|
||||
|
@ -527,6 +527,22 @@ class TransactionCollector implements TransactionCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $journalIds
|
||||
*
|
||||
* @return TransactionCollectorInterface
|
||||
*/
|
||||
public function setJournalIds(array $journalIds): TransactionCollectorInterface
|
||||
{
|
||||
$this->query->where(
|
||||
function (EloquentBuilder $q) use ($journalIds) {
|
||||
$q->whereIn('transaction_journals.id', $journalIds);
|
||||
}
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $journals
|
||||
*
|
||||
|
@ -82,13 +82,6 @@ interface TransactionCollectorInterface
|
||||
*/
|
||||
public function count(): int;
|
||||
|
||||
/**
|
||||
* Get all transactions.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTransactions(): Collection;
|
||||
|
||||
/**
|
||||
* Get a paginated result.
|
||||
*
|
||||
@ -103,6 +96,13 @@ interface TransactionCollectorInterface
|
||||
*/
|
||||
public function getQuery(): EloquentBuilder;
|
||||
|
||||
/**
|
||||
* Get all transactions.
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function getTransactions(): Collection;
|
||||
|
||||
/**
|
||||
* Set to ignore the cache.
|
||||
*
|
||||
@ -198,6 +198,15 @@ interface TransactionCollectorInterface
|
||||
*/
|
||||
public function setCategory(Category $category): TransactionCollectorInterface;
|
||||
|
||||
/**
|
||||
* Set the journal IDs to filter on.
|
||||
*
|
||||
* @param array $journalIds
|
||||
*
|
||||
* @return TransactionCollectorInterface
|
||||
*/
|
||||
public function setJournalIds(array $journalIds): TransactionCollectorInterface;
|
||||
|
||||
/**
|
||||
* Set the journals to filter on.
|
||||
*
|
||||
|
@ -175,6 +175,22 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
return $query->get(['transaction_journals.*'])->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get journal ID's for journals created by this recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJournalIds(Recurrence $recurrence): array
|
||||
{
|
||||
return TransactionJournalMeta::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id')
|
||||
->where('transaction_journals.user_id', $this->user->id)
|
||||
->where('journal_meta.name', '=', 'recurrence_id')
|
||||
->where('journal_meta.data', '=', json_encode((string)$recurrence->id))
|
||||
->get(['journal_meta.transaction_journal_id'])->pluck('transaction_journal_id')->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notes.
|
||||
*
|
||||
@ -500,6 +516,8 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences.
|
||||
*
|
||||
@ -528,6 +546,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences.
|
||||
*
|
||||
@ -575,6 +594,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences.
|
||||
*
|
||||
@ -607,7 +627,6 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences.
|
||||
*
|
||||
@ -652,6 +671,8 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
return $return;
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Calculates the number of daily occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
|
||||
* over $skipMod -1 recurrences.
|
||||
@ -681,6 +702,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Calculates the number of monthly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
|
||||
* over $skipMod -1 recurrences.
|
||||
@ -720,6 +742,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Calculates the number of NDOM occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
|
||||
* over $skipMod -1 recurrences.
|
||||
@ -759,6 +782,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Calculates the number of weekly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
|
||||
* over $skipMod -1 recurrences.
|
||||
@ -802,6 +826,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* Calculates the number of yearly occurrences for a recurring transaction, starting at the date, until $count is reached. It will skip
|
||||
* over $skipMod -1 recurrences.
|
||||
@ -838,7 +863,6 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* Get the number of daily occurrences for a recurring transaction until date $end is reached. Will skip every $skipMod-1 occurrences.
|
||||
*
|
||||
|
@ -89,6 +89,15 @@ interface RecurringRepositoryInterface
|
||||
*/
|
||||
public function getJournalCount(Recurrence $recurrence, Carbon $start = null, Carbon $end = null): int;
|
||||
|
||||
/**
|
||||
* Get journal ID's for journals created by this recurring transaction.
|
||||
*
|
||||
* @param Recurrence $recurrence
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJournalIds(Recurrence $recurrence): array;
|
||||
|
||||
/**
|
||||
* Get the notes.
|
||||
*
|
||||
|
@ -200,9 +200,11 @@ Route::group(
|
||||
// Recurrence API routes:
|
||||
Route::get('', ['uses' => 'RecurrenceController@index', 'as' => 'index']);
|
||||
Route::post('', ['uses' => 'RecurrenceController@store', 'as' => 'store']);
|
||||
Route::post('trigger', ['uses' => 'RecurrenceController@trigger', 'as' => 'trigger']);
|
||||
Route::get('{recurrence}', ['uses' => 'RecurrenceController@show', 'as' => 'show']);
|
||||
Route::put('{recurrence}', ['uses' => 'RecurrenceController@update', 'as' => 'update']);
|
||||
Route::delete('{recurrence}', ['uses' => 'RecurrenceController@delete', 'as' => 'delete']);
|
||||
Route::get('{recurrence}/transactions', ['uses' => 'RecurrenceController@transactions', 'as' => 'transactions']);
|
||||
}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user