208 lines
6.2 KiB
PHP
208 lines
6.2 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('content')
|
||
<section class="content pt-3">
|
||
<form method="POST" action="{{ route('cotizaciones.store') }}">
|
||
@csrf
|
||
|
||
<div class="row">
|
||
|
||
{{-- IZQUIERDA / CARRITO --}}
|
||
<div class="col-md-4">
|
||
|
||
<div class="card">
|
||
<div class="card-header bg-dark text-white">
|
||
<h5 class="mb-0">Productos Seleccionados</h5>
|
||
</div>
|
||
|
||
<div class="card-body p-0">
|
||
<table class="table table-sm mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th>Producto</th>
|
||
<th width="70">Cant</th>
|
||
<th>Total</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="items-table"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<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 mt-2">
|
||
<i class="fa fa-save"></i> Guardar Cotización
|
||
</button>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- DERECHA / PRODUCTOS --}}
|
||
<div class="col-md-8">
|
||
|
||
<div class="card mb-3">
|
||
<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">
|
||
<img src="{{ $producto->imagen ?? 'https://via.placeholder.com/100' }}"
|
||
class="img-fluid mb-2"
|
||
style="max-height:80px">
|
||
|
||
<h6 class="mb-1">{{ $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>
|
||
let index = 0;
|
||
|
||
const itemsTable = document.getElementById('items-table');
|
||
const subtotalEl = document.getElementById('subtotal');
|
||
const ivaEl = document.getElementById('iva');
|
||
const totalEl = document.getElementById('total');
|
||
|
||
function recalcTotals(){
|
||
let subtotal = 0;
|
||
|
||
itemsTable.querySelectorAll('tr').forEach(row => {
|
||
const qty = parseInt(row.querySelector('.qty').value);
|
||
const price = parseFloat(row.dataset.price);
|
||
const line = qty * price;
|
||
|
||
row.querySelector('.line-total').innerText = '$' + line.toFixed(2);
|
||
subtotal += line;
|
||
});
|
||
|
||
const iva = subtotal * 0.16;
|
||
|
||
subtotalEl.innerText = '$' + subtotal.toFixed(2);
|
||
ivaEl.innerText = '$' + iva.toFixed(2);
|
||
totalEl.innerText = '$' + (subtotal + iva).toFixed(2);
|
||
}
|
||
|
||
function addProduct(card){
|
||
const id = card.dataset.id;
|
||
const name = card.dataset.name;
|
||
const price = parseFloat(card.dataset.price);
|
||
|
||
let row = itemsTable.querySelector(`tr[data-id="${id}"]`);
|
||
|
||
if(row){
|
||
const qty = row.querySelector('.qty');
|
||
qty.value = parseInt(qty.value) + 1;
|
||
recalcTotals();
|
||
return;
|
||
}
|
||
|
||
const currentIndex = index++;
|
||
|
||
row = document.createElement('tr');
|
||
row.dataset.id = id;
|
||
row.dataset.price = price;
|
||
|
||
row.innerHTML = `
|
||
<td>
|
||
${name}
|
||
<input type="hidden" name="productos[${currentIndex}][producto_id]" value="${id}">
|
||
<input type="hidden" name="productos[${currentIndex}][precio_unitario]" value="${price}">
|
||
</td>
|
||
<td>
|
||
<input type="number"
|
||
name="productos[${currentIndex}][cantidad]"
|
||
class="form-control form-control-sm qty"
|
||
value="1" min="1">
|
||
</td>
|
||
<td class="line-total">$${price.toFixed(2)}</td>
|
||
<td>
|
||
<button type="button" class="btn btn-danger btn-sm remove">×</button>
|
||
</td>
|
||
`;
|
||
|
||
itemsTable.appendChild(row);
|
||
recalcTotals();
|
||
}
|
||
|
||
document.querySelectorAll('.product-card').forEach(card=>{
|
||
card.addEventListener('click', () => addProduct(card));
|
||
});
|
||
|
||
itemsTable.addEventListener('click', e=>{
|
||
if(e.target.classList.contains('remove')){
|
||
e.target.closest('tr').remove();
|
||
recalcTotals();
|
||
}
|
||
});
|
||
|
||
itemsTable.addEventListener('change', e=>{
|
||
if(e.target.classList.contains('qty')){
|
||
recalcTotals();
|
||
}
|
||
});
|
||
|
||
document.getElementById('search').addEventListener('keyup', function(){
|
||
const val = this.value.toLowerCase();
|
||
document.querySelectorAll('.product-card').forEach(card=>{
|
||
card.style.display = card.dataset.name.toLowerCase().includes(val) ? '' : 'none';
|
||
});
|
||
});
|
||
</script>
|
||
@endsection
|