cotizaweb/app/Http/Controllers/CotizacionController.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

280 lines
8.0 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;
use Barryvdh\DomPDF\Facade\Pdf;
class CotizacionController extends Controller
{
// Listado de cotizaciones
public function pdf(Cotizacion $cotizacion)
{
$cotizacion->load('cliente', 'items.producto');
$pdf = Pdf::loadView('cotizaciones.pdf', compact('cotizacion'))
->setPaper('letter', 'portrait');
return $pdf->download('Cotizacion_'.$cotizacion->id.'.pdf');
}
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 POS para crear cotización
public function create()
{
$user = auth()->user();
if ($user->hasRole('super-admin')) {
$clientes = Client::orderBy('nombre')->get();
$productos = Producto::orderBy('nombre')->get();
} else {
$clientes = Client::where('company_id', $user->company_id)
->orderBy('nombre')
->get();
$productos = Producto::where('company_id', $user->company_id)
->orderBy('nombre')
->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',
]);
$token = Str::uuid()->toString();
$subtotal = 0;
$totalDescuento = 0;
foreach ($request->productos as $item) {
$bruto = $item['cantidad'] * $item['precio_unitario'];
// porcentaje enviado desde la vista
$porcentaje = $item['descuento_porcentaje'] ?? 0;
// monto del descuento
$descuentoMonto = $item['descuento_monto'] ?? ($bruto * ($porcentaje / 100));
$subtotal += $bruto;
$totalDescuento += $descuentoMonto;
}
$neto = $subtotal - $totalDescuento;
$iva = $neto * 0.16;
$total = $neto + $iva;
$cotizacion = Cotizacion::create([
'company_id' => $user->company_id,
'cliente_id' => $request->cliente_id,
'token' => $token,
'estado' => 'pendiente',
'subtotal' => $subtotal,
'iva' => $iva,
'total' => $total
]);
foreach ($request->productos as $item) {
CotizacionItem::create([
'cotizacion_id' => $cotizacion->id,
'producto_id' => $item['producto_id'],
'cantidad' => $item['cantidad'],
'precio_unitario' => $item['precio_unitario'],
'descuento_porcentaje' => $item['descuento_porcentaje'] ?? 0,
'descuento_monto' => $item['descuento_monto'] ?? 0,
'total' => ($item['precio_unitario'] * $item['cantidad']) - ($item['descuento_monto'] ?? 0)
]);
}
audit_log(
'created',
'cotizaciones',
$cotizacion,
null,
$cotizacion->toArray()
);
return redirect()->route('cotizaciones.index')
->with('success', 'Cotización creada correctamente.');
}
// Editar cotización
public function edit(Cotizacion $cotizacion)
{
$this->authorizeCotizacion($cotizacion);
$user = auth()->user();
if ($user->hasRole('super-admin')) {
$clientes = Client::orderBy('nombre')->get();
$productos = Producto::orderBy('nombre')->get();
} else {
$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
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',
]);
$oldData = $cotizacion->toArray();
$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,
]);
$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'],
]);
}
audit_log(
'updated',
'cotizaciones',
$cotizacion,
$oldData,
$cotizacion->fresh()->toArray()
);
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.');
}
// Vista pública
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'));
}
public function aprobar($token)
{
$cotizacion = Cotizacion::where('token', $token)->firstOrFail();
$cotizacion->update([
'estado' => 'aprobada',
'aprobada_en' => now(),
'aprobada_por' => 'Cliente'
]);
return view('cotizaciones.aprobada', compact('cotizacion'));
}
public function rechazar($token)
{
$cotizacion = Cotizacion::where('token', $token)->firstOrFail();
$cotizacion->update([
'estado' => 'rechazada',
'aprobada_en' => now(),
'aprobada_por' => 'Cliente'
]);
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');
}
}
}