feat: agregar soporte para almacenamiento en masa de subcategorías y validaciones en la solicitud de creación

This commit is contained in:
Juan Felipe Zapata Moreno 2026-03-02 13:12:54 -06:00
parent 48fe26899a
commit 3d5198a65a
5 changed files with 80 additions and 4 deletions

View File

@ -52,9 +52,23 @@ public function index(Request $request)
$products = $products->orderBy('name')
->paginate(config('app.pagination'));
// Stock del almacén principal por producto
$mainWarehouseId = DB::table('warehouses')->where('is_main', true)->value('id');
$mainWarehouseStocks = $mainWarehouseId
? DB::table('inventory_warehouse')
->where('warehouse_id', $mainWarehouseId)
->whereIn('inventory_id', $products->pluck('id')->toArray())
->pluck('stock', 'inventory_id')
: collect();
$products->each(function ($product) use ($mainWarehouseStocks) {
$product->main_warehouse_stock = (float) ($mainWarehouseStocks[$product->id] ?? 0);
});
return ApiResponse::OK->response([
'products' => $products,
'total_inventory_value' => round($totalInventoryValue, 2)
'total_inventory_value' => round($totalInventoryValue, 2),
'main_warehouse_id' => $mainWarehouseId,
]);
}

View File

@ -29,6 +29,15 @@ public function show(Category $category, Subcategory $subcategory)
public function store(SubcategoryStoreRequest $request, Category $category)
{
if($request->isBulk()){
$subcategorias = collect($request->validated())
->map(fn($data) => $category->subcategories()->create($data));
return ApiResponse::OK->response([
'models' => $subcategorias,
]);
}
$subcategoria = $category->subcategories()->create($request->validated());
return ApiResponse::OK->response([
@ -47,6 +56,12 @@ public function update(SubcategoryUpdateRequest $request, Category $category, Su
public function destroy(Category $category, Subcategory $subcategory)
{
if ($subcategory->inventories()->exists()) {
return ApiResponse::BAD_REQUEST->response([
'message' => 'No se puede eliminar la subclasificación porque tiene productos asociados.'
]);
}
$subcategory->delete();
return ApiResponse::OK->response();

View File

@ -11,6 +11,13 @@ public function authorize(): bool
public function rules(): array
{
if($this->isBulk()) {
return [
'*.name' => ['required', 'string', 'max:100'],
'*.description' => ['nullable', 'string', 'max:255'],
'*.is_active' => ['nullable', 'boolean'],
];
}
return [
'name' => ['required', 'string', 'max:100'],
'description' => ['nullable', 'string', 'max:255'],
@ -21,12 +28,24 @@ public function rules(): array
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.',
'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.',
];
}
/**
* Detecta si el payload es un arreglo de objetos
*/
public function isBulk(): bool
{
return is_array($this->all()) && array_is_list($this->all());
}
}

View File

@ -120,7 +120,7 @@ private function createNewProduct(array $row)
// Buscar unidad de medida (requerida)
$unitId = null;
if (!empty($row['unidad_medida'])) {
$unit = \App\Models\UnitOfMeasurement::where('name', trim($row['unidad_medida']))
$unit = UnitOfMeasurement::where('name', trim($row['unidad_medida']))
->orWhere('abbreviation', trim($row['unidad_medida']))
->first();
@ -133,7 +133,7 @@ private function createNewProduct(array $row)
}
} else {
// Si no se proporciona, usar 'Pieza' por defecto
$unit = \App\Models\UnitOfMeasurement::where('name', 'Pieza')->first();
$unit = UnitOfMeasurement::where('name', 'Pieza')->first();
if ($unit) {
$unitId = $unit->id;
} else {

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('inventories', function (Blueprint $table) {
$table->string('key_sat')->nullable()->change();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('inventories', function (Blueprint $table) {
$table->integer('key_sat')->nullable()->change();
});
}
};