feat: marcar pago manual en contratos con enlace Bold pendiente

Agrega endpoint POST /api/contratos/:id/marcar-pagado y botón (✓)
en la tabla de contratos para confirmar el pago sin depender del
webhook de Bold. Llama a MarcarContratoPagado (pago_confirmado=true,
limpia enlace, renueva fecha vencimiento) y envía correo de confirmación.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-09 20:11:50 -05:00
co-authored by Claude Sonnet 4.6
parent 9305cd6eb2
commit 0218b93bb4
3 changed files with 34 additions and 0 deletions
@@ -116,6 +116,10 @@
<button x-show="d.enlace_pago_link_id && !d.pago_confirmado" @click="verificarPago(d)" :disabled="verificandoID===d.ID" title="Verificar pago en Bold" class="text-gray-400 hover:text-teal-500 disabled:opacity-40">
<svg class="w-4 h-4" :class="verificandoID===d.ID ? 'animate-spin' : ''" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"/></svg>
</button>
<!-- Marcar pagado manualmente (solo si tiene pago pendiente) -->
<button x-show="d.enlace_pago && !d.pago_confirmado" @click="marcarPagado(d)" title="Marcar como pagado manualmente" class="text-gray-400 hover:text-green-600">
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg>
</button>
<button @click="openHistorial(d)" title="Ver historial" class="text-gray-400 hover:text-indigo-500">
<svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6h4.5m4.5 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg>
</button>
@@ -572,6 +576,17 @@ document.addEventListener('alpine:init', () => {
} catch(e) { this.showToast(e.response?.data?.error||'Error', 'error'); }
},
async marcarPagado(d) {
if (!confirm(`¿Marcar el contrato de ${d.cliente?.nombre || '#'+d.ID} como pagado manualmente?\nEsto limpiará el enlace de Bold y renovará la fecha de vencimiento.`)) return;
try {
const { data } = await axios.post(`/app/api/contratos/${d.ID}/marcar-pagado`);
this.showToast(data.mensaje || 'Pago confirmado');
await this.loadData();
} catch(e) {
this.showToast(e.response?.data?.error || 'Error al marcar pago', 'error');
}
},
async verificarPago(d) {
this.verificandoID = d.ID;
try {