fix: actualizar respuestas de API para ventas con datos de facturación y ajustar seriales en inventarios

This commit is contained in:
Juan Felipe Zapata Moreno 2026-01-16 21:37:40 -06:00
parent 810aff1b0e
commit c1473cdb95
5 changed files with 40 additions and 45 deletions

View File

@ -32,7 +32,7 @@ public function show(string $invoiceNumber)
// Si ya tiene datos de facturación // Si ya tiene datos de facturación
if ($sale->client_id) { if ($sale->client_id) {
return ApiResponse::INTERNAL_ERROR->response([ return ApiResponse::NO_CONTENT->response([
'message' => 'Esta venta ya tiene datos de facturación registrados', 'message' => 'Esta venta ya tiene datos de facturación registrados',
'client' => $sale->client, 'client' => $sale->client,
'sale' => $this->formatSaleData($sale) 'sale' => $this->formatSaleData($sale)
@ -60,7 +60,7 @@ public function store(Request $request, string $invoiceNumber)
} }
if ($sale->client_id) { if ($sale->client_id) {
return ApiResponse::BAD_REQUEST->response([ return ApiResponse::NO_CONTENT->response([
'message' => 'Esta venta ya tiene datos de facturación registrados' 'message' => 'Esta venta ya tiene datos de facturación registrados'
]); ]);
} }

View File

@ -130,7 +130,8 @@ public function downloadTemplate()
'stock', 'stock',
'costo', 'costo',
'precio_venta', 'precio_venta',
'impuesto' 'impuesto',
'numeros_serie'
]; ];
$exampleData = [ $exampleData = [
@ -149,10 +150,11 @@ public function downloadTemplate()
'sku' => 'COCA-600', 'sku' => 'COCA-600',
'codigo_barras' => '750227686666', 'codigo_barras' => '750227686666',
'categoria' => 'Bebidas', 'categoria' => 'Bebidas',
'stock' => 100, 'stock' => 5,
'costo' => 12.50, 'costo' => 12.50,
'precio_venta' => 18.00, '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', 'nombre' => 'Laptop HP Pavilion 15',
@ -162,7 +164,8 @@ public function downloadTemplate()
'stock' => 5, 'stock' => 5,
'costo' => 8500.00, 'costo' => 8500.00,
'precio_venta' => 12000.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'
], ],
]; ];

View File

@ -20,9 +20,9 @@ class InventorySerialController extends Controller
/** /**
* Listar seriales de un producto * 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')) { if ($request->has('status')) {
$query->where('status', $request->status); $query->where('status', $request->status);
@ -32,22 +32,22 @@ public function index(Inventory $inventory, Request $request)
$query->where('serial_number', 'like', "%{$request->q}%"); $query->where('serial_number', 'like', "%{$request->q}%");
} }
$serials = $query->orderBy('created_at', 'desc') $serials = $query->orderBy('serial_number', 'ASC')
->paginate(config('app.pagination')); ->paginate(config('app.pagination'));
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'serials' => $serials, 'serials' => $serials,
'inventory' => $inventory->load('category'), 'inventory' => $inventario->load('category'),
]); ]);
} }
/** /**
* Mostrar un serial específico * 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 // Verificar que el serial pertenece al inventario
if ($serial->inventory_id !== $inventory->id) { if ($serial->inventory_id !== $inventario->id) {
return ApiResponse::NOT_FOUND->response([ return ApiResponse::NOT_FOUND->response([
'message' => 'Serial no encontrado para este inventario' 'message' => 'Serial no encontrado para este inventario'
]); ]);
@ -55,14 +55,14 @@ public function show(Inventory $inventory, InventorySerial $serial)
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'serial' => $serial->load('saleDetail'), 'serial' => $serial->load('saleDetail'),
'inventory' => $inventory->load('category'), 'inventory' => $inventario->load('category'),
]); ]);
} }
/** /**
* Crear un nuevo serial * Crear un nuevo serial
*/ */
public function store(Inventory $inventory, Request $request) public function store(Inventory $inventario, Request $request)
{ {
$request->validate([ $request->validate([
'serial_number' => ['required', 'string', 'unique:inventory_serials,serial_number'], 'serial_number' => ['required', 'string', 'unique:inventory_serials,serial_number'],
@ -70,28 +70,28 @@ public function store(Inventory $inventory, Request $request)
]); ]);
$serial = InventorySerial::create([ $serial = InventorySerial::create([
'inventory_id' => $inventory->id, 'inventory_id' => $inventario->id,
'serial_number' => $request->serial_number, 'serial_number' => $request->serial_number,
'status' => 'disponible', 'status' => 'disponible',
'notes' => $request->notes, 'notes' => $request->notes,
]); ]);
// Sincronizar stock // Sincronizar stock
$inventory->syncStock(); $inventario->syncStock();
return ApiResponse::CREATED->response([ return ApiResponse::CREATED->response([
'serial' => $serial, 'serial' => $serial,
'inventory' => $inventory->fresh(), 'inventory' => $inventario->fresh(),
]); ]);
} }
/** /**
* Actualizar un serial * 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 // Verificar que el serial pertenece al inventario
if ($serial->inventory_id !== $inventory->id) { if ($serial->inventory_id !== $inventario->id) {
return ApiResponse::NOT_FOUND->response([ return ApiResponse::NOT_FOUND->response([
'message' => 'Serial no encontrado para este inventario' 'message' => 'Serial no encontrado para este inventario'
]); ]);
@ -99,28 +99,28 @@ public function update(Inventory $inventory, InventorySerial $serial, Request $r
$request->validate([ $request->validate([
'serial_number' => ['sometimes', 'string', 'unique:inventory_serials,serial_number,' . $serial->id], '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'], 'notes' => ['nullable', 'string'],
]); ]);
$serial->update($request->only(['serial_number', 'status', 'notes'])); $serial->update($request->only(['serial_number', 'status', 'notes']));
// Sincronizar stock del inventario // Sincronizar stock del inventario
$inventory->syncStock(); $inventario->syncStock();
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'serial' => $serial->fresh(), 'serial' => $serial->fresh(),
'inventory' => $inventory->fresh(), 'inventory' => $inventario->fresh(),
]); ]);
} }
/** /**
* Eliminar un serial * Eliminar un serial
*/ */
public function destroy(Inventory $inventory, InventorySerial $serial) public function destroy(Inventory $inventario, InventorySerial $serial)
{ {
// Verificar que el serial pertenece al inventario // Verificar que el serial pertenece al inventario
if ($serial->inventory_id !== $inventory->id) { if ($serial->inventory_id !== $inventario->id) {
return ApiResponse::NOT_FOUND->response([ return ApiResponse::NOT_FOUND->response([
'message' => 'Serial no encontrado para este inventario' 'message' => 'Serial no encontrado para este inventario'
]); ]);
@ -129,18 +129,18 @@ public function destroy(Inventory $inventory, InventorySerial $serial)
$serial->delete(); $serial->delete();
// Sincronizar stock // Sincronizar stock
$inventory->syncStock(); $inventario->syncStock();
return ApiResponse::OK->response([ return ApiResponse::OK->response([
'message' => 'Serial eliminado exitosamente', 'message' => 'Serial eliminado exitosamente',
'inventory' => $inventory->fresh(), 'inventory' => $inventario->fresh(),
]); ]);
} }
/** /**
* Importar múltiples seriales * Importar múltiples seriales
*/ */
public function bulkStore(Inventory $inventory, Request $request) public function bulkStore(Inventory $inventario, Request $request)
{ {
$request->validate([ $request->validate([
'serial_numbers' => ['required', 'array', 'min:1'], 'serial_numbers' => ['required', 'array', 'min:1'],
@ -151,7 +151,7 @@ public function bulkStore(Inventory $inventory, Request $request)
foreach ($request->serial_numbers as $serialNumber) { foreach ($request->serial_numbers as $serialNumber) {
$serial = InventorySerial::create([ $serial = InventorySerial::create([
'inventory_id' => $inventory->id, 'inventory_id' => $inventario->id,
'serial_number' => $serialNumber, 'serial_number' => $serialNumber,
'status' => 'disponible', 'status' => 'disponible',
]); ]);
@ -160,12 +160,12 @@ public function bulkStore(Inventory $inventory, Request $request)
} }
// Sincronizar stock // Sincronizar stock
$inventory->syncStock(); $inventario->syncStock();
return ApiResponse::CREATED->response([ return ApiResponse::CREATED->response([
'serials' => $created, 'serials' => $created,
'count' => count($created), 'count' => count($created),
'inventory' => $inventory->fresh(), 'inventory' => $inventario->fresh(),
]); ]);
} }
} }

View File

@ -49,7 +49,7 @@ public function map($row): array
'costo' => $row['costo'] ?? null, 'costo' => $row['costo'] ?? null,
'precio_venta' => $row['precio_venta'] ?? null, 'precio_venta' => $row['precio_venta'] ?? null,
'impuesto' => $row['impuesto'] ?? 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 { } else {
// Si no se proporcionan seriales, generar automáticamente // Si no se proporcionan seriales, es un producto no serializado.
$stockQuantity = (int) $row['stock']; // Asignar el stock directamente desde la columna 'stock'.
$inventory->stock = (int) ($row['stock'] ?? 0);
for ($i = 1; $i <= $stockQuantity; $i++) { $inventory->save();
InventorySerial::create([
'inventory_id' => $inventory->id,
'serial_number' => $inventory->sku . '-' . str_pad($i, 4, '0', STR_PAD_LEFT),
'status' => 'disponible',
]);
}
} }
// Sincronizar stock
$inventory->syncStock();
$this->imported++; $this->imported++;
return $inventory; return $inventory;

View File

@ -19,7 +19,6 @@ public function up(): void
$table->integer('quantity'); $table->integer('quantity');
$table->decimal('unit_price', 10, 2); $table->decimal('unit_price', 10, 2);
$table->decimal('subtotal', 10, 2); $table->decimal('subtotal', 10, 2);
$table->json('serial_numbers')->nullable();
$table->timestamps(); $table->timestamps();
}); });
} }