feat: agregar soporte para subcategorías, incluyendo controladores, solicitudes y migraciones
This commit is contained in:
parent
1c21602b7e
commit
37f91d84f2
@ -11,7 +11,8 @@ class CategoryController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$categorias = Category::where('is_active', true)
|
||||
$categorias = Category::with(['subcategories' => fn ($q) => $q->where('is_active', true)->orderBy('name')])
|
||||
->where('is_active', true)
|
||||
->orderBy('name')
|
||||
->paginate(config('app.pagination'));
|
||||
|
||||
@ -22,6 +23,8 @@ public function index()
|
||||
|
||||
public function show(Category $categoria)
|
||||
{
|
||||
$categoria->load(['subcategories' => fn ($q) => $q->where('is_active', true)->orderBy('name')]);
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'model' => $categoria
|
||||
]);
|
||||
|
||||
55
app/Http/Controllers/App/SubcategoryController.php
Normal file
55
app/Http/Controllers/App/SubcategoryController.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php namespace App\Http\Controllers\App;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\App\SubcategoryStoreRequest;
|
||||
use App\Http\Requests\App\SubcategoryUpdateRequest;
|
||||
use App\Models\Category;
|
||||
use App\Models\Subcategory;
|
||||
use Notsoweb\ApiResponse\Enums\ApiResponse;
|
||||
|
||||
class SubcategoryController extends Controller
|
||||
{
|
||||
public function index(Category $category)
|
||||
{
|
||||
$subcategorias = $category->subcategories()
|
||||
->where('is_active', true)
|
||||
->orderBy('name')
|
||||
->paginate(config('app.pagination'));
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'subcategories' => $subcategorias,
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Category $category, Subcategory $subcategory)
|
||||
{
|
||||
return ApiResponse::OK->response([
|
||||
'model' => $subcategory,
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(SubcategoryStoreRequest $request, Category $category)
|
||||
{
|
||||
$subcategoria = $category->subcategories()->create($request->validated());
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'model' => $subcategoria,
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(SubcategoryUpdateRequest $request, Category $category, Subcategory $subcategory)
|
||||
{
|
||||
$subcategory->update($request->validated());
|
||||
|
||||
return ApiResponse::OK->response([
|
||||
'model' => $subcategory->fresh(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function destroy(Category $category, Subcategory $subcategory)
|
||||
{
|
||||
$subcategory->delete();
|
||||
|
||||
return ApiResponse::OK->response();
|
||||
}
|
||||
}
|
||||
@ -112,6 +112,13 @@ public function destroy(int $id)
|
||||
]);
|
||||
}
|
||||
|
||||
// Verificar si es el almacén principal
|
||||
if ($warehouse->is_main) {
|
||||
return ApiResponse::BAD_REQUEST->response([
|
||||
'message' => 'No se puede eliminar el almacén principal'
|
||||
]);
|
||||
}
|
||||
|
||||
// Verificar si tiene stock
|
||||
$hasStock = $warehouse->inventories()->wherePivot('stock', '>', 0)->exists();
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ public function rules(): array
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:100'],
|
||||
'description' => ['nullable', 'string', 'max:225'],
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@ public function rules(): array
|
||||
return [
|
||||
'name' => ['nullable', 'string', 'max:100'],
|
||||
'description' => ['nullable', 'string', 'max:225'],
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
@ -31,6 +32,7 @@ public function messages(): array
|
||||
'name.max' => 'El nombre no debe exceder los 100 caracteres.',
|
||||
'description.string' => 'La descripción debe ser una cadena de texto.',
|
||||
'description.max' => 'La descripción no debe exceder los 225 caracteres.',
|
||||
'is_active.boolean' => 'El campo activo debe ser verdadero o falso.',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
32
app/Http/Requests/App/SubcategoryStoreRequest.php
Normal file
32
app/Http/Requests/App/SubcategoryStoreRequest.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php namespace App\Http\Requests\App;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SubcategoryStoreRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['required', 'string', 'max:100'],
|
||||
'description' => ['nullable', 'string', 'max:255'],
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'name.required' => 'El nombre es obligatorio.',
|
||||
'name.string' => 'El nombre debe ser una cadena de texto.',
|
||||
'name.max' => 'El nombre no debe exceder los 100 caracteres.',
|
||||
'description.string' => 'La descripción debe ser una cadena de texto.',
|
||||
'description.max' => 'La descripción no debe exceder los 255 caracteres.',
|
||||
'is_active.boolean' => 'El campo activo debe ser verdadero o falso.',
|
||||
];
|
||||
}
|
||||
}
|
||||
31
app/Http/Requests/App/SubcategoryUpdateRequest.php
Normal file
31
app/Http/Requests/App/SubcategoryUpdateRequest.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php namespace App\Http\Requests\App;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SubcategoryUpdateRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => ['nullable', 'string', 'max:100'],
|
||||
'description' => ['nullable', 'string', 'max:255'],
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'name.string' => 'El nombre debe ser una cadena de texto.',
|
||||
'name.max' => 'El nombre no debe exceder los 100 caracteres.',
|
||||
'description.string' => 'La descripción debe ser una cadena de texto.',
|
||||
'description.max' => 'La descripción no debe exceder los 255 caracteres.',
|
||||
'is_active.boolean' => 'El campo activo debe ser verdadero o falso.',
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* Descripción
|
||||
@ -15,6 +16,8 @@
|
||||
*/
|
||||
class Category extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
@ -25,6 +28,11 @@ class Category extends Model
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
|
||||
public function subcategories()
|
||||
{
|
||||
return $this->hasMany(Subcategory::class);
|
||||
}
|
||||
|
||||
public function inventories()
|
||||
{
|
||||
return $this->hasMany(Inventory::class);
|
||||
|
||||
@ -22,6 +22,7 @@ class Inventory extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'category_id',
|
||||
'subcategory_id',
|
||||
'unit_of_measure_id',
|
||||
'name',
|
||||
'key_sat',
|
||||
@ -76,6 +77,11 @@ public function category()
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
public function subcategory()
|
||||
{
|
||||
return $this->belongsTo(Subcategory::class);
|
||||
}
|
||||
|
||||
public function unitOfMeasure()
|
||||
{
|
||||
return $this->belongsTo(UnitOfMeasurement::class);
|
||||
|
||||
30
app/Models/Subcategory.php
Normal file
30
app/Models/Subcategory.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Subcategory extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $fillable = [
|
||||
'category_id',
|
||||
'name',
|
||||
'description',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
];
|
||||
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
public function inventories()
|
||||
{
|
||||
return $this->hasMany(Inventory::class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('subcategories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('category_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('name');
|
||||
$table->text('description')->nullable();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('subcategories');
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('inventories', function (Blueprint $table) {
|
||||
$table->foreignId('subcategory_id')->nullable()->after('category_id')->constrained()->nullOnDelete();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('inventories', function (Blueprint $table) {
|
||||
$table->dropForeign(['subcategory_id']);
|
||||
$table->dropColumn('subcategory_id');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -3,6 +3,7 @@
|
||||
use App\Http\Controllers\App\BundleController;
|
||||
use App\Http\Controllers\App\CashRegisterController;
|
||||
use App\Http\Controllers\App\CategoryController;
|
||||
use App\Http\Controllers\App\SubcategoryController;
|
||||
use App\Http\Controllers\App\ClientController;
|
||||
use App\Http\Controllers\App\ClientTierController;
|
||||
use App\Http\Controllers\App\ExcelController;
|
||||
@ -85,6 +86,15 @@
|
||||
//CATEGORIAS
|
||||
Route::resource('categorias', CategoryController::class);
|
||||
|
||||
// SUBCATEGORIAS
|
||||
Route::prefix('categorias/{category}/subcategorias')->group(function () {
|
||||
Route::get('/', [SubcategoryController::class, 'index']);
|
||||
Route::post('/', [SubcategoryController::class, 'store']);
|
||||
Route::get('/{subcategory}', [SubcategoryController::class, 'show']);
|
||||
Route::put('/{subcategory}', [SubcategoryController::class, 'update']);
|
||||
Route::delete('/{subcategory}', [SubcategoryController::class, 'destroy']);
|
||||
});
|
||||
|
||||
//BUNDLES/KITS
|
||||
Route::resource('bundles', BundleController::class);
|
||||
Route::prefix('bundles')->group(function () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user