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

301 lines
9.1 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 pt-3 pb-4">
<div class="container-fluid">
<form method="POST" action="{{ route('cotizaciones.store') }}">
@csrf
<div class="row mb-3 align-items-stretch">
{{-- BUSCADOR + PRODUCTOS --}}
<div class="col-lg-8 d-flex flex-column">
<div class="card shadow-sm mb-3 flex-fill">
<div class="card-body py-3 d-flex flex-column">
<input type="text"
id="search"
class="form-control mb-3"
placeholder="Buscar producto...">
{{-- PRODUCTOS CON SCROLL POS --}}
<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="card h-100 text-center shadow-sm border product-inner">
<div class="card-body py-3">
@if($producto->foto)
<img src="{{ asset('storage/'.$producto->foto) }}"
width="60"
class="mb-2"
style="border-radius:6px;">
@endif
<div class="fw-semibold">
{{ $producto->nombre }}
</div>
<div class="text-success fw-bold">
${{ number_format($producto->precio,2) }}
</div>
</div>
</div>
</div>
@endforeach
</div>
</div>
</div>
</div>
{{-- TOTALES --}}
<div class="col-lg-4 d-flex">
<div class="card shadow-sm flex-fill">
<div class="card-body d-flex flex-column justify-content-between" style="font-size:14px;">
<div>
<div class="d-flex justify-content-between mb-1">
<span>Subtotal</span>
<span id="subtotal">$0.00</span>
</div>
<div class="d-flex justify-content-between mb-1">
<span>Total Descuento</span>
<span id="total-desc">$0.00</span>
</div>
<div class="d-flex justify-content-between mb-2">
<span>IVA (16%)</span>
<span id="iva">$0.00</span>
</div>
<hr class="my-2">
<div class="d-flex justify-content-between mb-3">
<strong>Total</strong>
<strong class="text-success" id="total">$0.00</strong>
</div>
</div>
<div>
<div class="mb-2">
<select name="cliente_id" class="form-control form-control-sm" 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 shadow-sm">
<div class="card-header bg-dark text-white py-2">
Productos Seleccionados
</div>
<div class="card-body p-0">
<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="130">Precio</th>
<th width="170">Desc %</th>
<th width="130">Total</th>
<th width="60"></th>
</tr>
</thead>
<tbody id="cart-body"></tbody>
</table>
</div>
</div>
</div>
</form>
</div>
</section>
@endsection
@section('scripts')
<style>
.products-scroll{
display:flex;
gap:15px;
overflow-x:auto;
scroll-snap-type:x mandatory;
padding-bottom:5px;
}
.products-scroll::-webkit-scrollbar{
height:6px;
}
.products-scroll::-webkit-scrollbar-thumb{
background:#d1d1d1;
border-radius:10px;
}
.product-card{
min-width:180px;
scroll-snap-align:start;
cursor:pointer;
}
.product-inner{
transition:.2s ease;
}
.product-inner:hover{
transform:scale(1.04);
}
</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="${item.id}">
<input type="hidden" name="productos[${index}][precio_unitario]" value="${item.precio}">
</td>
<td>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-outline-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-outline-secondary btn-sm"
onclick="qty(${item.id},1)">+</button>
</div>
</td>
<td>${money(item.precio)}</td>
<td>
<div class="d-flex align-items-center">
<button type="button" class="btn btn-outline-secondary btn-sm"
onclick="descBtn(${item.id},-1)"></button>
<input type="number"
class="form-control form-control-sm mx-1 text-center"
value="${item.descuento}" min="0" max="100"
onchange="setDesc(${item.id},this.value)">
<button type="button" class="btn btn-outline-secondary btn-sm"
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