194 lines
5.7 KiB
PHP
194 lines
5.7 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('content')
|
||
|
||
<section class="content pt-3">
|
||
<form method="POST" action="{{ route('cotizaciones.store') }}" id="posForm">
|
||
@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 type="submit" class="btn btn-success btn-block">
|
||
<i class="fa fa-save"></i> Guardar Cotización
|
||
</button>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{{-- DERECHA / PRODUCTOS --}}
|
||
<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">
|
||
<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>
|
||
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 total = qty * price;
|
||
row.querySelector('.line-total').innerText = '$' + total.toFixed(2);
|
||
subtotal += total;
|
||
});
|
||
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 index = itemsTable.children.length;
|
||
|
||
row = document.createElement('tr');
|
||
row.dataset.id = id;
|
||
row.dataset.price = price;
|
||
|
||
row.innerHTML = `
|
||
<td>
|
||
${name}
|
||
<input type="hidden" name="productos[${index}][producto_id]" value="${id}">
|
||
<input type="hidden" name="productos[${index}][precio_unitario]" value="${price}">
|
||
</td>
|
||
<td>
|
||
<input type="number" name="productos[${index}][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
|