From 0b9be029ac4e7108cd83ec7a3a9da55918ba3c7b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sun, 24 Jun 2018 13:20:29 +0200 Subject: [PATCH] Expand API with budget limits --- .../Controllers/AvailableBudgetController.php | 2 +- .../V1/Controllers/BudgetLimitController.php | 230 ++++++++++++++++++ app/Api/V1/Requests/BudgetLimitRequest.php | 77 ++++++ app/Factory/BillFactory.php | 4 +- app/Http/Requests/BillFormRequest.php | 3 - app/Models/BudgetLimit.php | 24 +- app/Repositories/Budget/BudgetRepository.php | 124 +++++++++- .../Budget/BudgetRepositoryInterface.php | 26 +- .../AvailableBudgetTransformer.php | 3 + app/Transformers/BudgetLimitTransformer.php | 103 ++++++++ resources/views/bills/create.twig | 2 - routes/api.php | 15 +- 12 files changed, 587 insertions(+), 26 deletions(-) create mode 100644 app/Api/V1/Controllers/BudgetLimitController.php create mode 100644 app/Api/V1/Requests/BudgetLimitRequest.php create mode 100644 app/Transformers/BudgetLimitTransformer.php diff --git a/app/Api/V1/Controllers/AvailableBudgetController.php b/app/Api/V1/Controllers/AvailableBudgetController.php index c209802979..ee182bb457 100644 --- a/app/Api/V1/Controllers/AvailableBudgetController.php +++ b/app/Api/V1/Controllers/AvailableBudgetController.php @@ -97,7 +97,7 @@ class AvailableBudgetController extends Controller // types to get, page size: $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; - // get list of accounts. Count it and split it. + // get list of available budgets. Count it and split it. $collection = $this->repository->getAvailableBudgets(); $count = $collection->count(); $availableBudgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); diff --git a/app/Api/V1/Controllers/BudgetLimitController.php b/app/Api/V1/Controllers/BudgetLimitController.php new file mode 100644 index 0000000000..70c452157d --- /dev/null +++ b/app/Api/V1/Controllers/BudgetLimitController.php @@ -0,0 +1,230 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Controllers; + +use Carbon\Carbon; +use FireflyIII\Api\V1\Requests\AvailableBudgetRequest; +use FireflyIII\Api\V1\Requests\BudgetLimitRequest; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Models\BudgetLimit; +use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; +use FireflyIII\Transformers\BudgetLimitTransformer; +use FireflyIII\User; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; +use InvalidArgumentException; +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; +use Log; + +/** + * Class BudgetLimitController + */ +class BudgetLimitController extends Controller +{ + ///** @var CurrencyRepositoryInterface */ + //private $currencyRepository; + /** @var BudgetRepositoryInterface */ + private $repository; + + /** + * AccountController constructor. + */ + public function __construct() + { + parent::__construct(); + $this->middleware( + function ($request, $next) { + /** @var User $user */ + $user = auth()->user(); + $this->repository = app(BudgetRepositoryInterface::class); + //$this->currencyRepository = app(CurrencyRepositoryInterface::class); + $this->repository->setUser($user); + + return $next($request); + } + ); + } + + /** + * Remove the specified resource from storage. + * + * @param BudgetLimit $budgetLimit + * + * @return JsonResponse + */ + public function delete(BudgetLimit $budgetLimit): JsonResponse + { + $this->repository->destroyBudgetLimit($budgetLimit); + + return response()->json([], 204); + } + + /** + * Display a listing of the resource. + * + * @param Request $request + * + * @return JsonResponse + */ + public function index(Request $request): JsonResponse + { + // create some objects: + $manager = new Manager; + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + + // read budget from request + $budgetId = (int)($request->get('budget_id') ?? 0); + $budget = null; + if ($budgetId > 0) { + $budget = $this->repository->findNull($budgetId); + } + // read start date from request + $start = null; + try { + $start = Carbon::createFromFormat('Y-m-d', $request->get('start')); + $this->parameters->set('start', $start->format('Y-m-d')); + } catch (InvalidArgumentException $e) { + Log::debug(sprintf('Could not parse start date "%s": %s', $request->get('start'), $e->getMessage())); + + } + + // read end date from request + $end = null; + try { + $end = Carbon::createFromFormat('Y-m-d', $request->get('end')); + $this->parameters->set('end', $end->format('Y-m-d')); + } catch (InvalidArgumentException $e) { + Log::debug(sprintf('Could not parse end date "%s": %s', $request->get('end'), $e->getMessage())); + } + $this->parameters->set('budget_id', $budgetId); + + // types to get, page size: + $pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data; + + // get list of budget limits. Count it and split it. + $collection = new Collection; + if (null === $budget) { + $collection = $this->repository->getAllBudgetLimits($start, $end); + } + if (null !== $budget) { + $collection = $this->repository->getBudgetLimits($budget, $start, $end); + } + + $count = $collection->count(); + $budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize); + + // make paginator: + $paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page')); + $paginator->setPath(route('api.v1.budget_limits.index') . $this->buildParams()); + + // present to user. + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + $resource = new FractalCollection($budgetLimits, new BudgetLimitTransformer($this->parameters), 'budget_limits'); + $resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + /** + * Display the specified resource. + * + * @param Request $request + * @param BudgetLimit $budgetLimit + * + * @return JsonResponse + */ + public function show(Request $request, BudgetLimit $budgetLimit): JsonResponse + { + $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($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + /** + * Store a newly created resource in storage. + * + * @param BudgetLimitRequest $request + * + * @return JsonResponse + * @throws FireflyException + */ + public function store(BudgetLimitRequest $request): JsonResponse + { + $data = $request->getAll(); + $budget = $this->repository->findNull($data['budget_id']); + if (null === $budget) { + throw new FireflyException('Unknown budget.'); + } + $data['budget'] = $budget; + $budgetLimit = $this->repository->storeBudgetLimit($data); + $manager = new Manager; + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + } + + /** + * Update the specified resource in storage. + * + * @param AvailableBudgetRequest $request + * @param BudgetLimit $budgetLimit + * + * @return JsonResponse + */ + public function update(BudgetLimitRequest $request, BudgetLimit $budgetLimit): JsonResponse + { + $data = $request->getAll(); + $budget = $this->repository->findNull($data['budget_id']); + if (null === $budget) { + $budget = $budgetLimit->budget; + } + $data['budget'] = $budget; + $budgetLimit = $this->repository->updateBudgetLimit($budgetLimit, $data); + $manager = new Manager; + $baseUrl = $request->getSchemeAndHttpHost() . '/api/v1'; + $manager->setSerializer(new JsonApiSerializer($baseUrl)); + + $resource = new Item($budgetLimit, new BudgetLimitTransformer($this->parameters), 'budget_limits'); + + return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json'); + + } +} \ No newline at end of file diff --git a/app/Api/V1/Requests/BudgetLimitRequest.php b/app/Api/V1/Requests/BudgetLimitRequest.php new file mode 100644 index 0000000000..8ede47cfce --- /dev/null +++ b/app/Api/V1/Requests/BudgetLimitRequest.php @@ -0,0 +1,77 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Api\V1\Requests; + + +/** + * Class BudgetLimitRequest + */ +class BudgetLimitRequest extends Request +{ + /** + * @return bool + */ + public function authorize(): bool + { + // Only allow authenticated users + return auth()->check(); + } + + /** + * @return array + */ + public function getAll(): array + { + return [ + 'budget_id' => $this->integer('budget_id'), + 'start_date' => $this->date('start_date'), + 'end_date' => $this->date('end_date'), + 'amount' => $this->string('amount'), + ]; + } + + /** + * @return array + */ + public function rules(): array + { + $rules = [ + 'budget_id' => 'required|exists:budgets,id|belongsToUser:budgets,id', + 'start_date' => 'required|before:end_date|date', + 'end_date' => 'required|after:start_date|date', + 'amount' => 'required|more:0', + ]; + switch ($this->method()) { + default: + break; + case 'PUT': + case 'PATCH': + $rules['budget_id'] = 'required|exists:budgets,id|belongsToUser:budgets,id'; + break; + } + + return $rules; + } + +} \ No newline at end of file diff --git a/app/Factory/BillFactory.php b/app/Factory/BillFactory.php index 94327af9ee..101d225452 100644 --- a/app/Factory/BillFactory.php +++ b/app/Factory/BillFactory.php @@ -58,8 +58,8 @@ class BillFactory 'date' => $data['date'], 'repeat_freq' => $data['repeat_freq'], 'skip' => $data['skip'], - 'automatch' => true, - 'active' => $data['active'], + 'automatch' => $data['automatch'] ?? true, + 'active' => $data['active'] ?? true, ] ); diff --git a/app/Http/Requests/BillFormRequest.php b/app/Http/Requests/BillFormRequest.php index 7b0b54083f..82e1581156 100644 --- a/app/Http/Requests/BillFormRequest.php +++ b/app/Http/Requests/BillFormRequest.php @@ -49,7 +49,6 @@ class BillFormRequest extends Request 'date' => $this->date('date'), 'repeat_freq' => $this->string('repeat_freq'), 'skip' => $this->integer('skip'), - 'active' => $this->boolean('active'), 'notes' => $this->string('notes'), ]; } @@ -73,8 +72,6 @@ class BillFormRequest extends Request 'date' => 'required|date', 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', 'skip' => 'required|between:0,31', - 'automatch' => 'in:1', - 'active' => 'in:1', ]; return $rules; diff --git a/app/Models/BudgetLimit.php b/app/Models/BudgetLimit.php index 2934a5b6f5..12c7b97612 100644 --- a/app/Models/BudgetLimit.php +++ b/app/Models/BudgetLimit.php @@ -22,11 +22,21 @@ declare(strict_types=1); namespace FireflyIII\Models; +use Carbon\Carbon; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Class BudgetLimit. + * + * @property Budget $budget + * @property int $id + * @property Carbon $created_at + * @property Carbon $updated_at + * @property Carbon $start_date + * @property Carbon $end_date + * @property string $amount */ class BudgetLimit extends Model { @@ -67,20 +77,10 @@ class BudgetLimit extends Model /** * @codeCoverageIgnore - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + * @return BelongsTo */ - public function budget() + public function budget(): BelongsTo { return $this->belongsTo(Budget::class); } - - /** - * @codeCoverageIgnore - * - * @param $value - */ - public function setAmountAttribute($value) - { - $this->attributes['amount'] = (string)round($value, 12); - } } diff --git a/app/Repositories/Budget/BudgetRepository.php b/app/Repositories/Budget/BudgetRepository.php index 8fb69c57c5..443a117405 100644 --- a/app/Repositories/Budget/BudgetRepository.php +++ b/app/Repositories/Budget/BudgetRepository.php @@ -154,6 +154,20 @@ class BudgetRepository implements BudgetRepositoryInterface return $return; } + /** + * Deletes a budget limit. + * + * @param BudgetLimit $budgetLimit + */ + public function deleteBudgetLimit(BudgetLimit $budgetLimit): void + { + try { + $budgetLimit->delete(); + } catch (Exception $e) { + Log::error(sprintf('Could not delete budget limit: %s', $e->getMessage())); + } + } + /** * @param Budget $budget * @@ -315,8 +329,35 @@ class BudgetRepository implements BudgetRepositoryInterface * * @return Collection */ - public function getAllBudgetLimits(Carbon $start, Carbon $end): Collection + public function getAllBudgetLimits(Carbon $start = null, Carbon $end = null): Collection { + // both are NULL: + if (null === $start && null === $end) { + $set = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + ->with(['budget']) + ->where('budgets.user_id', $this->user->id) + ->get(['budget_limits.*']); + + return $set; + } + // one of the two is NULL. + if (null === $start xor null === $end) { + $query = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') + ->with(['budget']) + ->where('budgets.user_id', $this->user->id); + if (null !== $end) { + // end date must be before $end. + $query->where('end_date', '<=', $end->format('Y-m-d 00:00:00')); + } + if (null !== $start) { + // start date must be after $start. + $query->where('start_date', '>=', $start->format('Y-m-d 00:00:00')); + } + $set = $query->get(['budget_limits.*']); + + return $set; + } + // neither are NULL: $set = BudgetLimit::leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id') ->with(['budget']) ->where('budgets.user_id', $this->user->id) @@ -389,8 +430,28 @@ class BudgetRepository implements BudgetRepositoryInterface * * @return Collection */ - public function getBudgetLimits(Budget $budget, Carbon $start, Carbon $end): Collection + public function getBudgetLimits(Budget $budget, Carbon $start = null, Carbon $end = null): Collection { + if (null === $end && null === $start) { + return $budget->budgetlimits()->orderBy('budget_limits.start_date', 'DESC')->get(['budget_limits.*']); + } + if (null === $end xor null === $start) { + $query = $budget->budgetlimits()->orderBy('budget_limits.start_date', 'DESC'); + // one of the two is null + if (null !== $end) { + // end date must be before $end. + $query->where('end_date', '<=', $end->format('Y-m-d 00:00:00')); + } + if (null !== $start) { + // start date must be after $start. + $query->where('start_date', '>=', $start->format('Y-m-d 00:00:00')); + } + $set = $query->get(['budget_limits.*']); + + return $set; + } + + // when both dates are set: $set = $budget->budgetlimits() ->where( function (Builder $q5) use ($start, $end) { @@ -663,6 +724,42 @@ class BudgetRepository implements BudgetRepositoryInterface return $newBudget; } + /** + * @param array $data + * + * @throws FireflyException + * @return BudgetLimit + */ + public function storeBudgetLimit(array $data): BudgetLimit + { + $this->cleanupBudgets(); + /** @var Budget $budget */ + $budget = $data['budget']; + + // find limit with same date range. + // if it exists, throw error. + $limits = $budget->budgetlimits() + ->where('budget_limits.start_date', $data['start_date']->format('Y-m-d 00:00:00')) + ->where('budget_limits.end_date', $data['end_date']->format('Y-m-d 00:00:00')) + ->get(['budget_limits.*'])->count(); + Log::debug(sprintf('Found %d budget limits.', $limits)); + if ($limits > 0) { + throw new FireflyException('A budget limit for this budget, and this date range already exists. You must update the existing one.'); + } + + Log::debug('No existing budget limit, create a new one'); + // or create one and return it. + $limit = new BudgetLimit; + $limit->budget()->associate($budget); + $limit->start_date = $data['start_date']->format('Y-m-d 00:00:00'); + $limit->end_date = $data['end_date']->format('Y-m-d 00:00:00'); + $limit->amount = $data['amount']; + $limit->save(); + Log::debug(sprintf('Created new budget limit with ID #%d and amount %s', $limit->id, $data['amount'])); + + return $limit; + } + /** * @param Budget $budget * @param array $data @@ -708,6 +805,29 @@ class BudgetRepository implements BudgetRepositoryInterface } + /** + * @param BudgetLimit $budgetLimit + * @param array $data + * + * @return BudgetLimit + * @throws Exception + */ + public function updateBudgetLimit(BudgetLimit $budgetLimit, array $data): BudgetLimit + { + $this->cleanupBudgets(); + /** @var Budget $budget */ + $budget = $data['budget']; + + $budgetLimit->budget()->associate($budget); + $budgetLimit->start_date = $data['start_date']->format('Y-m-d 00:00:00'); + $budgetLimit->end_date = $data['end_date']->format('Y-m-d 00:00:00'); + $budgetLimit->amount = $data['amount']; + $budgetLimit->save(); + Log::debug(sprintf('Updated budget limit with ID #%d and amount %s', $budgetLimit->id, $data['amount'])); + + return $budgetLimit; + } + /** * @param Budget $budget * @param Carbon $start diff --git a/app/Repositories/Budget/BudgetRepositoryInterface.php b/app/Repositories/Budget/BudgetRepositoryInterface.php index cbc9b224a3..d08e406a3d 100644 --- a/app/Repositories/Budget/BudgetRepositoryInterface.php +++ b/app/Repositories/Budget/BudgetRepositoryInterface.php @@ -63,6 +63,13 @@ interface BudgetRepositoryInterface */ public function collectBudgetInformation(Collection $budgets, Carbon $start, Carbon $end): array; + /** + * Deletes a budget limit. + * + * @param BudgetLimit $budgetLimit + */ + public function deleteBudgetLimit(BudgetLimit $budgetLimit): void; + /** * @param Budget $budget * @@ -136,7 +143,7 @@ interface BudgetRepositoryInterface * * @return Collection */ - public function getAllBudgetLimits(Carbon $start, Carbon $end): Collection; + public function getAllBudgetLimits(Carbon $start = null, Carbon $end = null): Collection; /** * @param TransactionCurrency $currency @@ -161,7 +168,7 @@ interface BudgetRepositoryInterface * * @return Collection */ - public function getBudgetLimits(Budget $budget, Carbon $start, Carbon $end): Collection; + public function getBudgetLimits(Budget $budget, Carbon $start = null, Carbon $end = null): Collection; /** * @param Collection $budgets @@ -259,6 +266,21 @@ interface BudgetRepositoryInterface */ public function updateAvailableBudget(AvailableBudget $availableBudget, array $data): AvailableBudget; + /** + * @param BudgetLimit $budgetLimit + * @param array $data + * + * @return BudgetLimit + */ + public function updateBudgetLimit(BudgetLimit $budgetLimit, array $data): BudgetLimit; + + /** + * @param array $data + * + * @return BudgetLimit + */ + public function storeBudgetLimit(array $data): BudgetLimit; + /** * @param Budget $budget * @param Carbon $start diff --git a/app/Transformers/AvailableBudgetTransformer.php b/app/Transformers/AvailableBudgetTransformer.php index 0f46939267..e50d0a162f 100644 --- a/app/Transformers/AvailableBudgetTransformer.php +++ b/app/Transformers/AvailableBudgetTransformer.php @@ -29,6 +29,9 @@ use League\Fractal\Resource\Item; use League\Fractal\TransformerAbstract; use Symfony\Component\HttpFoundation\ParameterBag; +/** + * Class AvailableBudgetTransformer + */ class AvailableBudgetTransformer extends TransformerAbstract { /** diff --git a/app/Transformers/BudgetLimitTransformer.php b/app/Transformers/BudgetLimitTransformer.php new file mode 100644 index 0000000000..462290fdb9 --- /dev/null +++ b/app/Transformers/BudgetLimitTransformer.php @@ -0,0 +1,103 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Transformers; +use FireflyIII\Models\BudgetLimit; +use League\Fractal\Resource\Item; +use League\Fractal\TransformerAbstract; +use Symfony\Component\HttpFoundation\ParameterBag; + +/** + * Class BudgetLimitTransformer + */ +class BudgetLimitTransformer extends TransformerAbstract +{ + /** + * List of resources possible to include + * + * @var array + */ + protected $availableIncludes = ['budget']; + /** + * List of resources to automatically include + * + * @var array + */ + protected $defaultIncludes = ['budget']; + + /** @var ParameterBag */ + protected $parameters; + + /** + * CurrencyTransformer constructor. + * + * @codeCoverageIgnore + * + * @param ParameterBag $parameters + */ + public function __construct(ParameterBag $parameters) + { + $this->parameters = $parameters; + } + + /** + * Attach the budget. + * + * @codeCoverageIgnore + * + * @param BudgetLimit $budgetLimit + * + * @return Item + */ + public function includeBudget(BudgetLimit $budgetLimit): Item + { + return $this->item($budgetLimit->budget, new BudgetTransformer($this->parameters), 'budgets'); + } + + /** + * Transform the note. + * + * @param BudgetLimit $budgetLimit + * + * @return array + */ + public function transform(BudgetLimit $budgetLimit): array + { + $data = [ + 'id' => (int)$budgetLimit->id, + 'updated_at' => $budgetLimit->updated_at->toAtomString(), + 'created_at' => $budgetLimit->created_at->toAtomString(), + 'start_date' => $budgetLimit->start_date->format('Y-m-d'), + 'end_date' => $budgetLimit->end_date->format('Y-m-d'), + 'amount' => $budgetLimit->amount, + 'links' => [ + [ + 'rel' => 'self', + 'uri' => '/budget_limits/' . $budgetLimit->id, + ], + ], + ]; + + return $data; + } +} \ No newline at end of file diff --git a/resources/views/bills/create.twig b/resources/views/bills/create.twig index 5e5508d02c..2548c0ed6b 100644 --- a/resources/views/bills/create.twig +++ b/resources/views/bills/create.twig @@ -35,8 +35,6 @@ {{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }} {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} {{ ExpandedForm.integer('skip',0) }} - {# only correct way to do active checkbox #} - {{ ExpandedForm.checkbox('active', 1) }} diff --git a/routes/api.php b/routes/api.php index d4bc282787..ae67e1232d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -66,13 +66,24 @@ Route::group( Route::get('', ['uses' => 'AvailableBudgetController@index', 'as' => 'index']); Route::post('', ['uses' => 'AvailableBudgetController@store', 'as' => 'store']); Route::get('{availableBudget}', ['uses' => 'AvailableBudgetController@show', 'as' => 'show']); - Route::get('{availableBudget}/download', ['uses' => 'AvailableBudgetController@download', 'as' => 'download']); - Route::post('{availableBudget}/upload', ['uses' => 'AvailableBudgetController@upload', 'as' => 'upload']); Route::put('{availableBudget}', ['uses' => 'AvailableBudgetController@update', 'as' => 'update']); Route::delete('{availableBudget}', ['uses' => 'AvailableBudgetController@delete', 'as' => 'delete']); } ); +Route::group( + ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'budget_limits', 'as' => 'api.v1.budget_limits.'], + function () { + + // Budget Limit API routes: + Route::get('', ['uses' => 'BudgetLimitController@index', 'as' => 'index']); + Route::post('', ['uses' => 'BudgetLimitController@store', 'as' => 'store']); + Route::get('{budgetLimit}', ['uses' => 'BudgetLimitController@show', 'as' => 'show']); + Route::put('{budgetLimit}', ['uses' => 'BudgetLimitController@update', 'as' => 'update']); + Route::delete('{budgetLimit}', ['uses' => 'BudgetLimitController@delete', 'as' => 'delete']); + } +); + Route::group( ['middleware' => ['auth:api', 'bindings'], 'namespace' => 'FireflyIII\Api\V1\Controllers', 'prefix' => 'bills', 'as' => 'api.v1.bills.'], function () {