280 lines
8.0 KiB
PHP
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');
|
|
}
|
|
}
|
|
}
|