From 507b81b54e081610963f105d330df0199cc92af5 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Fri, 19 Jun 2026 11:34:10 -0300 Subject: [PATCH] Add Tenant model, controller, and migration; update Producto model to reference tenant_codigo --- app/Http/Controllers/ProductController.php | 2 +- app/Http/Controllers/TenantController.php | 64 +++++++++++++++++++ app/Models/Producto.php | 12 +++- app/Models/Tenant.php | 26 ++++++++ ...2026_06_18_135000_create_tenants_table.php | 30 +++++++++ ...e_productos_tenant_reference_to_codigo.php | 38 +++++++++++ routes/api.php | 2 + 7 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 app/Http/Controllers/TenantController.php create mode 100644 app/Models/Tenant.php create mode 100644 database/migrations/2026_06_18_135000_create_tenants_table.php create mode 100644 database/migrations/2026_06_19_000000_update_productos_tenant_reference_to_codigo.php diff --git a/app/Http/Controllers/ProductController.php b/app/Http/Controllers/ProductController.php index 182dd37..1bf6371 100644 --- a/app/Http/Controllers/ProductController.php +++ b/app/Http/Controllers/ProductController.php @@ -51,7 +51,7 @@ class ProductController extends Controller protected function rules(?int $productoId = null): array { return [ - 'tenant_id' => ['required', 'integer'], + 'tenant_codigo' => ['required', 'string', 'exists:tenants,codigo'], 'categoria_id' => ['required', 'integer'], 'slug' => [ 'required', diff --git a/app/Http/Controllers/TenantController.php b/app/Http/Controllers/TenantController.php new file mode 100644 index 0000000..43cde02 --- /dev/null +++ b/app/Http/Controllers/TenantController.php @@ -0,0 +1,64 @@ +json(Tenant::query()->latest()->get()); + } + + public function store(Request $request): JsonResponse + { + $validated = $request->validate($this->rules()); + + $tenant = Tenant::create($validated); + + return response()->json($tenant, 201); + } + + public function show(Tenant $tenant): JsonResponse + { + return response()->json($tenant); + } + + public function update(Request $request, Tenant $tenant): JsonResponse + { + $validated = $request->validate($this->rules($tenant->id)); + + $tenant->update($validated); + + return response()->json($tenant); + } + + public function destroy(Tenant $tenant): Response + { + $tenant->delete(); + + return response()->noContent(); + } + + /** + * @return array + */ + protected function rules(?int $tenantId = null): array + { + return [ + 'codigo' => [ + 'required', + 'string', + 'max:255', + Rule::unique('tenants', 'codigo')->ignore($tenantId), + ], + 'nombre' => ['required', 'string', 'max:255'], + 'dominio' => ['nullable', 'string', 'max:255'], + ]; + } +} diff --git a/app/Models/Producto.php b/app/Models/Producto.php index 9147d68..e4a0d62 100644 --- a/app/Models/Producto.php +++ b/app/Models/Producto.php @@ -5,9 +5,10 @@ namespace App\Models; use Illuminate\Database\Eloquent\Attributes\Fillable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; #[Fillable([ - 'tenant_id', + 'tenant_codigo', 'categoria_id', 'slug', 'nombre', @@ -23,9 +24,16 @@ class Producto extends Model protected function casts(): array { return [ - 'tenant_id' => 'integer', 'categoria_id' => 'integer', 'precio' => 'decimal:2', ]; } + + /** + * @return BelongsTo + */ + public function tenant(): BelongsTo + { + return $this->belongsTo(Tenant::class, 'tenant_codigo', 'codigo'); + } } diff --git a/app/Models/Tenant.php b/app/Models/Tenant.php new file mode 100644 index 0000000..c03aacf --- /dev/null +++ b/app/Models/Tenant.php @@ -0,0 +1,26 @@ + + */ + public function productos(): HasMany + { + return $this->hasMany(Producto::class, 'tenant_codigo', 'codigo'); + } +} diff --git a/database/migrations/2026_06_18_135000_create_tenants_table.php b/database/migrations/2026_06_18_135000_create_tenants_table.php new file mode 100644 index 0000000..4445d5e --- /dev/null +++ b/database/migrations/2026_06_18_135000_create_tenants_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('codigo')->unique(); + $table->string('nombre'); + $table->string('dominio')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('tenants'); + } +}; diff --git a/database/migrations/2026_06_19_000000_update_productos_tenant_reference_to_codigo.php b/database/migrations/2026_06_19_000000_update_productos_tenant_reference_to_codigo.php new file mode 100644 index 0000000..5c1d3b4 --- /dev/null +++ b/database/migrations/2026_06_19_000000_update_productos_tenant_reference_to_codigo.php @@ -0,0 +1,38 @@ +dropColumn('tenant_id'); + }); + + Schema::table('productos', function (Blueprint $table) { + $table->string('tenant_codigo')->after('id'); + $table->foreign('tenant_codigo')->references('codigo')->on('tenants')->cascadeOnUpdate()->restrictOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('productos', function (Blueprint $table) { + $table->dropForeign(['tenant_codigo']); + $table->dropColumn('tenant_codigo'); + }); + + Schema::table('productos', function (Blueprint $table) { + $table->unsignedBigInteger('tenant_id')->after('id'); + }); + } +}; diff --git a/routes/api.php b/routes/api.php index 8155e77..691f4a5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,6 +1,7 @@ middleware('auth:sanctum'); Route::apiResource('productos', ProductController::class); +Route::apiResource('tenants', TenantController::class);