cotizaweb/app/Http/Controllers/CotizacionController copy.php
jesusfb 161fcee049
Some checks are pending
Deploy to EC2 cotiza / deploy (push) Waiting to run
first commit
2026-04-24 12:53:27 -07:00

258 lines
7.5 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Cotizacion;
use App\Models\CotizacionItem;
use App\Models\Producto;
use App\Models\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class CotizacionController extends Controller
{
// Listado de cotizaciones
public function index()
{
$user = auth()->user();
if ($user->hasRole('super-admin')) {
$cotizaciones = Cotizacion::with(['cliente','items'])->latest()->get();
} else {
$cotizaciones = Cotizacion::with(['cliente','items'])
->where('company_id', $user->company_id)
->latest()
->get();
}
return view('cotizaciones.index', compact('cotizaciones'));
}
// Formulario para crear cotización
public function create()
{
$user = auth()->user();
$clientes = Client::where('company_id', $user->company_id)->get();
$productos = Producto::where('company_id', $user->company_id)->get();
return view('cotizaciones.create', compact('clientes','productos'));
}
// Guardar cotización + items
public function store(Request $request)
{
$user = auth()->user();
$request->validate([
'cliente_id' => 'required|exists:clients,id',
'productos' => 'required|array',
'productos.*.producto_id' => 'required|exists:productos,id',
'productos.*.cantidad' => 'required|integer|min:1',
'productos.*.precio_unitario' => 'required|numeric|min:0',
]);
// Generar token único para link
$token = Str::uuid()->toString();
// Calcular totales
$subtotal = 0;
foreach ($request->productos as $item) {
$subtotal += $item['cantidad'] * $item['precio_unitario'];
}
$iva = $subtotal * 0.16; // 16% IVA
$total = $subtotal + $iva;
$cotizacionData = [
'company_id' => $user->company_id,
'cliente_id' => $request->cliente_id,
'token' => $token,
'estado' => 'pendiente',
'subtotal' => $subtotal,
'iva' => $iva,
'total' => $total
];
// Guardamos en variable para auditoría
$cotizacion = Cotizacion::create($cotizacionData);
// Guardar items
foreach ($request->productos as $item) {
CotizacionItem::create([
'cotizacion_id' => $cotizacion->id,
'producto_id' => $item['producto_id'],
'cantidad' => $item['cantidad'],
'precio_unitario' => $item['precio_unitario'],
'total' => $item['cantidad'] * $item['precio_unitario'],
]);
}
// Auditoría
audit_log(
'created',
'cotizaciones',
$cotizacion,
null,
$cotizacion->toArray()
);
return redirect()->route('cotizaciones.index')
->with('success', 'Cotización creada correctamente.');
}
// Formulario para editar cotización
public function edit(Cotizacion $cotizacion)
{
$this->authorizeCotizacion($cotizacion);
$user = auth()->user();
$clientes = Client::where('company_id', $user->company_id)->get();
$productos = Producto::where('company_id', $user->company_id)->get();
return view('cotizaciones.edit', compact('cotizacion','clientes','productos'));
}
// Actualizar cotización y sus items
public function update(Request $request, Cotizacion $cotizacion)
{
$this->authorizeCotizacion($cotizacion);
$request->validate([
'cliente_id' => 'required|exists:clients,id',
'productos' => 'required|array',
'productos.*.producto_id' => 'required|exists:productos,id',
'productos.*.cantidad' => 'required|integer|min:1',
'productos.*.precio_unitario' => 'required|numeric|min:0',
]);
// Capturar estado anterior para auditoría
$oldData = $cotizacion->toArray();
// Recalcular totales
$subtotal = 0;
foreach ($request->productos as $item) {
$subtotal += $item['cantidad'] * $item['precio_unitario'];
}
$iva = $subtotal * 0.16;
$total = $subtotal + $iva;
$cotizacion->update([
'cliente_id' => $request->cliente_id,
'subtotal' => $subtotal,
'iva' => $iva,
'total' => $total,
]);
// Reemplazar items (simplificación)
$cotizacion->items()->delete();
foreach ($request->productos as $item) {
CotizacionItem::create([
'cotizacion_id' => $cotizacion->id,
'producto_id' => $item['producto_id'],
'cantidad' => $item['cantidad'],
'precio_unitario' => $item['precio_unitario'],
'total' => $item['cantidad'] * $item['precio_unitario'],
]);
}
// Auditoría
$newData = $cotizacion->fresh()->toArray();
audit_log(
'updated',
'cotizaciones',
$cotizacion,
$oldData,
$newData
);
return redirect()->route('cotizaciones.index')
->with('success', 'Cotización actualizada correctamente.');
}
// Eliminar cotización
public function destroy(Cotizacion $cotizacion)
{
$this->authorizeCotizacion($cotizacion);
$deletedData = $cotizacion->toArray();
$cotizacion->delete();
audit_log(
'deleted',
'cotizaciones',
$cotizacion,
$deletedData,
null
);
return redirect()->route('cotizaciones.index')
->with('success', 'Cotización eliminada correctamente.');
}
// Mostrar cotización vía link público
public function showCliente($token)
{
$cotizacion = Cotizacion::where('token', $token)->with('items.producto')->firstOrFail();
if ($cotizacion->estado === 'pendiente') {
$cotizacion->update(['estado' => 'vista']);
}
return view('cotizaciones.show_cliente', compact('cotizacion'));
}
// Aprobar cotización
public function aprobar($token)
{
$cotizacion = Cotizacion::where('token', $token)->firstOrFail();
$cotizacion->update([
'estado' => 'aprobada',
'aprobada_en' => now(),
'aprobada_por' => 'Cliente'
]);
audit_log(
'updated',
'cotizaciones',
$cotizacion,
null,
$cotizacion->toArray()
);
return view('cotizaciones.aprobada', compact('cotizacion'));
}
// Rechazar cotización
public function rechazar($token)
{
$cotizacion = Cotizacion::where('token', $token)->firstOrFail();
$cotizacion->update([
'estado' => 'rechazada',
'aprobada_en' => now(),
'aprobada_por' => 'Cliente'
]);
audit_log(
'updated',
'cotizaciones',
$cotizacion,
null,
$cotizacion->toArray()
);
return view('cotizaciones.rechazada', compact('cotizacion'));
}
// Seguridad multiempresa
private function authorizeCotizacion(Cotizacion $cotizacion)
{
$user = auth()->user();
if (!$user->hasRole('super-admin') && $cotizacion->company_id !== $user->company_id) {
abort(403,'No autorizado');
}
}
}