Cambios en ventas para ver el "ticket" cuando registras la venta

This commit is contained in:
BryamE
2026-01-08 20:52:36 -03:00
parent 8f10e3595d
commit b8282fdf06
4 changed files with 170 additions and 16 deletions
+19 -6
View File
@@ -41,7 +41,8 @@ class SaleController extends Controller
]); ]);
try { try {
DB::transaction(function () use ($request) { // Variable para guardar el objeto venta y usarlo fuera del closure
$sale = DB::transaction(function () use ($request) {
$totalSale = 0; $totalSale = 0;
foreach ($request->items as $item) { foreach ($request->items as $item) {
@@ -54,7 +55,7 @@ class SaleController extends Controller
} }
//cabecera //cabecera
$sale = Sale::create([ $newSale = Sale::create([
//'user_id' => auth()->id(), //empleado logueado //'user_id' => auth()->id(), //empleado logueado
'client_id' => $request->client_id, 'client_id' => $request->client_id,
'total' => $totalSale, 'total' => $totalSale,
@@ -65,7 +66,7 @@ class SaleController extends Controller
$product = Product::find($item['product_id']); $product = Product::find($item['product_id']);
SaleDetail::create([ SaleDetail::create([
'sale_id' => $sale->id, 'sale_id' => $newSale->id,
'product_id' => $product->id, 'product_id' => $product->id,
'quantity' => $item['quantity'], 'quantity' => $item['quantity'],
'price' => $product->price, 'price' => $product->price,
@@ -74,15 +75,27 @@ class SaleController extends Controller
$product->stock_quantity = $nuevoStock; $product->stock_quantity = $nuevoStock;
$product->save(); $product->save();
} }
return $newSale; // Retornamos la venta creada fuera de la transacción
}); });
// 5. REDIRECCIÓN DE ÉXITO // 4. REDIRECCIÓN AL DETALLE (FACTURA)
// Redirigimos al usuario con un mensaje flash [cite: 668] // Usamos la variable $sale que nos devolvió la transacción
return redirect()->route('sales.create')->with('success', '¡Venta registrada correctamente!'); return redirect()->route('sales.show', $sale)->with('success', '¡Venta registrada exitosamente!');
} catch (\Exception $e) { } catch (\Exception $e) {
// Si algo falló (ej: falta stock), volvemos atrás con el error // Si algo falló (ej: falta stock), volvemos atrás con el error
return back()->with('error', 'Error en la venta: ' . $e->getMessage()); return back()->with('error', 'Error en la venta: ' . $e->getMessage());
} }
} }
/**
* Muestra el detalle de una venta específica.
*/
public function show(Sale $sale)
{
// Cargamos la venta con el cliente y los detalles
$sale->load(['client', 'details.product']);
return view('sales.show', compact('sale'));
}
} }
+1 -3
View File
@@ -56,9 +56,7 @@
${{ number_format($sale->total, 2, ',', '.') }} ${{ number_format($sale->total, 2, ',', '.') }}
</td> </td>
<td class="px-6 py-4 text-center"> <td class="px-6 py-4 text-center">
<button class="text-blue-400 hover:text-blue-300 font-medium text-sm transition-colors"> <a href="{{ route('sales.show', $sale) }}" class="font-medium text-blue-400 hover:underline mr-3">Ver Detalle</a>
Ver Detalle
</button>
</td> </td>
</tr> </tr>
@empty @empty
+149
View File
@@ -0,0 +1,149 @@
<x-layout title="Detalle de Venta #{{ $sale->id }}">
<!-- Mensajes de Alerta -->
<x-ui.alert />
<!-- Encabezado de Navegación -->
<div class="w-full flex justify-between items-center mb-8 print:hidden">
<a href="{{ route('sales.index') }}" class="text-gray-400 hover:text-white flex items-center gap-2 transition-colors">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"></path></svg>
Volver al Historial
</a>
<button onclick="window.print()" class="px-5 py-2.5 bg-neutral-800 text-neon-lime border border-neon-lime/30 font-bold rounded-lg hover:bg-neon-lime hover:text-neutral-900 transition-colors flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"></path></svg>
Imprimir / Guardar PDF
</button>
</div>
<!-- Contenedor "Hoja" de la Factura -->
<div class="max-w-3xl mx-auto bg-white text-neutral-900 rounded-xl shadow-2xl overflow-hidden print:shadow-none print:w-full print:max-w-none">
<!-- Cabecera Factura -->
<div class="p-8 border-b-2 border-gray-100 flex justify-between items-start bg-gray-50 print:bg-white">
<div>
<!-- Logo Simulado -->
<div class="flex items-center gap-2 mb-4">
<div class="h-8 w-8 bg-neutral-900 rounded-full flex items-center justify-center text-neon-lime">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
</div>
<span class="text-2xl font-black uppercase tracking-wide text-neutral-900">
CICLES<span class="text-lime-800"> LAUCK</span>
</span>
</div>
<p class="text-sm text-gray-500">
Av. Francisco Ramírez 1389<br>
Paraná, Entre Ríos<br>
Tel: 343 422-0103
</p>
</div>
<div class="text-right">
<h2 class="text-sm font-bold text-gray-400 uppercase tracking-widest mb-1">Comprobante de Venta</h2>
<div class="text-4xl font-mono font-bold text-neutral-900">#{{ str_pad($sale->id, 5, '0', STR_PAD_LEFT) }}</div>
<div class="mt-2 text-sm text-gray-600">
Fecha: <strong>{{ $sale->created_at->format('d/m/Y') }}</strong><br>
Hora: {{ $sale->created_at->format('H:i') }} hs
</div>
</div>
</div>
<!-- Datos del Cliente -->
<div class="p-8 grid grid-cols-2 gap-8">
<div>
<h3 class="text-xs font-bold text-gray-400 uppercase mb-2">Facturado A:</h3>
@if($sale->client)
<p class="font-bold text-lg">{{ $sale->client->name }}</p>
<p class="text-gray-600 text-sm">{{ $sale->client->phone }}</p>
<p class="text-gray-600 text-sm">{{ $sale->client->email }}</p>
@if($sale->client->address)
<p class="text-gray-600 text-sm mt-1">{{ $sale->client->address }}</p>
@endif
@else
<p class="font-bold text-lg text-gray-500 italic">Consumidor Final</p>
<p class="text-gray-400 text-sm">Venta anónima de mostrador</p>
@endif
</div>
<div class="text-right">
<h3 class="text-xs font-bold text-gray-400 uppercase mb-2">Método de Pago:</h3>
<span class="inline-block bg-gray-100 text-gray-800 text-sm font-bold px-3 py-1 rounded border border-gray-200">
{{ $sale->payment_method }}
</span>
</div>
</div>
<!-- Tabla de Detalles -->
<div class="px-8 pb-8">
<table class="w-full text-sm text-left">
<thead class="bg-gray-100 text-gray-600 uppercase font-bold text-xs">
<tr>
<th class="px-4 py-3 rounded-l-lg">Producto</th>
<th class="px-4 py-3 text-right">Precio Unit.</th>
<th class="px-4 py-3 text-center">Cant.</th>
<th class="px-4 py-3 text-right rounded-r-lg">Subtotal</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100">
@foreach($sale->details as $detail)
<tr>
<td class="px-4 py-4">
<div class="font-bold text-gray-900">{{ $detail->product->name }}</div>
<div class="text-xs text-gray-500 font-mono">{{ $detail->product->sku }}</div>
</td>
<td class="px-4 py-4 text-right font-mono text-gray-600">
${{ number_format($detail->price, 2, ',', '.') }}
</td>
<td class="px-4 py-4 text-center font-bold text-gray-900">
{{ $detail->quantity }}
</td>
<td class="px-4 py-4 text-right font-mono font-bold text-gray-900">
${{ number_format($detail->price * $detail->quantity, 2, ',', '.') }}
</td>
</tr>
@endforeach
</tbody>
<tfoot class="border-t-2 border-gray-100">
<tr>
<td colspan="3" class="px-4 pt-6 text-right text-gray-500 uppercase font-bold text-sm">Total a Pagar</td>
<td class="px-4 pt-6 text-right text-3xl font-black text-gray-900">
${{ number_format($sale->total, 2, ',', '.') }}
</td>
</tr>
</tfoot>
</table>
</div>
<!-- Footer Factura -->
<div class="bg-gray-50 p-6 text-center border-t border-gray-100 print:bg-white">
<p class="text-sm text-gray-500 font-medium">¡Gracias por tu compra!</p>
<p class="text-xs text-gray-400 mt-1">Documento no valido como factura.</p>
</div>
</div>
<!-- Estilos específicos para impresión -->
<style>
@media print {
body * {
visibility: hidden;
}
.max-w-3xl, .max-w-3xl * {
visibility: visible;
}
.max-w-3xl {
position: absolute;
left: 0;
top: 0;
width: 100%;
margin: 0;
box-shadow: none;
}
/* Ocultar elementos del layout */
nav, footer, header {
display: none !important;
}
}
</style>
</x-layout>
+1 -7
View File
@@ -43,13 +43,7 @@ Route::middleware(['auth'])->group(function () {
Route::resource('productos', ProductosController::class)->parameters([ Route::resource('productos', ProductosController::class)->parameters([
'productos' => 'product' 'productos' => 'product'
]); ]);
Route::resource('sales', SaleController::class)->only(['index', 'create', 'store', 'show']);
Route::controller(SaleController::class)->prefix('sales')->name('sales.')->group(function () {
Route::get('/', 'index')->name('index');
Route::get('/create', 'create')->name('create');
Route::post('/', 'store')->name('store');
Route::get('/{sale}', 'show')->name('show');
});
}); });