diff --git a/backend/app/Http/Controllers/Controller.php b/backend/app/Http/Controllers/Controller.php index 0ccb918..2562b53 100644 --- a/backend/app/Http/Controllers/Controller.php +++ b/backend/app/Http/Controllers/Controller.php @@ -2,9 +2,12 @@ namespace App\Http\Controllers; +use Illuminate\Http\Request; use Laravel\Lumen\Routing\Controller as BaseController; class Controller extends BaseController { - // + protected function buildFailedValidationResponse(Request $request, array $errors) { + return ["error" => "validation_error", "message" => $errors]; + } } diff --git a/backend/app/Http/Controllers/ExampleController.php b/backend/app/Http/Controllers/ExampleController.php deleted file mode 100644 index aab066e..0000000 --- a/backend/app/Http/Controllers/ExampleController.php +++ /dev/null @@ -1,18 +0,0 @@ -json(['usuarios' => $usuarios]); + } + + /** + * @param $id + * @return JsonResponse + */ + public function get($id) { + if (!Uuid::isValid($id)) { + return response()->json([ + 'error' => 'invalid_id', + 'message' => 'El id debe ser un UUID valido' + ]); + } + + $usuario = Usuario::find($id); + + if (!$usuario) { + return response()->json([ + 'error' => 'not_found', + 'message' => 'El usuario con id ' . $id . ' no existe' + ], 404); + } + + return response()->json(['usuario' => $usuario]); + } + + /** + * @throws ValidationException + */ + public function create(Request $request) { + $this->validate($request, [ + 'nombre' => 'required', + 'email' => 'required|email', + 'username' => 'required', + 'password' => 'required', + 'type' => 'required|array', + 'type.*' => ['required', Rule::in(['admin', 'mesero', 'recaudador', 'productor'])], + 'restaurant' => 'required|exists:restaurantes,id', + ]); + + $restaurant = $request->input('restaurant'); + + // solo un global admin puede crear usuarios en cualquier restaurant + if (!in_array('global_admin', $request->user->roles)) { + // si el usuario no es administrador no puede crear usuarios + if (!in_array('admin', $request->user->roles)) { + return response()->json([ + 'error' => 'not_allowed', + 'message' => 'El usuario no puede tiene permisos para crear usuarios' + ]); + } + // los administradores solo pueden crear restaurantes en su propio restaurant + if (!$request->user->restaurantes->contains($restaurant)) { + return response()->json([ + 'error' => 'not_allowed', + 'message' => 'El usuario no puede crear un usuario en un restaurant al que no pertenece' + ]); + } + } + + $auth0 = app(Auth0Service::class); + $auth0User = $auth0->createUser( + email: $request->input('email'), + username: $request->input('username'), + password: $request->input('password'), + metadata: [ + 'roles' => $request->input('type'), + 'restaurantes' => [$restaurant], + ] + ); + + if (array_key_exists('error', $auth0User)) { + return response()->json([ + 'error' => $auth0User['errorCode'], + 'message' => $auth0User['message'], + ], $auth0User['statusCode']); + } + + $usuario = new Usuario(); + $usuario->id = Uuid::uuid4(); + $usuario->auth0_id = $auth0User['identities'][0]['provider'] . '|' . $auth0User['identities'][0]['user_id']; + $usuario->nombre = $request->input('nombre'); + $usuario->save(); + + $usuario->restaurantes()->attach($restaurant); + + return response()->json($usuario); + } + +} diff --git a/backend/app/Http/Middleware/Auth0Middleware.php b/backend/app/Http/Middleware/Auth0Middleware.php index b107026..453077e 100644 --- a/backend/app/Http/Middleware/Auth0Middleware.php +++ b/backend/app/Http/Middleware/Auth0Middleware.php @@ -3,26 +3,37 @@ namespace App\Http\Middleware; use Closure; +use App\Models\Usuario; use Auth0\SDK\Exception\InvalidTokenException; use Auth0\SDK\Helpers\JWKFetcher; use Auth0\SDK\Helpers\Tokens\AsymmetricVerifier; use Auth0\SDK\Helpers\Tokens\TokenVerifier; +use Illuminate\Support\Facades\Log; class Auth0Middleware { + /** + * @throws InvalidTokenException + */ public function handle($request, Closure $next) { $token = $request->bearerToken(); if (!$token) { - return response()->json('No token provided', 401); + return response()->json(['error' => 'no_token', 'message' => 'No se envío el token'], 401); } - $this->validateToken($token); + $validated = $this->validateToken($token); + $user = Usuario::where('auth0_id', $validated['sub'])->first(); + + $request = $request->merge(['user' => $user]); return $next($request); } + /** + * @throws InvalidTokenException + */ public function validateToken($token) { try { $jwksUri = env('AUTH0_DOMAIN') . '.well-known/jwks.json'; @@ -30,9 +41,9 @@ class Auth0Middleware { $signatureVerifier = new AsymmetricVerifier($jwksFetcher); $tokenVerifier = new TokenVerifier(env('AUTH0_DOMAIN'), env('AUTH0_AUD'), $signatureVerifier); - $decoded = $tokenVerifier->verify($token); + return $tokenVerifier->verify($token); } catch (InvalidTokenException $e) { throw $e; - }; + } } } diff --git a/backend/app/Models/Restaurante.php b/backend/app/Models/Restaurante.php index 011e578..edb8657 100644 --- a/backend/app/Models/Restaurante.php +++ b/backend/app/Models/Restaurante.php @@ -6,6 +6,9 @@ use App\Traits\UuidPrimaryKey; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * @method static find(mixed $restaurant) + */ class Restaurante extends Model { use UuidPrimaryKey, SoftDeletes; diff --git a/backend/app/Models/Usuario.php b/backend/app/Models/Usuario.php index 9923907..bcc3140 100644 --- a/backend/app/Models/Usuario.php +++ b/backend/app/Models/Usuario.php @@ -2,16 +2,53 @@ namespace App\Models; +use App\Services\Auth0Service; use App\Traits\UuidPrimaryKey; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; +/** + * Class Usuario + * + * @property $id + * @property $auth0_id + * @property $nombre + * + * @method static find($id) + * @method static where(string $string, $sub) + * + * @package App\Models + * + */ class Usuario extends Model { use UuidPrimaryKey, SoftDeletes; protected $table = 'usuarios'; + protected $appends = ['roles']; public function restaurantes() { return $this->belongsToMany(Restaurante::class, 'usuarios_restaurantes', 'usuario_id', 'restaurante_id'); } + + public function administrador() { + return $this->hasOne(Administrador::class); + } + + public function recaudador() { + return $this->hasOne(Recaudador::class); + } + + public function mesero() { + return $this->hasOne(Mesero::class); + } + + public function productor() { + return $this->hasOne(Productor::class); + } + + public function getRolesAttribute() { + $auth0Service = app(Auth0Service::class); + $auth0User = $auth0Service->getUser($this->auth0_id); + return $this->attributes['roles'] = array_key_exists('app_metadata', $auth0User) ? $auth0User['app_metadata']['roles'] : []; + } } diff --git a/backend/app/Providers/AppServiceProvider.php b/backend/app/Providers/AppServiceProvider.php index ddec046..5d4ffac 100644 --- a/backend/app/Providers/AppServiceProvider.php +++ b/backend/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Services\Auth0Service; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider @@ -13,6 +14,8 @@ class AppServiceProvider extends ServiceProvider */ public function register() { - // + $this->app->singleton(Auth0Service::class, function($app) { + return new Auth0Service($app); + }); } } diff --git a/backend/app/Services/Auth0Service.php b/backend/app/Services/Auth0Service.php new file mode 100644 index 0000000..e3e9c9f --- /dev/null +++ b/backend/app/Services/Auth0Service.php @@ -0,0 +1,73 @@ +queryAuth0ForToken(); + if ($auth0Token == null) + return null; + Redis::set( + 'auth0_token', $auth0Token['access_token'], + 'EX', $auth0Token['expires_in'] + ); + $token = $auth0Token['access_token']; + } + return $token; + } + + private function queryAuth0ForToken() { + $endpoint = env('AUTH0_DOMAIN') . 'oauth/token'; + $payload = [ + "client_id" => env('AUTH0_CLIENT_ID'), + "client_secret" => env('AUTH0_CLIENT_SECRET'), + "audience" => env('AUTH0_API_AUD'), + "grant_type" => "client_credentials" + ]; + + $response = Http::post($endpoint, $payload); + + $json = $response->json(); + + if (array_key_exists('error', $json)) { + return null; + } else { + return $json; + } + } + + public function getUser($id) { + $endpoint = env('AUTH0_DOMAIN') . 'api/v2/users/' . $id; + return Http::withToken($this->getToken()) + ->get($endpoint) + ->json(); + } + + public function createUser( + $email, + $username, + $password, + $metadata, + ) { + $endpoint = env('AUTH0_DOMAIN') . 'api/v2/users'; + + $payload = [ + "email" => $email, + "username" => $username, + "password" => $password, + "app_metadata" => $metadata, + "connection" => env('AUTH0_CONNECTION'), + "verify_email" => env('AUTH0_VERIFY_MAIL'), + ]; + + return Http::withToken($this->getToken()) + ->post($endpoint, $payload) + ->json(); + } +} diff --git a/backend/bootstrap/app.php b/backend/bootstrap/app.php index 52dd761..63c8a0b 100644 --- a/backend/bootstrap/app.php +++ b/backend/bootstrap/app.php @@ -91,9 +91,10 @@ $app->routeMiddleware([ | */ -// $app->register(App\Providers\AppServiceProvider::class); + $app->register(App\Providers\AppServiceProvider::class); // $app->register(App\Providers\AuthServiceProvider::class); // $app->register(App\Providers\EventServiceProvider::class); +$app->register(Illuminate\Redis\RedisServiceProvider::class); /* |-------------------------------------------------------------------------- diff --git a/backend/composer.json b/backend/composer.json index 72d3cf0..3b92179 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -7,7 +7,10 @@ "require": { "php": "^7.3|^8.0", "auth0/auth0-php": "^7.8", - "laravel/lumen-framework": "^8.0" + "guzzlehttp/guzzle": "^7.3", + "illuminate/redis": "^8.38", + "laravel/lumen-framework": "^8.0", + "predis/predis": "^1.1" }, "require-dev": { "fakerphp/faker": "^1.9.1", diff --git a/backend/composer.lock b/backend/composer.lock index 11703d5..9e3ed14 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "187e06bbce99a322bf2d6b2628d34204", + "content-hash": "73e3da6538bda6b13d5240cfc43b8a7f", "packages": [ { "name": "auth0/auth0-php", @@ -1875,6 +1875,60 @@ }, "time": "2021-04-15T11:53:14+00:00" }, + { + "name": "illuminate/redis", + "version": "v8.38.0", + "source": { + "type": "git", + "url": "https://github.com/illuminate/redis.git", + "reference": "8c4acca0e65b6a7eaaff1ecf9b6d8267b09004e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/redis/zipball/8c4acca0e65b6a7eaaff1ecf9b6d8267b09004e2", + "reference": "8c4acca0e65b6a7eaaff1ecf9b6d8267b09004e2", + "shasum": "" + }, + "require": { + "illuminate/collections": "^8.0", + "illuminate/contracts": "^8.0", + "illuminate/macroable": "^8.0", + "illuminate/support": "^8.0", + "php": "^7.3|^8.0" + }, + "suggest": { + "ext-redis": "Required to use the phpredis connector (^4.0|^5.0).", + "predis/predis": "Required to use the predis connector (^1.1.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Redis\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Redis package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2021-03-26T15:23:04+00:00" + }, { "name": "illuminate/session", "version": "v8.38.0", @@ -2692,6 +2746,72 @@ ], "time": "2020-07-20T17:29:33+00:00" }, + { + "name": "predis/predis", + "version": "v1.1.7", + "source": { + "type": "git", + "url": "https://github.com/predis/predis.git", + "reference": "b240daa106d4e02f0c5b7079b41e31ddf66fddf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/predis/predis/zipball/b240daa106d4e02f0c5b7079b41e31ddf66fddf8", + "reference": "b240daa106d4e02f0c5b7079b41e31ddf66fddf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-curl": "Allows access to Webdis when paired with phpiredis", + "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniele Alessandri", + "email": "suppakilla@gmail.com", + "homepage": "http://clorophilla.net", + "role": "Creator & Maintainer" + }, + { + "name": "Till Krüss", + "homepage": "https://till.im", + "role": "Maintainer" + } + ], + "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "homepage": "http://github.com/predis/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "support": { + "issues": "https://github.com/predis/predis/issues", + "source": "https://github.com/predis/predis/tree/v1.1.7" + }, + "funding": [ + { + "url": "https://github.com/sponsors/tillkruss", + "type": "github" + } + ], + "time": "2021-04-04T19:34:46+00:00" + }, { "name": "psr/container", "version": "1.1.1", diff --git a/backend/database/factories/UserFactory.php b/backend/database/factories/UserFactory.php deleted file mode 100644 index 31f0a5d..0000000 --- a/backend/database/factories/UserFactory.php +++ /dev/null @@ -1,29 +0,0 @@ - $this->faker->name, - 'email' => $this->faker->unique()->safeEmail, - ]; - } -} diff --git a/backend/database/migrations/.gitkeep b/backend/database/migrations/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/backend/database/seeders/DatabaseSeeder.php b/backend/database/seeders/DatabaseSeeder.php deleted file mode 100644 index 7d3ff6c..0000000 --- a/backend/database/seeders/DatabaseSeeder.php +++ /dev/null @@ -1,18 +0,0 @@ -call('UsersTableSeeder'); - } -} diff --git a/backend/routes/web.php b/backend/routes/web.php index 6f794e1..67c3dea 100644 --- a/backend/routes/web.php +++ b/backend/routes/web.php @@ -3,22 +3,16 @@ /** @var \Laravel\Lumen\Routing\Router $router */ -/* -|-------------------------------------------------------------------------- -| Application Routes -|-------------------------------------------------------------------------- -| -| Here is where you can register all of the routes for an application. -| It is a breeze. Simply tell Lumen the URIs it should respond to -| and give it the Closure to call when that URI is requested. -| -*/ - $router->get('/', function () use ($router) { return 'Public View'; }); + $router->group(['prefix' => 'api/v1', 'middleware' => 'auth'], function () use ($router) { - $router->get('/', function () use ($router) { - return \App\Models\Venta::with('productos')->get(); + $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']); }); }); diff --git a/backend/tests/Auth0ServiceTest.php b/backend/tests/Auth0ServiceTest.php new file mode 100644 index 0000000..2652b90 --- /dev/null +++ b/backend/tests/Auth0ServiceTest.php @@ -0,0 +1,33 @@ +once()->with('auth0_token')->andReturns(null); + Http::fake([ + '*' => Http::response([ + "access_token" => "token", + "scope" => "read:client_grants", + "expires_in" => 86400, + "token_type" => "Bearer" + ]) + ]); + Redis::shouldReceive('set')->with('auth0_token', "token", 'EX', 86400); + + $tokenService = app(Auth0Service::class); + $this->assertEquals("token", $tokenService->getToken()); + } + + public function testIsInCache() { + Redis::shouldReceive('get')->once()->with('auth0_token')->andReturns("token"); + Redis::shouldReceive('set')->never(); + Http::shouldReceive('post')->never(); + + $tokenService = app(Auth0Service::class); + $this->assertEquals("token", $tokenService->getToken()); + } +} diff --git a/backend/tests/ExampleTest.php b/backend/tests/ExampleTest.php deleted file mode 100644 index 1bad6ef..0000000 --- a/backend/tests/ExampleTest.php +++ /dev/null @@ -1,21 +0,0 @@ -get('/'); - - $this->assertEquals( - $this->app->version(), $this->response->getContent() - ); - } -} diff --git a/database/modelo.vpp b/database/modelo.vpp index c2ee822..a79a4b7 100644 Binary files a/database/modelo.vpp and b/database/modelo.vpp differ diff --git a/database/schema.sql b/database/schema.sql index 5d4cd53..b01e92a 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -1,38 +1,44 @@ create table restaurantes ( id uuid primary key default gen_random_uuid(), nombre text not null, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table categorias ( id uuid primary key default gen_random_uuid(), nombre text not null, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table zonas_produccion ( id uuid primary key default gen_random_uuid(), nombre text not null, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp - + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table usuarios ( - id uuid primary key default gen_random_uuid(), - auth0_id text not null, - nombre text not null + id uuid primary key default gen_random_uuid(), + auth0_id text not null, + nombre text not null, + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table usuarios_restaurantes ( usuario_id uuid references usuarios, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, + created_at timestamptz not null default current_timestamp, updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz, primary key (usuario_id, restaurante_id) ); @@ -40,29 +46,33 @@ create table productores ( id uuid primary key default gen_random_uuid(), usuario_id uuid references usuarios, zona_produccion_id uuid references zonas_produccion, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table recaudadores ( id uuid primary key default gen_random_uuid(), usuario_id uuid references usuarios, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table meseros ( id uuid primary key default gen_random_uuid(), usuario_id uuid references usuarios, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table administradores ( id uuid primary key default gen_random_uuid(), usuario_id uuid references usuarios, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table ingredientes ( @@ -70,8 +80,9 @@ create table ingredientes ( nombre text not null, medida text not null, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table productos ( @@ -81,16 +92,18 @@ create table productos ( categoria_id uuid references categorias, zona_produccion_id uuid references zonas_produccion, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table recetas ( producto_id uuid references productos, ingrediente_id uuid references ingredientes, unidades numeric not null, - inserted_at timestamptz not null default current_timestamp, + created_at timestamptz not null default current_timestamp, updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz, primary key (producto_id, ingrediente_id) ); @@ -102,8 +115,9 @@ create table proveedores ( direccion text null, telefono text null, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table compras ( @@ -111,8 +125,9 @@ create table compras ( fecha_compra date not null, proveedor_id uuid references proveedores, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table facturas ( @@ -125,8 +140,9 @@ create table facturas ( fecha_emision date not null, fecha_vencimiento date not null, compra_id uuid references compras, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table compra_ingredientes ( @@ -136,23 +152,26 @@ create table compra_ingredientes ( monto_unitario_neto bigint not null, compra_id uuid references compras, ingrediente_id uuid references ingredientes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table sectores ( id uuid primary key default gen_random_uuid(), nombre text not null, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table tipos_canal ( id uuid primary key default gen_random_uuid(), nombre text not null, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table canales_venta ( @@ -161,8 +180,9 @@ create table canales_venta ( sector_id uuid references sectores, tipo_canal_id uuid references tipos_canal, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table ventas ( @@ -171,8 +191,9 @@ create table ventas ( mesero_id uuid references meseros, canal_id uuid references canales_venta, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table boletas_electronicas ( @@ -180,23 +201,26 @@ create table boletas_electronicas ( numero_boleta text not null, venta_id uuid references ventas, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table boletas_exentas ( id uuid primary key default gen_random_uuid(), venta_id uuid references ventas, restaurante_id uuid references restaurantes, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table estados_produccion ( id uuid primary key default gen_random_uuid(), nombre text not null, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); create table venta_productos ( @@ -206,8 +230,9 @@ create table venta_productos ( venta_id uuid references ventas, producto_id uuid references productos, estado_id uuid references estados_produccion, - inserted_at timestamptz not null default current_timestamp, - updated_at timestamptz not null default current_timestamp + created_at timestamptz not null default current_timestamp, + updated_at timestamptz not null default current_timestamp, + deleted_at timestamptz ); ------------------------------------ diff --git a/planificacion/Planificacion.mpp b/planificacion/Planificacion.mpp new file mode 100644 index 0000000..4a058df Binary files /dev/null and b/planificacion/Planificacion.mpp differ diff --git a/planificacion/mockup.xd b/planificacion/mockup.xd new file mode 100644 index 0000000..045ac9d Binary files /dev/null and b/planificacion/mockup.xd differ