208 lines
6.3 KiB
PHP
208 lines
6.3 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('content')
|
||
<section class="content pt-3">
|
||
<form method="POST" action="{{ route('cotizaciones.store') }}">
|
||
@csrf
|
||
|
||
<div class="row">
|
||
|
||
{{-- ================= IZQUIERDA ================= --}}
|
||
<div class="col-md-4">
|
||
|
||
<div class="card">
|
||
<div class="card-header bg-dark text-white">
|
||
Productos Seleccionados
|
||
</div>
|
||
|
||
<div class="card-body p-0">
|
||
<table class="table table-sm mb-0">
|
||
<thead class="thead-light">
|
||
<tr>
|
||
<th>Producto</th>
|
||
<th width="120">Cant</th>
|
||
<th width="110">Precio</th>
|
||
<th width="90">Desc %</th>
|
||
<th width="110">Total</th>
|
||
<th width="40"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="cart-body"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card mt-2">
|
||
<div class="card-body">
|
||
<div class="d-flex justify-content-between">
|
||
<span>Subtotal</span>
|
||
<strong id="subtotal">$0.00</strong>
|
||
</div>
|
||
<div class="d-flex justify-content-between">
|
||
<span>IVA (16%)</span>
|
||
<strong id="iva">$0.00</strong>
|
||
</div>
|
||
<hr>
|
||
<div class="d-flex justify-content-between">
|
||
<h5>Total</h5>
|
||
<h5 class="text-success" id="total">$0.00</h5>
|
||
</div>
|
||
|
||
<div class="form-group mt-3">
|
||
<label>Cliente *</label>
|
||
<select name="cliente_id" class="form-control" 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-block">
|
||
<i class="fa fa-save"></i> Guardar Cotización
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- ================= DERECHA ================= --}}
|
||
<div class="col-md-8">
|
||
|
||
<div class="card mb-2">
|
||
<div class="card-body">
|
||
<input type="text" id="search" class="form-control" placeholder="Buscar producto...">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="row" id="products-grid">
|
||
@foreach($productos as $producto)
|
||
<div class="col-md-3 mb-3 product-card"
|
||
data-id="{{ $producto->id }}"
|
||
data-name="{{ $producto->nombre }}"
|
||
data-price="{{ $producto->precio }}">
|
||
|
||
<div class="card h-100 text-center" style="cursor:pointer">
|
||
<div class="card-body">
|
||
@if($producto->foto)
|
||
<img src="{{ asset('storage/'.$producto->foto) }}"
|
||
width="60" style="border-radius:6px;">
|
||
@else
|
||
—
|
||
@endif
|
||
<h6>{{ $producto->nombre }}</h6>
|
||
<strong class="text-success">
|
||
${{ number_format($producto->precio,2) }}
|
||
</strong>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endforeach
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</form>
|
||
</section>
|
||
@endsection
|
||
|
||
@section('scripts')
|
||
<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 index = 0;
|
||
|
||
Object.values(cart).forEach(item=>{
|
||
const bruto = item.cantidad * item.precio;
|
||
const desc = bruto * (item.descuento/100);
|
||
const total = bruto - desc;
|
||
subtotal += total;
|
||
|
||
const tr = document.createElement('tr');
|
||
tr.innerHTML = `
|
||
<td>
|
||
${item.nombre}
|
||
<input type="hidden" name="productos[${index}][producto_id]" value="${item.id}">
|
||
<input type="hidden" name="productos[${index}][precio_unitario]" value="${item.precio}">
|
||
</td>
|
||
<td>
|
||
<div class="d-flex">
|
||
<button type="button" class="btn btn-secondary btn-sm" onclick="qty(${item.id},-1)">−</button>
|
||
<input type="number" name="productos[${index}][cantidad]"
|
||
class="form-control form-control-sm mx-1 text-center"
|
||
value="${item.cantidad}" min="1"
|
||
onchange="setQty(${item.id},this.value)">
|
||
<button type="button" class="btn btn-secondary btn-sm" onclick="qty(${item.id},1)">+</button>
|
||
</div>
|
||
</td>
|
||
<td class="text-right">${money(item.precio)}</td>
|
||
<td>
|
||
<input type="number" class="form-control form-control-sm"
|
||
value="${item.descuento}" min="0" max="100"
|
||
onchange="setDesc(${item.id},this.value)">
|
||
</td>
|
||
<td class="text-right">${money(total)}</td>
|
||
<td>
|
||
<button type="button" class="btn btn-danger btn-sm" onclick="removeItem(${item.id})">×</button>
|
||
</td>
|
||
`;
|
||
tbody.appendChild(tr);
|
||
index++;
|
||
});
|
||
|
||
document.getElementById('subtotal').innerText = money(subtotal);
|
||
document.getElementById('iva').innerText = money(subtotal * IVA);
|
||
document.getElementById('total').innerText = money(subtotal * (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,delta){
|
||
cart[id].cantidad = Math.max(1, cart[id].cantidad + delta);
|
||
render();
|
||
}
|
||
function setQty(id,val){ cart[id].cantidad = Math.max(1,parseInt(val)); render(); }
|
||
function setDesc(id,val){ cart[id].descuento = Math.max(0,Math.min(100,parseFloat(val))); 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) ? '' : 'none';
|
||
});
|
||
});
|
||
</script>
|
||
@endsection
|