First code for the piggy bank API.

This commit is contained in:
James Cole 2018-06-29 06:43:44 +02:00
parent c8de1d3372
commit 12a84572e2
8 changed files with 214 additions and 28 deletions

View File

@ -23,8 +23,10 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\PiggyBankRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\BudgetTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@ -33,8 +35,13 @@ use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Manager;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
use League\Fractal\Serializer\JsonApiSerializer;
/**
* TODO order up and down.
* Class PiggyBankController
*/
class PiggyBankController extends Controller
{
@ -59,13 +66,13 @@ class PiggyBankController extends Controller
/**
* Delete the resource.
*
* @param string $object
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function delete(string $object): JsonResponse
public function delete(PiggyBank $piggyBank): JsonResponse
{
// todo delete object.
$this->repository->destroy($piggyBank);
return response()->json([], 204);
}
@ -89,7 +96,7 @@ class PiggyBankController extends Controller
// get list of budgets. Count it and split it.
$collection = $this->repository->getPiggyBanks();
$count = $collection->count();
$piggyBanks= $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
@ -107,27 +114,48 @@ class PiggyBankController extends Controller
/**
* List single resource.
*
* @param Request $request
* @param string $object
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function show(Request $request, string $object): JsonResponse
public function show(Request $request, PiggyBank $piggyBank): JsonResponse
{
// todo implement me.
$manager = new Manager();
// add include parameter:
$include = $request->get('include') ?? '';
$manager->parseIncludes($include);
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Store new object.
*
* @param Request $request
* @param PiggyBankRequest $request
*
* @return JsonResponse
* @throws FireflyException
*/
public function store(Request $request): JsonResponse
public function store(PiggyBankRequest $request): JsonResponse
{
// todo replace code and replace request object.
$piggyBank = $this->repository->store($request->getAll());
if (null !== $piggyBank) {
$manager = new Manager();
$baseUrl = $request->getSchemeAndHttpHost() . '/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$resource = new Item($piggyBank, new PiggyBankTransformer($this->parameters), 'piggy_banks');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
throw new FireflyException('Could not store new piggy bank.'); // @codeCoverageIgnore
}

View File

@ -0,0 +1,90 @@
<?php
/**
* PiggyBankRequest.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\Api\V1\Requests;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Rules\IsAssetAccountId;
/**
*
* Class PiggyBankRequest
*/
class PiggyBankRequest extends Request
{
/**
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* @return array
*/
public function getAll(): array
{
return [
'name' => $this->string('name'),
'account_id' => $this->integer('account_id'),
'targetamount' => $this->string('target_amount'),
'current_amount' => $this->string('current_amount'),
'start_date' => $this->date('start_date'),
'target_date' => $this->date('target_date'),
'note' => $this->string('notes'),
];
}
/**
* @return array
*/
public function rules(): array
{
$rules = [
'name' => 'required|between:1,255|uniquePiggyBankForUser',
'account_id' => ['required', 'belongsToUser:accounts', new IsAssetAccountId],
'target_amount' => 'required|numeric|more:0',
'current_amount' => 'numeric|more:0|lte:target_amount',
'start_date' => 'date|nullable',
'target_date' => 'date|nullable',
'notes' => 'max:65000',
];
switch ($this->method()) {
default:
break;
case 'PUT':
case 'PATCH':
/** @var PiggyBank $piggyBank */
$piggyBank = $this->route()->parameter('piggyBank');
$rules['name'] = 'required|between:1,255|uniquePiggyBankForUser:' . $piggyBank->id;
break;
}
return $rules;
}
}

View File

@ -33,12 +33,17 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class PiggyBank.
*
* @property Carbon $targetdate
* @property Carbon $startdate
* @property string $targetamount
* @property int $id
* @property string $name
* @property Carbon $targetdate
* @property Carbon $startdate
* @property string $targetamount
* @property int $id
* @property string $name
* @property Account $account
* @property Carbon $updated_at
* @property Carbon $created_at
* @property int $order
* @property bool $active
* @property int $account_id
*
*/
class PiggyBank extends Model

View File

@ -30,6 +30,8 @@ use Illuminate\Database\Eloquent\Model;
* Class PiggyBankRepetition.
*
* @property string $currentamount
* @property Carbon $startdate
* @property Carbon $targetdate
*/
class PiggyBankRepetition extends Model
{

View File

@ -117,7 +117,7 @@ class EventServiceProvider extends ServiceProvider
*/
protected function registerCreateEvents(): void
{
// move this routine to a filter
// todo move this routine to a filter
// in case of repeated piggy banks and/or other problems.
PiggyBank::created(
function (PiggyBank $piggyBank) {

View File

@ -49,7 +49,10 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
*/
public function addAmount(PiggyBank $piggyBank, string $amount): bool
{
$repetition = $piggyBank->currentRelevantRep();
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
}
$currentAmount = $repetition->currentamount ?? '0';
$repetition->currentamount = bcadd($currentAmount, $amount);
$repetition->save();
@ -99,7 +102,11 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
*/
public function canRemoveAmount(PiggyBank $piggyBank, string $amount): bool
{
$savedSoFar = $piggyBank->currentRelevantRep()->currentamount;
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
}
$savedSoFar = $repetition->currentamount;
return bccomp($amount, $savedSoFar) <= 0;
}
@ -171,6 +178,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/**
* @param int $piggyBankid
*
* @deprecated
* @return PiggyBank
*/
public function find(int $piggyBankid): PiggyBank
@ -268,7 +276,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
Log::debug(sprintf('Will add/remove %f to piggy bank #%d ("%s")', $amount, $piggyBank->id, $piggyBank->name));
// if piggy account matches source account, the amount is positive
if (\in_array($piggyBank->account_id, $sources)) {
if (\in_array($piggyBank->account_id, $sources, true)) {
$amount = bcmul($amount, '-1');
Log::debug(sprintf('Account #%d is the source, so will remove amount from piggy bank.', $piggyBank->account_id));
}
@ -438,8 +446,8 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/**
* set id of piggy bank.
*
* @param int $piggyBankId
* @param int $order
* @param PiggyBank $piggyBank
* @param int $order
*
* @return bool
*/
@ -454,7 +462,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
/**
* @param User $user
*/
public function setUser(User $user)
public function setUser(User $user): void
{
$this->user = $user;
}
@ -472,6 +480,13 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
$this->updateNote($piggyBank, $data['note']);
// repetition is auto created.
$repetition = $this->getRepetition($piggyBank);
if (null !== $repetition && isset($data['current_amount'])) {
$repetition->currentamount = $data['current_amount'];
$repetition->save();
}
return $piggyBank;
}
@ -495,7 +510,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
// if the piggy bank is now smaller than the current relevant rep,
// remove money from the rep.
$repetition = $piggyBank->currentRelevantRep();
$repetition = $this->getRepetition($piggyBank);
if ($repetition->currentamount > $piggyBank->targetamount) {
$diff = bcsub($piggyBank->targetamount, $repetition->currentamount);
$this->createEvent($piggyBank, $diff);

View File

@ -0,0 +1,46 @@
<?php
namespace FireflyIII\Rules;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use Illuminate\Contracts\Validation\Rule;
/**
*
* Class IsAssetAccountId
*/
class IsAssetAccountId implements Rule
{
/**
* Get the validation error message. This is not translated because only the API uses it.
*
* @return string
*/
public function message(): string
{
return 'This is not an asset account.';
}
/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
*
* @return bool
*/
public function passes($attribute, $value): bool
{
$accountId = (int)$value;
$account = Account::with('accountType')->find($accountId);
if (null === $account) {
return false;
}
if ($account->accountType->type !== AccountType::ASSET && $account->accountType->type !== AccountType::DEFAULT) {
return false;
}
return true;
}
}

View File

@ -166,9 +166,9 @@ class PiggyBankTransformer extends TransformerAbstract
'percentage' => $percentage,
'current_amount' => $currentAmount,
'left_to_save' => round($leftToSave, $decimalPlaces),
'save_per_month' => $piggyRepos->getSuggestedMonthlyAmount($piggyBank),
'startdate' => $startDate,
'targetdate' => $targetDate,
'save_per_month' => round($piggyRepos->getSuggestedMonthlyAmount($piggyBank), $decimalPlaces),
'start_date' => $startDate,
'target_date' => $targetDate,
'order' => (int)$piggyBank->order,
'active' => (int)$piggyBank->active === 1,
'notes' => null,