mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-04 04:30:39 -06:00
First code for the piggy bank API.
This commit is contained in:
parent
c8de1d3372
commit
12a84572e2
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
90
app/Api/V1/Requests/PiggyBankRequest.php
Normal file
90
app/Api/V1/Requests/PiggyBankRequest.php
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -30,6 +30,8 @@ use Illuminate\Database\Eloquent\Model;
|
||||
* Class PiggyBankRepetition.
|
||||
*
|
||||
* @property string $currentamount
|
||||
* @property Carbon $startdate
|
||||
* @property Carbon $targetdate
|
||||
*/
|
||||
class PiggyBankRepetition extends Model
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
46
app/Rules/IsAssetAccountId.php
Normal file
46
app/Rules/IsAssetAccountId.php
Normal 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;
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user