Complete API for recurring transactions.

This commit is contained in:
James Cole
2018-06-30 06:14:39 +02:00
parent b8893bcad7
commit 0509e54a95
8 changed files with 98 additions and 47 deletions

View File

@@ -155,14 +155,25 @@ class RecurrenceController extends Controller
}
/**
* @param Request $request
* @param string $object
* @param RecurrenceRequest $request
* @param Recurrence $recurrence
*
* @return JsonResponse
*/
public function update(Request $request, string $object): JsonResponse
public function update(RecurrenceRequest $request, Recurrence $recurrence): JsonResponse
{
// todo replace code and replace request object.
$data = $request->getAll();
//
$category = $this->repository->update($recurrence, $data);
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($category, new RecurrenceTransformer($this->parameters), 'recurrences');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@@ -124,7 +124,7 @@ class RecurrenceRequest extends Request
return [
'type' => 'required|in:withdrawal,transfer,deposit',
'title' => 'required|between:1,255',
'title' => 'required|between:1,255|uniqueObjectForUser:recurrences,title',
'description' => 'between:1,65000',
'first_date' => sprintf('required|date|after:%s', $today->format('Y-m-d')),
'repeat_until' => sprintf('date|after:%s', $today->format('Y-m-d')),
@@ -139,8 +139,8 @@ class RecurrenceRequest extends Request
// rules for repetitions.
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
'repetitions.*.moment' => 'between:0,10',
'repetitions.*.skip' => 'required|between:0,31',
'repetitions.*.weekend' => 'required|between:1,4',
'repetitions.*.skip' => 'required|numeric|between:0,31',
'repetitions.*.weekend' => 'required|numeric|min:1|max:4',
// rules for transactions.
'transactions.*.currency_id' => 'numeric|exists:transaction_currencies,id|required_without:transactions.*.currency_code',

View File

@@ -72,7 +72,7 @@ class CategoryFactory
Log::debug(sprintf('Going to find category with ID %d and name "%s"', $categoryId, $categoryName));
if (\strlen($categoryName) === 0 && $categoryId === 0) {
if ('' === $categoryName && $categoryId === 0) {
return null;
}
// first by ID:

View File

@@ -66,21 +66,26 @@ class RecurrenceFormRequest extends Request
],
'transactions' => [
[
'transaction_currency_id' => $this->integer('transaction_currency_id'),
'type' => $this->string('transaction_type'),
'description' => $this->string('transaction_description'),
'amount' => $this->string('amount'),
'foreign_amount' => null,
'foreign_currency_id' => null,
'budget_id' => $this->integer('budget_id'),
'category_name' => $this->string('category'),
'currency_id' => $this->integer('transaction_currency_id'),
'currency_code' => null,
'type' => $this->string('transaction_type'),
'description' => $this->string('transaction_description'),
'amount' => $this->string('amount'),
'foreign_amount' => null,
'foreign_currency_id' => null,
'foreign_currency_code' => null,
'budget_id' => $this->integer('budget_id'),
'budget_name' => null,
'category_id' => null,
'category_name' => $this->string('category'),
],
],
'meta' => [
// tags and piggy bank ID.
'tags' => '' !== $this->string('tags') ? explode(',', $this->string('tags')) : [],
'piggy_bank_id' => $this->integer('piggy_bank_id'),
'tags' => '' !== $this->string('tags') ? explode(',', $this->string('tags')) : [],
'piggy_bank_id' => $this->integer('piggy_bank_id'),
'piggy_bank_name' => null,
],
'repetitions' => [
[
@@ -98,7 +103,11 @@ class RecurrenceFormRequest extends Request
$return['transactions'][0]['foreign_amount'] = $this->string('foreign_amount');
$return['transactions'][0]['foreign_currency_id'] = $this->integer('foreign_currency_id');
}
// default values:
$return['transactions'][0]['source_id'] = null;
$return['transactions'][0]['source_name'] = null;
$return['transactions'][0]['destination_id'] = null;
$return['transactions'][0]['destination_name'] = null;
// fill in source and destination account data
switch ($this->string('transaction_type')) {
default:

View File

@@ -73,7 +73,7 @@ class RecurrenceTransaction extends Model
*/
public function destinationAccount(): BelongsTo
{
return $this->belongsTo(Account::class);
return $this->belongsTo(Account::class,'destination_id');
}
/**
@@ -109,7 +109,7 @@ class RecurrenceTransaction extends Model
*/
public function sourceAccount(): BelongsTo
{
return $this->belongsTo(Account::class);
return $this->belongsTo(Account::class,'source_id');
}
/**

View File

@@ -32,6 +32,7 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;
use Log;
use Preferences;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -42,6 +43,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property User $user
* @property int $bill_id
* @property Collection $categories
* @property bool $completed
*/
class TransactionJournal extends Model
{

View File

@@ -24,7 +24,10 @@ declare(strict_types=1);
namespace FireflyIII\Services\Internal\Support;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\BudgetFactory;
use FireflyIII\Factory\CategoryFactory;
use FireflyIII\Factory\PiggyBankFactory;
use FireflyIII\Factory\TransactionCurrencyFactory;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Recurrence;
use FireflyIII\Models\RecurrenceMeta;
@@ -69,32 +72,39 @@ trait RecurringTransactionTrait
*/
public function createTransactions(Recurrence $recurrence, array $transactions): void
{
foreach ($transactions as $array) {
$source = null;
$destination = null;
switch ($recurrence->transactionType->type) {
case TransactionType::WITHDRAWAL:
$source = $this->findAccount(AccountType::ASSET, $array['source_id'], $array['source_name'] ?? null);
$destination = $this->findAccount(AccountType::EXPENSE, $array['destination_id'] ?? null, $array['destination_name']);
$source = $this->findAccount(AccountType::ASSET, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::EXPENSE, $array['destination_id'], $array['destination_name']);
break;
case TransactionType::DEPOSIT:
$source = $this->findAccount(AccountType::REVENUE, $array['source_id'] ?? null, $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, $array['destination_id'], $array['destination_name'] ?? null);
$source = $this->findAccount(AccountType::REVENUE, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, $array['destination_id'], $array['destination_name']);
break;
case TransactionType::TRANSFER:
$source = $this->findAccount(AccountType::ASSET, $array['source_id'], $array['source_name'] ?? null);
$destination = $this->findAccount(AccountType::ASSET, $array['destination_id'], $array['destination_name'] ?? null);
$source = $this->findAccount(AccountType::ASSET, $array['source_id'], $array['source_name']);
$destination = $this->findAccount(AccountType::ASSET, $array['destination_id'], $array['destination_name']);
break;
}
/** @var TransactionCurrencyFactory $factory */
$factory = app(TransactionCurrencyFactory::class);
$currency = $factory->find($array['currency_id'], $array['currency_code']);
$foreignCurrency = $factory->find($array['foreign_currency_id'], $array['foreign_currency_code']);
$defaultCurrency = app('amount')->getDefaultCurrencyByUser($recurrence->user);
if (null === $currency) {
$currency = $defaultCurrency;
}
$transaction = new RecurrenceTransaction(
[
'recurrence_id' => $recurrence->id,
'transaction_currency_id' => $array['transaction_currency_id'],
'foreign_currency_id' => '' === (string)$array['foreign_currency_id'] ? null : $array['foreign_currency_id'],
'source_id' => $source->id,
'destination_id' => $destination->id,
'transaction_currency_id' => $currency->id,
'foreign_currency_id' => null === $foreignCurrency ? null : $foreignCurrency->id,
'source_id' => $source->id,
'destination_id' => $destination->id,
'amount' => $array['amount'],
'foreign_amount' => '' === (string)$array['foreign_amount'] ? null : (string)$array['foreign_amount'],
'description' => $array['description'],
@@ -102,22 +112,32 @@ trait RecurringTransactionTrait
);
$transaction->save();
/** @var BudgetFactory $budgetFactory */
$budgetFactory = app(BudgetFactory::class);
$budgetFactory->setUser($recurrence->user);
$budget = $budgetFactory->find($array['budget_id'], $array['budget_name']);
/** @var CategoryFactory $categoryFactory */
$categoryFactory = app(CategoryFactory::class);
$categoryFactory->setUser($recurrence->user);
$category = $categoryFactory->findOrCreate($array['category_id'], $array['category_name']);
// create recurrence transaction meta:
if ($array['budget_id'] > 0) {
if (null !== $budget) {
RecurrenceTransactionMeta::create(
[
'rt_id' => $transaction->id,
'name' => 'budget_id',
'value' => $array['budget_id'],
'value' => $budget->id,
]
);
}
if ('' !== (string)$array['category_name']) {
if (null !== $category) {
RecurrenceTransactionMeta::create(
[
'rt_id' => $transaction->id,
'name' => 'category_name',
'value' => $array['category_name'],
'value' => $category->name,
]
);
}
@@ -155,20 +175,27 @@ trait RecurringTransactionTrait
public function updateMetaData(Recurrence $recurrence, array $data): void
{
// only two special meta fields right now. Let's just hard code them.
$piggyId = (int)($data['meta']['piggy_bank_id'] ?? 0.0);
if ($piggyId > 0) {
$piggyId = (int)($data['meta']['piggy_bank_id'] ?? 0.0);
$piggyName = $data['meta']['piggy_bank_name'] ?? '';
/** @var PiggyBankFactory $factory */
$factory = app(PiggyBankFactory::class);
$factory->setUser($recurrence->user);
$piggyBank = $factory->find($piggyId, $piggyName);
if (null !== $piggyBank) {
/** @var RecurrenceMeta $entry */
$entry = $recurrence->recurrenceMeta()->where('name', 'piggy_bank_id')->first();
if (null === $entry) {
$entry = RecurrenceMeta::create(['recurrence_id' => $recurrence->id, 'name' => 'piggy_bank_id', 'value' => $piggyId]);
$entry = RecurrenceMeta::create(['recurrence_id' => $recurrence->id, 'name' => 'piggy_bank_id', 'value' => $piggyBank->id]);
}
$entry->value = $piggyId;
$entry->value = $piggyBank->id;
$entry->save();
}
if ($piggyId === 0) {
if (null === $piggyBank) {
// delete if present
$recurrence->recurrenceMeta()->where('name', 'piggy_bank_id')->delete();
}
$tags = $data['meta']['tags'] ?? [];
if (\count($tags) > 0) {
/** @var RecurrenceMeta $entry */

View File

@@ -65,11 +65,13 @@ class RecurrenceUpdateService
$recurrence->apply_rules = $data['recurrence']['apply_rules'] ?? $recurrence->apply_rules;
$recurrence->active = $data['recurrence']['active'] ?? $recurrence->active;
if (\in_array($data['recurrence']['repetition_end'], ['forever ', 'until_date'])) {
$recurrence->repetitions = 0;
}
if (\in_array($data['recurrence']['repetition_end'], ['forever ', 'times'])) {
$recurrence->repeat_until = null;
if(isset($data['recurrence']['repetition_end'])) {
if (\in_array($data['recurrence']['repetition_end'], ['forever ', 'until_date'])) {
$recurrence->repetitions = 0;
}
if (\in_array($data['recurrence']['repetition_end'], ['forever ', 'times'])) {
$recurrence->repeat_until = null;
}
}
$recurrence->save();