From c0fdba3072e732ac4d66e69b58c645fcd0cf18df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Cort=C3=A9s?= Date: Mon, 12 Jul 2021 16:52:59 -0400 Subject: [PATCH] Categorias --- .../Http/Controllers/CategoriasController.php | 125 ++++++++++++++++++ .../Controllers/RestaurantesController.php | 1 + .../Controllers/ZonasProduccionController.php | 6 +- backend/app/Models/Categoria.php | 8 ++ backend/app/Models/Restaurante.php | 5 + backend/routes/web.php | 49 +++---- database/modelo.vpp | Bin 994304 -> 994304 bytes 7 files changed, 163 insertions(+), 31 deletions(-) create mode 100644 backend/app/Http/Controllers/CategoriasController.php diff --git a/backend/app/Http/Controllers/CategoriasController.php b/backend/app/Http/Controllers/CategoriasController.php new file mode 100644 index 0000000..463d18c --- /dev/null +++ b/backend/app/Http/Controllers/CategoriasController.php @@ -0,0 +1,125 @@ +validOrFail($restaurante_id); + $restaurante = Restaurante::findOrFail($restaurante_id); + + $categorias = $restaurante->categorias(); + + $paginate = app(PaginatorService::class)->paginate( + perPage: $request->input('per_page', 15), + page: $request->input('page', 1), + total: $categorias->count(), + route: 'restaurant.all', + data: ['restaurante_id' => $restaurante_id] + ); + + $data = $categorias->get() + ->skip($paginate['from'] - 1) + ->take($paginate['per_page']) + ->all(); + + return response()->json([ + 'pagination' => $paginate, + 'data' => $data + ]); + } + + /** + * Obtiene una categoria por su id + */ + public function get(Request $request, $restaurante_id, $id) { + app(UuidService::class)->validOrFail($restaurante_id); + app(UuidService::class)->validOrFail($id); + + $restaurante = Restaurante::findOrFail($restaurante_id); + $categoria = Categoria::findOrFail($id); + + if($categoria->restaurante != $restaurante) { + throw new ModelNotFoundException("categoria", $id); + } + + return response()->json($categoria); + } + + /** + * Crea una nueva categoria + */ + public function create(Request $request, $restaurante_id) { + app(UuidService::class)->validOrFail($restaurante_id); + $restaurante = Restaurante::findOrFail($restaurante_id); + + $this->validate($request, [ + 'nombre' => 'required' + ]); + + $categoria = Categoria::create([ + 'id' => Uuid::uuid4(), + 'nombre' => $request->input('nombre'), + 'restaurante_id' => $restaurante->id + ]); + + return response()->json($categoria, 201); + } + + /** + * Actualiza un categoria + */ + public function update(Request $request, $restaurante_id, $id) { + app(UuidService::class)->validOrFail($restaurante_id); + app(UuidService::class)->validOrFail($id); + + $this->validate($request, [ + 'nombre' => 'required' + ]); + + $restaurante = Restaurante::findOrFail($restaurante_id); + $categoria = Categoria::findOrFail($id); + + if($categoria->restaurante != $restaurante) { + throw new ModelNotFoundException("categoria", $id); + } + + $categoria->nombre = $request->input('nombre'); + $categoria->save(); + + return response()->json($categoria); + } + + /** + * Elimina una categoria + */ + public function delete(Request $request, $restaurante_id, $id) { + app(UuidService::class)->validOrFail($restaurante_id); + app(UuidService::class)->validOrFail($id); + + $restaurante = Restaurante::findOrFail($restaurante_id); + $categoria = Categoria::findOrFail($id); + + if($categoria->restaurante != $restaurante) { + throw new ModelNotFoundException("categoria", $id); + } + + $categoria->delete(); + + return response()->json([], 204); + } +} diff --git a/backend/app/Http/Controllers/RestaurantesController.php b/backend/app/Http/Controllers/RestaurantesController.php index a7e279d..43d71bb 100644 --- a/backend/app/Http/Controllers/RestaurantesController.php +++ b/backend/app/Http/Controllers/RestaurantesController.php @@ -98,6 +98,7 @@ class RestaurantesController extends Controller { if($restaurant->canalesVenta()->count() > 0) throw new CantDeleteHasChildException("restaurant", "canal_venta"); if($restaurant->sectores()->count() > 0) throw new CantDeleteHasChildException("restaurant", "sector"); if($restaurant->zonasProduccion()->count() > 0) throw new CantDeleteHasChildException("restaurant", "zona_produccion"); + if($restaurant->categorias()->count() > 0) throw new CantDeleteHasChildException("restaurant", "categoria"); $restaurant->delete(); diff --git a/backend/app/Http/Controllers/ZonasProduccionController.php b/backend/app/Http/Controllers/ZonasProduccionController.php index 8311d23..ff6ca53 100644 --- a/backend/app/Http/Controllers/ZonasProduccionController.php +++ b/backend/app/Http/Controllers/ZonasProduccionController.php @@ -81,7 +81,7 @@ class ZonasProduccionController extends Controller { } /** - * Actualiza un zona de produccion + * Actualiza una zona de produccion */ public function update(Request $request, $restaurante_id, $id) { app(UuidService::class)->validOrFail($restaurante_id); @@ -95,7 +95,7 @@ class ZonasProduccionController extends Controller { $zonaProduccion = ZonaProduccion::findOrFail($id); if($zonaProduccion->restaurante != $restaurante) { - throw new ModelNotFoundException("sector", $id); + throw new ModelNotFoundException("categoria", $id); } $zonaProduccion->nombre = $request->input('nombre'); @@ -105,7 +105,7 @@ class ZonasProduccionController extends Controller { } /** - * Elimina un sector + * Elimina una zona de produccion */ public function delete(Request $request, $restaurante_id, $id) { app(UuidService::class)->validOrFail($restaurante_id); diff --git a/backend/app/Models/Categoria.php b/backend/app/Models/Categoria.php index 71399d4..eeced5c 100644 --- a/backend/app/Models/Categoria.php +++ b/backend/app/Models/Categoria.php @@ -10,6 +10,14 @@ class Categoria extends Model { use UuidPrimaryKey, SoftDeletes; protected $table = 'categorias'; + protected $fillable = ['id', 'nombre', 'restaurante_id']; + + public static function findOrFail($id) { + $categoria = Categoria::find($id); + if(!$categoria) throw new ModelNotFoundException("categoria", $id); + return $categoria; + } + public function restaurante() { return $this->belongsTo(Restaurante::class); diff --git a/backend/app/Models/Restaurante.php b/backend/app/Models/Restaurante.php index 43fa492..adc1c62 100644 --- a/backend/app/Models/Restaurante.php +++ b/backend/app/Models/Restaurante.php @@ -5,6 +5,7 @@ namespace App\Models; use App\Models\CanalVenta; use App\Models\Sector; use App\Models\ZonaProduccion; +use App\Models\Categoria; use App\Traits\UuidPrimaryKey; use App\Exceptions\ModelNotFoundException; use Illuminate\Database\Eloquent\Model; @@ -40,4 +41,8 @@ class Restaurante extends Model { public function zonasProduccion() { return $this->hasMany(ZonaProduccion::class, 'restaurante_id'); } + + public function categorias() { + return $this->hasMany(Categoria::class, 'restaurante_id'); + } } diff --git a/backend/routes/web.php b/backend/routes/web.php index 7fc0311..a7ed8da 100644 --- a/backend/routes/web.php +++ b/backend/routes/web.php @@ -2,9 +2,22 @@ use Laravel\Lumen\Routing\Router; -function registerRestaurantApi($router) { +$router->get('/', function () use ($router) { + return 'Public View'; +}); + +$router->group(['prefix' => 'api/v1', 'middleware' => ['auth', 'log_endpoint']], function () use ($router) { + $router->group(['prefix' => '/users'], function () use ($router) { + $router->get( '/', ['as' => 'users.all', 'uses' => 'UsuariosController@all']); + $router->get( '/{id}', ['as' => 'users.get', 'uses' => 'UsuariosController@get']); + $router->post( '/', ['as' => 'users.create', 'uses' => 'UsuariosController@create']); + $router->put( '/{id}', ['as' => 'users.update', 'uses' => 'UsuariosController@update']); + $router->delete('/{id}', ['as' => 'users.delete', 'uses' => 'UsuariosController@delete']); + $router->put( '/{id}/restaurantes/{restaurant}', ['as' => 'users.add_to_restaurant', 'uses' => 'UsuariosController@addToRestaurant']); + $router->delete('/{id}/restaurantes/{restaurant}', ['as' => 'users.remove_from_restaurant', 'uses' => 'UsuariosController@removeFromRestaurant']); + }); + $router->group(['prefix' => '/restaurantes'], function () use ($router) { - // Rutas del recurso $router->get( '/', ['as' => 'restaurant.all', 'uses' => 'RestaurantesController@all']); $router->get( '/{id}', ['as' => 'restaurant.get', 'uses' => 'RestaurantesController@get']); $router->post( '/', ['as' => 'restaurant.create', 'uses' => 'RestaurantesController@create']); @@ -28,31 +41,11 @@ function registerRestaurantApi($router) { $router->post( '/{restaurante_id}/zonas-produccion', ['as' => 'zonas-produccion.create', 'uses' => 'ZonasProduccionController@create']); $router->put( '/{restaurante_id}/zonas-produccion/{id}', ['as' => 'zonas-produccion.update', 'uses' => 'ZonasProduccionController@update']); $router->delete('/{restaurante_id}/zonas-produccion/{id}', ['as' => 'zonas-produccion.delete', 'uses' => 'ZonasProduccionController@delete']); + + $router->get( '/{restaurante_id}/categorias', ['as' => 'categorias.all', 'uses' => 'CategoriasController@all']); + $router->get( '/{restaurante_id}/categorias/{id}', ['as' => 'categorias.get', 'uses' => 'CategoriasController@get']); + $router->post( '/{restaurante_id}/categorias', ['as' => 'categorias.create', 'uses' => 'CategoriasController@create']); + $router->put( '/{restaurante_id}/categorias/{id}', ['as' => 'categorias.update', 'uses' => 'CategoriasController@update']); + $router->delete('/{restaurante_id}/categorias/{id}', ['as' => 'categorias.delete', 'uses' => 'CategoriasController@delete']); }); -} - -function registerUserApi($router) { - $router->group(['prefix' => '/users'], function () use ($router) { - // Rutas del recurso - $router->get( '/', ['as' => 'users.all', 'uses' => 'UsuariosController@all']); - $router->get( '/{id}', ['as' => 'users.get', 'uses' => 'UsuariosController@get']); - $router->post( '/', ['as' => 'users.create', 'uses' => 'UsuariosController@create']); - $router->put( '/{id}', ['as' => 'users.update', 'uses' => 'UsuariosController@update']); - $router->delete('/{id}', ['as' => 'users.delete', 'uses' => 'UsuariosController@delete']); - - // Rutas de acciones - $router->put( '/{id}/restaurantes/{restaurant}', ['as' => 'users.add_to_restaurant', 'uses' => 'UsuariosController@addToRestaurant']); - $router->delete('/{id}/restaurantes/{restaurant}', ['as' => 'users.remove_from_restaurant', 'uses' => 'UsuariosController@removeFromRestaurant']); - }); -} - -/** @var Router $router */ - -$router->get('/', function () use ($router) { - return 'Public View'; -}); - -$router->group(['prefix' => 'api/v1', 'middleware' => ['auth', 'log_endpoint']], function () use ($router) { - registerUserApi($router); - registerRestaurantApi($router); }); diff --git a/database/modelo.vpp b/database/modelo.vpp index 2e5eab4b9042d1ae5d585b647f22181803289ed2..c7f1752da87e92f0cbeed0bf81e147fe8cb09fd6 100644 GIT binary patch delta 4039 zcmb7HdvI079lrZG=bn3BM4C!UiQEXJiosqa@+tu`Fubim7{rz-&p5G#Kr!0TNhLr8 z6oiC(Ws#yL^0+`533;3i7$DLRLrtx=3bX{Fkf~1Pk2>QYDv<4EjN8DoNE=w@uo)EL@@V3n%$M=NMyPm8NQZppOhJ%l>}2Z_>5i z80=qz`ufuTJz;9jwDF4yYljhktejrm|DI;*cG_Q++@3?pk*d5v5=p7PXPQln+Q~%g z?A8O%oukTPJUF|mXu`deJrSO?bqQs2!j5a64EGPi%nfgaq4jGb>mp=bgszLQbrJ4F z6r+W_EzSArXH0$Hk3pu&Zx*RqN|Y8_oRV^}f1KS{$Pe`tQJijbIp&~wib-CgcJv|@ zqHK(vE(aE=e`jQ$sQU??Y^>0dMd=}}r<^?3I>IQ~FFri2e@{HWOY@6{VYVjI=UA;w z(tRp1^#k*=pDkFHvoe2?cw>#)Plj5wzoO4uk~eGZ%p`~M3+Ck%tXz_t6%y~XXhHdK zz4j40H>iXgmH7*nJeFIq;^{@th+vz)m-y|E>=c=mWW39wyje|B7d~5%n>9;}J)=D+ zhkc-*X1riQL9WxPQmjmhv=dsYC||1u!o`XyM>gwCcmTsWZ7S2qF|q7~)<*`%T9+}S z2BCd!r^>Wq?IPP&q$yJQQf>E>CeizfohH`(PE8S*dk;A+WYw`f+@CBmF535rU+(H; zLlu?jc0lA`v~~G-M5_gZDgF*dsw6j!cD9}d{eUKEFmU5>(&Q`;EKQdAHGvsS9G_~B zmvlpbekFOP)yTvQrVn>YbQ)r`GGFp?{Tg%XbjE2_K=R!v?QPJxg1D-lB6yo#7Z@5E zF?84v{0nEdx>O9=qxRRk>ITaNd(;X_X{`u;YTPI9Z&WX1b}f1bqcT3AJ6LV}Rjz;Z zI}f~zO5Un>_`&AQ(J!$m{Y>YQPO~YOJY;k*{n*6pUuTc|S$5uRk=CfD$N^W?3yjj^ zU7bE*&UKw>^u%4gS;N@$JIo; z`Pi@EOaNL?c>=Z)wgEQV=Of?1uL6F9az5~T`0HUG1TugS%FBQkfz<$(Lx%!A;Mc&q z6RHDV1y%snKq=~X0s8?59oQN;cnM7h1^{V5Umz8@7wvh#Q$Q}@ip?TmA=*v?m@s=8 zb_j3^Xhiu4@Eq_w@B-?N!af7*vbq@-tEcWnCIf*<_;Kl+BIb-V9$v+;DuMwBW=`q> zYzYAyqzM3>1QR7-h#UeyF*yKWC1f8^0hD7qA*}>k;==-bKLq+={MkSbFcX*oOa~rA z8x~4lhjkZUk0;q&G&~8+0iHku7$G}=H&C96hu#;BBaDZjoFyZTRTbpV9x{27Npi{9 z%qW{D%B~noDP8Ea89XyCnr7fUlS&`6!|)K!ql_4L(9MuZ#_DFGZhpX=0+S=4Q>+eV z^i2@XKGw&~2zpCq&}w2NEy_1R;Q0m+3-h)ir3EQYw3vLBJHgH&nPW7Ib#p4^ipFRY7D*~csfDI8HC&k+KiKo z1m=?iO(3?$ywQuYL2kG<$D$D%ViX<}Sj+BqH zE^8AL`P9HCn4aXh4gSt;$nM(O*cFIK`AWaeoD2&xPQQeTIyL%PCf*F&gQ9%6#kB-Y zKhG3bHKvQSPmNUfrul>^?x~+4mEG#K&c>NiDThyVXPSjuI7ccw-D39MQk|Dgcf%7e zjX8NYoyAtWKT2yL=5#swNTnoj135yGMK$8NpmlWvC!TQ=;SuaUoJ*Gu3bVGSe!`4T^H;?jUo8N(LR~U^K zJ?f~ws-3aJJEYx&9T}&4SM0!XH*wrII!kQaWl97E z#Z6salS(Ok(Q)2XqP);HrLxIw%R<|mIPtE(4gM~v6vLMtTWkgWm%H^HsNXACI{^bnCoB_eeZ+-@ZL`TeL%5UTm||*tS+buD43_Ykb)` zSFstML5aM+^Aj+3!5;Sx?h~FzL2pQWIX><9ZZ{52O1={}D`kI_JQ8ynB`%gyVIV=w=Nkaerx!{=$N&nd|_q3yrJD$le4 delta 12637 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 E0YKA&M*si-