cotizaweb/resources/views/cotizaciones/create.blade.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

355 lines
9.7 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@extends('layouts.app')
@section('content')
<section class="content py-3">
<div class="container-fluid">
<form method="POST" action="{{ route('cotizaciones.store') }}">
@csrf
<div class="row g-3">
{{-- ===================== PRODUCTOS ===================== --}}
<div class="col-lg-8">
<div class="card border-0 shadow-sm h-100">
<div class="card-body d-flex flex-column">
<h6 class="text-muted mb-2">Productos</h6>
<input type="text"
id="search"
class="form-control mb-3"
placeholder="Buscar producto por nombre...">
<div class="products-scroll">
@foreach($productos as $producto)
<div class="product-card"
data-id="{{ $producto->id }}"
data-name="{{ $producto->nombre }}"
data-price="{{ $producto->precio }}">
<div class="product-inner text-center">
@if($producto->foto)
<img src="{{ asset('storage/'.$producto->foto) }}"
class="product-img">
@else
<div class="product-img-placeholder">
<i class="bi bi-box"></i>
</div>
@endif
<div class="product-name">
{{ $producto->nombre }}
</div>
<div class="product-price">
${{ number_format($producto->precio,2) }}
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
</div>
{{-- ===================== TOTALES ===================== --}}
<div class="col-lg-4">
<div class="card border-0 shadow-sm total-card">
<div class="card-body">
<h6 class="text-muted mb-3">Resumen</h6>
<div class="total-row">
<span>Subtotal</span>
<span id="subtotal">$0.00</span>
</div>
<div class="total-row text-danger">
<span>Descuento</span>
<span id="total-desc">$0.00</span>
</div>
<div class="total-row">
<span>IVA (16%)</span>
<span id="iva">$0.00</span>
</div>
<hr>
<div class="total-final">
<span>Total</span>
<span id="total">$0.00</span>
</div>
<div>
<div class="mb-2">
<select name="cliente_id" class="form-control select2" required>
<option value="">Seleccionar cliente</option>
@foreach($clientes as $cliente)
<option value="{{ $cliente->id }}">
{{ $cliente->nombre ?? $cliente->name }}
</option>
@endforeach
</select>
</div>
<button class="btn btn-success btn-sm w-100">
Guardar Cotización
</button>
</div>
</div>
</div>
</div>
</div>
{{-- ===================== TABLA ===================== --}}
<div class="card border-0 shadow-sm mt-3">
<div class="card-header bg-dark text-white py-2">
Productos seleccionados
</div>
<div class="table-responsive">
<table class="table align-middle mb-0">
<thead class="table-light">
<tr>
<th>Producto</th>
<th width="170">Cantidad</th>
<th width="120">Precio</th>
<th width="170">Desc %</th>
<th width="120">Total</th>
<th width="60"></th>
</tr>
</thead>
<tbody id="cart-body"></tbody>
</table>
</div>
</div>
</form>
</div>
</section>
@endsection
@section('scripts')
<style>
/* ========= PRODUCTOS ========= */
.products-scroll{
display:flex;
gap:15px;
overflow-x:auto;
padding-bottom:5px;
}
.product-card{
min-width:160px;
cursor:pointer;
}
.product-inner{
background:#fff;
border-radius:10px;
padding:15px;
border:1px solid #eee;
transition:.2s;
}
.product-inner:hover{
transform:translateY(-3px);
box-shadow:0 6px 14px rgba(0,0,0,.08);
border-color:#0d6efd;
}
.product-img{
width:60px;
height:60px;
object-fit:cover;
border-radius:6px;
margin-bottom:6px;
}
.product-img-placeholder{
width:60px;
height:60px;
background:#f5f5f5;
border-radius:6px;
display:flex;
align-items:center;
justify-content:center;
margin:auto;
margin-bottom:6px;
}
.product-name{
font-size:14px;
font-weight:600;
min-height:34px;
}
.product-price{
color:#198754;
font-weight:700;
}
/* ========= TOTALES ========= */
.total-card{
position:sticky;
top:15px;
}
.total-row{
display:flex;
justify-content:space-between;
margin-bottom:6px;
font-size:14px;
}
.total-final{
display:flex;
justify-content:space-between;
font-size:22px;
font-weight:700;
color:#198754;
}
/* ========= TABLA ========= */
.table td{
vertical-align:middle;
}
</style>
<script>
const cart = {};
const IVA = 0.16;
const tbody = document.getElementById('cart-body');
function money(n){
return new Intl.NumberFormat('es-MX',{
style:'currency',
currency:'MXN'
}).format(n);
}
function render(){
tbody.innerHTML='';
let subtotal=0;
let totalDesc=0;
let index=0;
Object.values(cart).forEach(item=>{
const bruto=item.cantidad*item.precio;
const desc=bruto*(item.descuento/100);
const total=bruto-desc;
subtotal+=bruto;
totalDesc+=desc;
const tr=document.createElement('tr');
tr.innerHTML=`
<td>
${item.nombre}
<input type="hidden" name="productos[${index}][producto_id]" value="${Number(item.id)}">
<input type="hidden" name="productos[${index}][precio_unitario]" value="${Number(item.precio)}">
<input type="hidden" name="productos[${index}][cantidad]" value="${Number(item.cantidad)}">
<input type="hidden" name="productos[${index}][descuento_porcentaje]" value="${Number(item.descuento)}">
<input type="hidden" name="productos[${index}][descuento_monto]" value="${desc.toFixed(2)}">
</td>
<td>
<div class="input-group input-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="qty(${item.id},-1)">-</button>
<input type="number"
name="productos[${index}][cantidad]"
class="form-control text-center"
value="${item.cantidad}" min="1"
onchange="setQty(${item.id},this.value)">
<button type="button" class="btn btn-outline-secondary" onclick="qty(${item.id},1)">+</button>
</div>
</td>
<td>${money(item.precio)}</td>
<td>
<div class="input-group input-group-sm">
<button type="button" class="btn btn-outline-secondary" onclick="descBtn(${item.id},-1)">-</button>
<input type="number"
class="form-control text-center"
value="${item.descuento}" min="0" max="100"
onchange="setDesc(${item.id},this.value)">
<button type="button" class="btn btn-outline-secondary" onclick="descBtn(${item.id},1)">+</button>
</div>
</td>
<td>${money(total)}</td>
<td>
<button type="button" class="btn btn-outline-danger btn-sm"
onclick="removeItem(${item.id})">×</button>
</td>
`;
tbody.appendChild(tr);
index++;
});
const neto=subtotal-totalDesc;
document.getElementById('subtotal').innerText=money(subtotal);
document.getElementById('total-desc').innerText='- '+money(totalDesc);
document.getElementById('iva').innerText=money(neto*IVA);
document.getElementById('total').innerText=money(neto*(1+IVA));
}
function addProduct(el){
const id=el.dataset.id;
if(!cart[id]){
cart[id]={
id,
nombre:el.dataset.name,
precio:parseFloat(el.dataset.price),
cantidad:1,
descuento:0
};
}else{
cart[id].cantidad++;
}
render();
}
function qty(id,d){ cart[id].cantidad=Math.max(1,cart[id].cantidad+d); render(); }
function setQty(id,v){ cart[id].cantidad=Math.max(1,parseInt(v)); render(); }
function descBtn(id,d){ cart[id].descuento=Math.max(0,Math.min(100,cart[id].descuento+d)); render(); }
function setDesc(id,v){ cart[id].descuento=Math.max(0,Math.min(100,parseFloat(v))); render(); }
function removeItem(id){ delete cart[id]; render(); }
document.querySelectorAll('.product-card').forEach(c=>{
c.addEventListener('click',()=>addProduct(c));
});
document.getElementById('search').addEventListener('keyup',function(){
const v=this.value.toLowerCase();
document.querySelectorAll('.product-card').forEach(c=>{
c.style.display=c.dataset.name.toLowerCase().includes(v)?'block':'none';
});
});
</script>
@endsection