diff --git a/app/Http/Controllers/App/FacturaDataController.php b/app/Http/Controllers/App/FacturaDataController.php index 5bee255..69cd204 100644 --- a/app/Http/Controllers/App/FacturaDataController.php +++ b/app/Http/Controllers/App/FacturaDataController.php @@ -32,7 +32,7 @@ public function show(string $invoiceNumber) // Si ya tiene datos de facturación if ($sale->client_id) { - return ApiResponse::INTERNAL_ERROR->response([ + return ApiResponse::NO_CONTENT->response([ 'message' => 'Esta venta ya tiene datos de facturación registrados', 'client' => $sale->client, 'sale' => $this->formatSaleData($sale) @@ -60,7 +60,7 @@ public function store(Request $request, string $invoiceNumber) } if ($sale->client_id) { - return ApiResponse::BAD_REQUEST->response([ + return ApiResponse::NO_CONTENT->response([ 'message' => 'Esta venta ya tiene datos de facturación registrados' ]); } diff --git a/app/Http/Controllers/App/InventoryController.php b/app/Http/Controllers/App/InventoryController.php index 526b38d..92f7948 100644 --- a/app/Http/Controllers/App/InventoryController.php +++ b/app/Http/Controllers/App/InventoryController.php @@ -130,7 +130,8 @@ public function downloadTemplate() 'stock', 'costo', 'precio_venta', - 'impuesto' + 'impuesto', + 'numeros_serie' ]; $exampleData = [ @@ -149,10 +150,11 @@ public function downloadTemplate() 'sku' => 'COCA-600', 'codigo_barras' => '750227686666', 'categoria' => 'Bebidas', - 'stock' => 100, + 'stock' => 5, 'costo' => 12.50, 'precio_venta' => 18.00, - 'impuesto' => 8 + 'impuesto' => 8, + 'numeros_serie' => '' // Dejar vacío si el producto no maneja seriales individuales ], [ 'nombre' => 'Laptop HP Pavilion 15', @@ -162,7 +164,8 @@ public function downloadTemplate() 'stock' => 5, 'costo' => 8500.00, 'precio_venta' => 12000.00, - 'impuesto' => 16 + 'impuesto' => 16, + 'numeros_serie' => 'HP-LAP-15-01,HP-LAP-15-02,HP-LAP-15-03,HP-LAP-15-04,HP-LAP-15-05' ], ]; diff --git a/app/Http/Controllers/App/InventorySerialController.php b/app/Http/Controllers/App/InventorySerialController.php index f4ba8d4..1cb91d8 100644 --- a/app/Http/Controllers/App/InventorySerialController.php +++ b/app/Http/Controllers/App/InventorySerialController.php @@ -20,9 +20,9 @@ class InventorySerialController extends Controller /** * Listar seriales de un producto */ - public function index(Inventory $inventory, Request $request) + public function index(Inventory $inventario, Request $request) { - $query = $inventory->serials(); + $query = $inventario->serials(); if ($request->has('status')) { $query->where('status', $request->status); @@ -32,22 +32,22 @@ public function index(Inventory $inventory, Request $request) $query->where('serial_number', 'like', "%{$request->q}%"); } - $serials = $query->orderBy('created_at', 'desc') + $serials = $query->orderBy('serial_number', 'ASC') ->paginate(config('app.pagination')); return ApiResponse::OK->response([ 'serials' => $serials, - 'inventory' => $inventory->load('category'), + 'inventory' => $inventario->load('category'), ]); } /** * Mostrar un serial específico */ - public function show(Inventory $inventory, InventorySerial $serial) + public function show(Inventory $inventario, InventorySerial $serial) { // Verificar que el serial pertenece al inventario - if ($serial->inventory_id !== $inventory->id) { + if ($serial->inventory_id !== $inventario->id) { return ApiResponse::NOT_FOUND->response([ 'message' => 'Serial no encontrado para este inventario' ]); @@ -55,14 +55,14 @@ public function show(Inventory $inventory, InventorySerial $serial) return ApiResponse::OK->response([ 'serial' => $serial->load('saleDetail'), - 'inventory' => $inventory->load('category'), + 'inventory' => $inventario->load('category'), ]); } /** * Crear un nuevo serial */ - public function store(Inventory $inventory, Request $request) + public function store(Inventory $inventario, Request $request) { $request->validate([ 'serial_number' => ['required', 'string', 'unique:inventory_serials,serial_number'], @@ -70,28 +70,28 @@ public function store(Inventory $inventory, Request $request) ]); $serial = InventorySerial::create([ - 'inventory_id' => $inventory->id, + 'inventory_id' => $inventario->id, 'serial_number' => $request->serial_number, 'status' => 'disponible', 'notes' => $request->notes, ]); // Sincronizar stock - $inventory->syncStock(); + $inventario->syncStock(); return ApiResponse::CREATED->response([ 'serial' => $serial, - 'inventory' => $inventory->fresh(), + 'inventory' => $inventario->fresh(), ]); } /** * Actualizar un serial */ - public function update(Inventory $inventory, InventorySerial $serial, Request $request) + public function update(Inventory $inventario , InventorySerial $serial, Request $request) { // Verificar que el serial pertenece al inventario - if ($serial->inventory_id !== $inventory->id) { + if ($serial->inventory_id !== $inventario->id) { return ApiResponse::NOT_FOUND->response([ 'message' => 'Serial no encontrado para este inventario' ]); @@ -99,28 +99,28 @@ public function update(Inventory $inventory, InventorySerial $serial, Request $r $request->validate([ 'serial_number' => ['sometimes', 'string', 'unique:inventory_serials,serial_number,' . $serial->id], - 'status' => ['sometimes', 'in:disponible,vendido,dañado,reservado'], + 'status' => ['sometimes', 'in:disponible,vendido'], 'notes' => ['nullable', 'string'], ]); $serial->update($request->only(['serial_number', 'status', 'notes'])); // Sincronizar stock del inventario - $inventory->syncStock(); + $inventario->syncStock(); return ApiResponse::OK->response([ 'serial' => $serial->fresh(), - 'inventory' => $inventory->fresh(), + 'inventory' => $inventario->fresh(), ]); } /** * Eliminar un serial */ - public function destroy(Inventory $inventory, InventorySerial $serial) + public function destroy(Inventory $inventario, InventorySerial $serial) { // Verificar que el serial pertenece al inventario - if ($serial->inventory_id !== $inventory->id) { + if ($serial->inventory_id !== $inventario->id) { return ApiResponse::NOT_FOUND->response([ 'message' => 'Serial no encontrado para este inventario' ]); @@ -129,18 +129,18 @@ public function destroy(Inventory $inventory, InventorySerial $serial) $serial->delete(); // Sincronizar stock - $inventory->syncStock(); + $inventario->syncStock(); return ApiResponse::OK->response([ 'message' => 'Serial eliminado exitosamente', - 'inventory' => $inventory->fresh(), + 'inventory' => $inventario->fresh(), ]); } /** * Importar múltiples seriales */ - public function bulkStore(Inventory $inventory, Request $request) + public function bulkStore(Inventory $inventario, Request $request) { $request->validate([ 'serial_numbers' => ['required', 'array', 'min:1'], @@ -151,7 +151,7 @@ public function bulkStore(Inventory $inventory, Request $request) foreach ($request->serial_numbers as $serialNumber) { $serial = InventorySerial::create([ - 'inventory_id' => $inventory->id, + 'inventory_id' => $inventario->id, 'serial_number' => $serialNumber, 'status' => 'disponible', ]); @@ -160,12 +160,12 @@ public function bulkStore(Inventory $inventory, Request $request) } // Sincronizar stock - $inventory->syncStock(); + $inventario->syncStock(); return ApiResponse::CREATED->response([ 'serials' => $created, 'count' => count($created), - 'inventory' => $inventory->fresh(), + 'inventory' => $inventario->fresh(), ]); } } diff --git a/app/Imports/ProductsImport.php b/app/Imports/ProductsImport.php index 49fc27e..108b6c9 100644 --- a/app/Imports/ProductsImport.php +++ b/app/Imports/ProductsImport.php @@ -49,7 +49,7 @@ public function map($row): array 'costo' => $row['costo'] ?? null, 'precio_venta' => $row['precio_venta'] ?? null, 'impuesto' => $row['impuesto'] ?? null, - 'numeros_serie' => $row['numeros_serie'] ?? null, // Nueva columna: separados por comas + 'numeros_serie' => $row['numeros_serie'] ?? null, ]; } @@ -117,22 +117,15 @@ public function model(array $row) ]); } } + // Sincronizar stock basado en los seriales + $inventory->syncStock(); } else { - // Si no se proporcionan seriales, generar automáticamente - $stockQuantity = (int) $row['stock']; - - for ($i = 1; $i <= $stockQuantity; $i++) { - InventorySerial::create([ - 'inventory_id' => $inventory->id, - 'serial_number' => $inventory->sku . '-' . str_pad($i, 4, '0', STR_PAD_LEFT), - 'status' => 'disponible', - ]); - } + // Si no se proporcionan seriales, es un producto no serializado. + // Asignar el stock directamente desde la columna 'stock'. + $inventory->stock = (int) ($row['stock'] ?? 0); + $inventory->save(); } - // Sincronizar stock - $inventory->syncStock(); - $this->imported++; return $inventory; diff --git a/database/migrations/2025_12_30_151510_create_sale_details_table.php b/database/migrations/2025_12_30_151510_create_sale_details_table.php index 336cd36..4d5d331 100644 --- a/database/migrations/2025_12_30_151510_create_sale_details_table.php +++ b/database/migrations/2025_12_30_151510_create_sale_details_table.php @@ -19,7 +19,6 @@ public function up(): void $table->integer('quantity'); $table->decimal('unit_price', 10, 2); $table->decimal('subtotal', 10, 2); - $table->json('serial_numbers')->nullable(); $table->timestamps(); }); }