haciendo datatables de los pagos

This commit is contained in:
2025-11-04 22:03:03 +01:00
parent dc64e40e38
commit ed32f773a4
23 changed files with 434 additions and 37 deletions

View File

@ -0,0 +1,28 @@
databaseChangeLog:
- changeSet:
id: 0008-update-cart-status-constraint
author: jjo
changes:
# 1) Eliminar el índice único antiguo (user_id, status)
- sql:
sql: |
ALTER TABLE carts
DROP INDEX uq_carts_user_active;
# 2) Añadir columna generada 'active_flag'
# Será 1 si status = 'ACTIVE', y NULL en cualquier otro caso
- sql:
sql: |
ALTER TABLE carts
ADD COLUMN active_flag TINYINT(1)
GENERATED ALWAYS AS (
CASE WHEN status = 'ACTIVE' THEN 1 ELSE NULL END
);
# 3) Crear el nuevo índice único:
# solo limita (user_id, active_flag=1),
# se permiten muchos registros con active_flag NULL (LOCKED, COMPLETED, etc.)
- sql:
sql: |
CREATE UNIQUE INDEX uq_carts_user_active
ON carts (user_id, active_flag);

View File

@ -12,4 +12,6 @@ databaseChangeLog:
- include:
file: db/changelog/changesets/0006-add-cart-direcciones.yml
- include:
file: db/changelog/changesets/0007-payments-core.yml
file: db/changelog/changesets/0007-payments-core.yml
- include:
file: db/changelog/changesets/0008-update-cart-status-constraint.yml

View File

@ -1,4 +1,12 @@
pagos.module-title=Gestión de Pagos
pagos.tab.movimientos-redsys=Movimientos Redsys
pagos.tab.transferencias-bancarias=Transferencias Bancarias
pagos.tab.transferencias-bancarias=Transferencias Bancarias
pagos.table.cliente.nombre=Nombre Cliente
pagos.table.redsys.id=Cod. Redsys
pagos.table.pedido.id=Pedido
pagos.table.cantidad=Cantidad
pagos.table.fecha=Fecha
pagos.table.estado=Estado
pagos.table.acciones=Acciones

View File

@ -12,5 +12,7 @@ checkout.billing-address.errors.noAddressSelected=Debe seleccionar una direcció
checkout.payment.card=Tarjeta de crédito / débito
checkout.payment.bizum=Bizum
checkout.payment.bank-transfer=Transferencia bancaria
checkout.error.payment=Error al procesar el pago: el pago ha sido cancelado o rechazado Por favor, inténtelo de nuevo.
checkout.success.payment=Pago realizado con éxito. Gracias por su compra.
checkout.make-payment=Realizar el pago

View File

@ -57,3 +57,13 @@ body {
color: #92b2a7;
}
.alert-fadeout {
opacity: 1;
transition: opacity 1s ease;
animation: fadeout 4s forwards;
}
@keyframes fadeout {
0%, 70% { opacity: 1; }
100% { opacity: 0; }
}

View File

@ -256,4 +256,13 @@
}
}
// Oculta los alerts cuando se termina la animacion:
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll('.alert-fadeout').forEach(alert => {
alert.addEventListener('animationend', () => {
alert.classList.add('d-none');
});
});
});
})();

View File

@ -1,3 +1,60 @@
$(()=>{
$(() => {
const csrfToken = document.querySelector('meta[name="_csrf"]')?.getAttribute('content');
const csrfHeader = document.querySelector('meta[name="_csrf_header"]')?.getAttribute('content');
if (window.$ && csrfToken && csrfHeader) {
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader(csrfHeader, csrfToken);
}
});
}
const language = document.documentElement.lang || 'es-ES';
// Comprueba dependencias antes de iniciar
if (!window.DataTable) {
console.error('DataTables no está cargado aún');
return;
}
const table = new DataTable('#pagos-redsys-datatable', {
processing: true,
serverSide: true,
orderCellsTop: true,
pageLength: 50,
language: { url: '/assets/libs/datatables/i18n/' + language + '.json' },
responsive: true,
dom: 'lrBtip',
buttons: {
dom: {
button: {
className: 'btn btn-sm btn-outline-primary me-1'
},
buttons: [
{ extend: 'copy' },
{ extend: 'csv' },
{ extend: 'excel' },
{ extend: 'pdf' },
{ extend: 'print' },
{ extend: 'colvis' }
],
}
},
ajax: {
url: '/pagos/datatable/redsys',
method: 'GET',
},
order: [[4, 'asc']], // Ordena por fecha por defecto
columns: [
{ data: 'client', name: 'user.fullName', orderable: true },
{ data: 'gateway_order_id', name: 'payments.gateway_order_id', orderable: true },
{ data: 'orderId', name: 'order.id', orderable: true },
{ data: 'amount_cents', name: 'amount_cents', orderable: true },
{ data: 'created_at', name: 'created_at', orderable: true },
{ data: 'actions', name: 'actions' }
],
columnDefs: [{ targets: -1, orderable: false, searchable: false }]
});
})

View File

@ -7,9 +7,11 @@
</div>
</div>
<div id="errorEnvio" th:class="${'alert alert-danger' + (errorEnvio ? '' : ' d-none')}" role="alert"
<div th:if="${errorPago}" class="alert alert-danger alert-fadeout my-1" role="alert" th:text="${errorPago}"></div>
<div id="errorEnvio" th:class="${'alert alert-danger my-1' + (errorEnvio ? '' : ' d-none')}" role="alert"
th:text="#{cart.errors.shipping}"></div>
<div th:if="${!#strings.isEmpty(errorMessage) and items != null and !items.isEmpty()}" class="alert alert-danger "
<div th:if="${!#strings.isEmpty(errorMessage) and items != null and !items.isEmpty()}" class="alert alert-danger my-1 "
role="alert" th:text="${errorMessage}"></div>
<div class="alert alert-danger alert-shipment d-none" role="alert"

View File

@ -35,7 +35,9 @@
</ol>
</nav>
</div>
<div th:if="${successPago}" class="alert alert-success alert-fadeout my-1" role="alert" th:text="${successPago}"></div>
<div th:if="${items.isEmpty()}">
<div id="alert-empty"class="alert alert-info" role="alert" th:text="#{cart.empty}"></div>
</div>

View File

@ -41,6 +41,7 @@
<form th:action="@{/pagos/redsys/crear}" method="post">
<input type="hidden" name="amountCents" th:value="${summary.amountCents}" />
<input type="hidden" name="method" value="card"/>
<input type="hidden" name="cartId" th:value="${summary.cartId}" />
<button id="btn-checkout" type="submit" class="btn btn-secondary w-100 mt-2"
th:text="#{checkout.make-payment}" disabled>Checkout</button>
</form>

View File

@ -62,11 +62,10 @@
<!-- Tab panes -->
<div class="tab-content text-muted">
<div class="tab-pane active show" id="arrow-redsys" role="tabpanel">
<!---
<div
th:insert="~{imprimelibros/presupuestos/presupuesto-list-items/tabla-cliente :: tabla-cliente}">
</div>
--->
<div th:insert="~{imprimelibros/pagos/tabla-redsys :: tabla-redsys}">
</div>
</div>
<div class="tab-pane" id="arrow-transferencias" role="tabpanel">
<!---
@ -89,6 +88,19 @@
window.languageBundle = /*[[${languageBundle}]]*/ {};
</script>
<script th:src="@{/assets/libs/datatables/datatables.min.js}"></script>
<script th:src="@{/assets/libs/datatables/dataTables.bootstrap5.min.js}"></script>
<!-- JS de Buttons y dependencias -->
<script th:src="@{/assets/libs/datatables/dataTables.buttons.min.js}"></script>
<script th:src="@{/assets/libs/jszip/jszip.min.js}"></script>
<script th:src="@{/assets/libs/pdfmake/pdfmake.min.js}"></script>
<script th:src="@{/assets/libs/pdfmake/vfs_fonts.min.js}"></script>
<script th:src="@{/assets/libs/datatables/buttons.html5.min.js}"></script>
<script th:src="@{/assets/libs/datatables/buttons.print.min.js}"></script>
<script th:src="@{/assets/libs/datatables/buttons.colVis.min.js}"></script>
<script type="module" th:src="@{/assets/js/pages/imprimelibros/pagos/pagos.js}"></script>
</th:block>
</body>

View File

@ -0,0 +1,24 @@
<div th:fragment="tabla-redsys">
<table id="pagos-redsys-datatable" class="table table-striped table-nowrap responsive w-100">
<thead>
<tr>
<th scope="col" th:text="#{pagos.table.cliente.nombre}">ID</th>
<th scope="col" th:text="#{pagos.table.redsys.id}">Cliente</th>
<th scope="col" th:text="#{pagos.table.pedido.id}">Pedido</th>
<th scope="col" th:text="#{pagos.table.cantidad}">Cantidad</th>
<th scope="col" th:text="#{pagos.table.fecha}">Fecha</th>
<th scope="col" th:text="#{pagos.table.acciones}">Acciones</th>
</tr>
<tr>
<th><input type="text" class="form-control form-control-sm presupuesto-filter" data-col="user.fullName" /></th>
<th><input type="text" class="form-control form-control-sm presupuesto-filter" data-col="user.fullName" /></th>
<th><input type="text" class="form-control form-control-sm presupuesto-filter" data-col="payments.gateway_order_id" /></th>
<th></th>
<th></th>
<th></th> <!-- Acciones (sin filtro) -->
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>