67a0e674ca
Marine maintenance management: work orders with photos, ISM/SWP procedures, MSDS, inventory, RFQ/purchases, vessel history, bilingual PDF reports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
93 lines
4.1 KiB
HTML
93 lines
4.1 KiB
HTML
{% extends 'base.html' %}
|
||
{% block title %}Compra #{{ purchase.id }}{% endblock %}
|
||
{% block page_title %}Compra — {{ purchase.purchase_date }}{% endblock %}
|
||
{% block topbar_actions %}<a href="{{ url_for('purchases') }}" class="btn btn-secondary">← Volver</a>{% endblock %}
|
||
{% block content %}
|
||
<div class="grid-2 mb-4">
|
||
<div class="card">
|
||
<div class="card-header">📋 Detalles</div>
|
||
<table style="font-size:13px">
|
||
<tr><td style="color:var(--gray);padding:6px 0;width:140px">Proveedor</td><td>{{ purchase.supplier_name or '—' }}</td></tr>
|
||
<tr><td style="color:var(--gray);padding:6px 0">Factura</td><td>{{ purchase.invoice_number or '—' }}</td></tr>
|
||
<tr><td style="color:var(--gray);padding:6px 0">Fecha</td><td>{{ purchase.purchase_date }}</td></tr>
|
||
<tr><td style="color:var(--gray);padding:6px 0">Total</td><td class="text-cyan">${{ "%.2f"|format(purchase.total_amount or 0) }}</td></tr>
|
||
</table>
|
||
{% if purchase.notes %}<p style="font-size:13px;color:var(--gray);margin-top:10px">{{ purchase.notes }}</p>{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="card-header flex justify-between">
|
||
<span>📦 Ítems Comprados</span>
|
||
<button onclick="document.getElementById('itemModal').style.display='flex'" class="btn btn-sm btn-primary">+ Agregar Ítem</button>
|
||
</div>
|
||
<div class="table-wrap">
|
||
<table>
|
||
<thead><tr><th>Repuesto</th><th>Descripción</th><th>Cantidad</th><th>Costo Unit.</th><th>Total</th></tr></thead>
|
||
<tbody>
|
||
{% for i in items %}
|
||
<tr>
|
||
<td>{{ i.part_name or '—' }}</td>
|
||
<td class="text-gray">{{ i.description or '' }}</td>
|
||
<td>{{ i.quantity }}</td>
|
||
<td>${{ "%.2f"|format(i.unit_cost) }}</td>
|
||
<td class="text-cyan">${{ "%.2f"|format(i.total_cost) }}</td>
|
||
</tr>
|
||
{% else %}
|
||
<tr><td colspan="5" class="text-gray" style="text-align:center;padding:20px">Sin ítems.</td></tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="itemModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,0.8);z-index:1000;align-items:center;justify-content:center">
|
||
<div class="card" style="width:460px;max-width:95vw">
|
||
<div class="card-header">📦 Agregar Ítem</div>
|
||
<div class="form-group mb-4">
|
||
<label>Repuesto del Inventario</label>
|
||
<select id="itemPart">
|
||
<option value="">-- Sin inventario (manual) --</option>
|
||
{% for p in parts %}
|
||
<option value="{{ p.id }}">{{ p.name }} {% if p.part_number %}({{ p.part_number }}){% endif %}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</div>
|
||
<div class="form-group mb-4">
|
||
<label>Descripción (si es manual)</label>
|
||
<input type="text" id="itemDesc">
|
||
</div>
|
||
<div class="form-grid mb-4">
|
||
<div class="form-group">
|
||
<label>Cantidad</label>
|
||
<input type="number" id="itemQty" value="1" step="0.01">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Costo Unitario ($)</label>
|
||
<input type="number" id="itemCost" value="0" step="0.01">
|
||
</div>
|
||
</div>
|
||
<div class="flex gap-3">
|
||
<button onclick="addItem()" class="btn btn-primary">➕ Agregar</button>
|
||
<button onclick="document.getElementById('itemModal').style.display='none'" class="btn btn-secondary">Cancelar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
{% block scripts %}
|
||
<script>
|
||
function addItem() {
|
||
const data = {
|
||
part_id: document.getElementById('itemPart').value || null,
|
||
description: document.getElementById('itemDesc').value,
|
||
quantity: document.getElementById('itemQty').value,
|
||
unit_cost: document.getElementById('itemCost').value
|
||
};
|
||
fetch(`/purchases/{{ purchase.id }}/add-item`, {
|
||
method:'POST', headers:{'Content-Type':'application/json'},
|
||
body: JSON.stringify(data)
|
||
}).then(() => location.reload());
|
||
}
|
||
</script>
|
||
{% endblock %}
|