mirror of
https://git.imnavajas.es/jjimenez/erp-imprimelibros.git
synced 2026-01-21 16:20:22 +00:00
modificando carrito
This commit is contained in:
@ -11,8 +11,8 @@ logging.level.org.springframework=ERROR
|
||||
#
|
||||
# Database Configuration
|
||||
#
|
||||
spring.datasource.url=jdbc:mysql://localhost:3309/imprimelibros
|
||||
#spring.datasource.url=jdbc:mysql://127.0.0.1:3309/imprimelibros?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Europe/Madrid&characterEncoding=utf8
|
||||
#spring.datasource.url=jdbc:mysql://localhost:3309/imprimelibros
|
||||
spring.datasource.url=jdbc:mysql://127.0.0.1:3309/imprimelibros?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Europe/Madrid&characterEncoding=utf8
|
||||
spring.datasource.username=imprimelibros_user
|
||||
spring.datasource.password=om91irrDctd
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
@ -24,8 +24,8 @@ spring.jpa.show-sql=false
|
||||
#
|
||||
# Safekat API Configuration
|
||||
#
|
||||
safekat.api.url=http://localhost:8000/
|
||||
#safekat.api.url=https://erp-dev.safekat.es/
|
||||
#safekat.api.url=http://localhost:8000/
|
||||
safekat.api.url=https://erp-dev.safekat.es/
|
||||
safekat.api.email=imnavajas@coit.es
|
||||
safekat.api.password=Safekat2024
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ app.yes=Sí
|
||||
app.no=No
|
||||
app.aceptar=Aceptar
|
||||
app.cancelar=Cancelar
|
||||
app.seleccionar=Seleccionar
|
||||
app.guardar=Guardar
|
||||
app.editar=Editar
|
||||
app.add=Añadir
|
||||
|
||||
@ -53,5 +53,7 @@ direcciones.error.delete-internal-error=Error interno al eliminar la dirección.
|
||||
direcciones.error.noEncontrado=Dirección no encontrada.
|
||||
direcciones.error.sinPermiso=No tiene permiso para realizar esta acción.
|
||||
|
||||
direcciones.error.noShippingCost=No se pudo calcular el coste de envío para la dirección proporcionada.
|
||||
|
||||
direcciones.form.error.required=Campo obligatorio.
|
||||
|
||||
|
||||
0
src/main/resources/i18n/pedidos_en.properties
Normal file
0
src/main/resources/i18n/pedidos_en.properties
Normal file
17
src/main/resources/i18n/pedidos_es.properties
Normal file
17
src/main/resources/i18n/pedidos_es.properties
Normal file
@ -0,0 +1,17 @@
|
||||
checkout.title=Finalizar compra
|
||||
checkout.summay=Resumen de la compra
|
||||
checkout.shipping=Envío
|
||||
checkout.payment=Método de pago
|
||||
|
||||
checkout.shipping.info=Todos los pedidos incluyen un envío gratuito a la Península y Baleares por línea de pedido.
|
||||
checkout.shipping.order=Envío del pedido
|
||||
checkout.shipping.samples=Envío de pruebas
|
||||
checkout.shipping.onlyOneShipping=Todo el pedido se envía a una única dirección.
|
||||
checkout.shipping.add=Añadir dirección
|
||||
checkout.shipping.add.title=Seleccione una dirección
|
||||
checkout.shipping.select-placeholder=Buscar en direcciones...
|
||||
checkout.shipping.new-address=Nueva dirección
|
||||
|
||||
checkout.summary.presupuesto=#Presupuesto
|
||||
checkout.summary.titulo=Título
|
||||
checkout.summary.base=Base
|
||||
@ -0,0 +1,193 @@
|
||||
$(() => {
|
||||
|
||||
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';
|
||||
const modalEl = document.getElementById('direccionFormModal');
|
||||
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
|
||||
|
||||
|
||||
$("#onlyOneShipping").on('change', function () {
|
||||
if ($(this).is(':checked')) {
|
||||
$('#shippingAddressesContainer').empty().show();
|
||||
$('#shippingMultipleAddressesContainer').show();
|
||||
} else {
|
||||
$('#shippingAddressesContainer').hide();
|
||||
$('#shippingMultipleAddressesContainer').empty().hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#addOrderAddress').on('click', () => {
|
||||
if ($('#onlyOneShipping').is(':checked')) {
|
||||
seleccionarDireccionEnvio();
|
||||
} else {
|
||||
// Add address to multiple shipping addresses container
|
||||
}
|
||||
});
|
||||
|
||||
async function seleccionarDireccionEnvio() {
|
||||
|
||||
const { value: direccionId, isDenied } = await Swal.fire({
|
||||
title: window.languageBundle['checkout.shipping.add.title'] || 'Seleccione una dirección',
|
||||
html: `
|
||||
<select id="direccionSelect" class="form-select" style="width: 100%"></select>
|
||||
`,
|
||||
showCancelButton: true,
|
||||
showDenyButton: true,
|
||||
buttonsStyling: false,
|
||||
confirmButtonText: window.languageBundle['app.seleccionar'] || 'Seleccionar',
|
||||
cancelButtonText: window.languageBundle['app.cancelar'] || 'Cancelar',
|
||||
denyButtonText: window.languageBundle['checkout.shipping.new-address'] || 'Nueva dirección',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-secondary me-2',
|
||||
cancelButton: 'btn btn-light',
|
||||
denyButton: 'btn btn-secondary me-2'
|
||||
},
|
||||
focusConfirm: false,
|
||||
|
||||
// Inicializa cuando el DOM del modal ya existe
|
||||
didOpen: () => {
|
||||
const $select = $('#direccionSelect');
|
||||
$select.empty(); // limpia placeholder estático
|
||||
|
||||
$select.select2({
|
||||
width: '100%',
|
||||
dropdownParent: $('.swal2-container'),
|
||||
ajax: {
|
||||
url: '/direcciones/select2',
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
data: params => ({ q: params.term || '' }),
|
||||
processResults: (data) => {
|
||||
const items = Array.isArray(data) ? data : (data.results || []);
|
||||
return {
|
||||
results: items.map(item => ({
|
||||
id: item.id,
|
||||
text: item.text, // ← Select2 necesita 'id' y 'text'
|
||||
alias: item.alias || 'Sin alias',
|
||||
att: item.att || '',
|
||||
direccion: item.direccion || '',
|
||||
cp: item.cp || '',
|
||||
ciudad: item.ciudad || '',
|
||||
html: `
|
||||
<div>
|
||||
<strong>${item.alias || 'Sin alias'}</strong><br>
|
||||
${item.att ? `<small>${item.att}</small><br>` : ''}
|
||||
<small>${item.direccion || ''}${item.cp ? ', ' + item.cp : ''}${item.ciudad ? ', ' + item.ciudad : ''}</small>
|
||||
</div>
|
||||
`
|
||||
})),
|
||||
pagination: { more: false } // opcional, evita que espere más páginas
|
||||
};
|
||||
}
|
||||
|
||||
},
|
||||
placeholder: window.languageBundle['checkout.shipping.select-placeholder'] || 'Buscar en direcciones...',
|
||||
language: language,
|
||||
|
||||
templateResult: data => {
|
||||
if (data.loading) return data.text;
|
||||
return $(data.html || data.text);
|
||||
},
|
||||
// Selección más compacta (solo alias + ciudad)
|
||||
templateSelection: data => {
|
||||
if (!data.id) return data.text;
|
||||
const alias = data.alias || data.text;
|
||||
const ciudad = data.ciudad ? ` — ${data.ciudad}` : '';
|
||||
return $(`<span>${alias}${ciudad}</span>`);
|
||||
},
|
||||
escapeMarkup: m => m
|
||||
});
|
||||
|
||||
// (Opcional) Prefijar valor si ya tienes una dirección elegida:
|
||||
// const preselected = { id: '123', text: 'Oficina Central — Madrid' };
|
||||
// const option = new Option(preselected.text, preselected.id, true, true);
|
||||
// $select.append(option).trigger('change');
|
||||
},
|
||||
|
||||
preConfirm: () => {
|
||||
const $select = $('#direccionSelect');
|
||||
const val = $select.val();
|
||||
if (!val) {
|
||||
Swal.showValidationMessage(
|
||||
lang.startsWith('es') ? 'Debes seleccionar una dirección' : 'You must select an address'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
didClose: () => {
|
||||
// Limpieza: destruir select2 para evitar fugas
|
||||
const $select = $('#direccionSelect');
|
||||
if ($select.data('select2')) {
|
||||
$select.select2('destroy');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isDenied) {
|
||||
$.get('/direcciones/direction-form', function (html) {
|
||||
$('#direccionFormModalBody').html(html);
|
||||
const title = $('#direccionFormModalBody #direccionForm').data('add');
|
||||
$('#direccionFormModal .modal-title').text(title);
|
||||
modal.show();
|
||||
});
|
||||
}
|
||||
|
||||
if (direccionId) {
|
||||
// Obtén el objeto completo seleccionado
|
||||
const response = await fetch(`/checkout/get-address/${direccionId}`);
|
||||
if (response.ok) {
|
||||
const html = await response.text();
|
||||
$('#shippingAddressesContainer').html(html);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(document).on('submit', '#direccionForm', function (e) {
|
||||
e.preventDefault();
|
||||
const $form = $(this);
|
||||
|
||||
$.ajax({
|
||||
url: $form.attr('action'),
|
||||
type: 'POST', // PUT simulado via _method
|
||||
data: $form.serialize(),
|
||||
dataType: 'html',
|
||||
success: function (html) {
|
||||
// Si por cualquier motivo llega 200 con fragmento, lo insertamos igual
|
||||
if (typeof html === 'string' && html.indexOf('id="direccionForm"') !== -1 && html.indexOf('<html') === -1) {
|
||||
$('#direccionFormModalBody').html(html);
|
||||
const isEdit = $('#direccionFormModalBody #direccionForm input[name="_method"][value="PUT"]').length > 0;
|
||||
const title = $('#direccionFormModalBody #direccionForm').data(isEdit ? 'edit' : 'add');
|
||||
$('#direccionModal .modal-title').text(title);
|
||||
return;
|
||||
}
|
||||
// Éxito real: cerrar y recargar tabla
|
||||
modal.hide();
|
||||
seleccionarDireccionEnvio();
|
||||
},
|
||||
error: function (xhr) {
|
||||
// Con 422 devolvemos el fragmento con errores aquí
|
||||
if (xhr.status === 422 && xhr.responseText) {
|
||||
$('#direccionFormModalBody').html(xhr.responseText);
|
||||
const isEdit = $('#direccionFormModalBody #direccionForm input[name="_method"][value="PUT"]').length > 0;
|
||||
const title = $('#direccionFormModalBody #direccionForm').data(isEdit ? 'edit' : 'add');
|
||||
$('#direccionModal .modal-title').text(title);
|
||||
initSelect2Cliente(true);
|
||||
return;
|
||||
}
|
||||
// Fallback
|
||||
$('#direccionFormModalBody').html('<div class="p-3 text-danger">Error inesperado.</div>');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -36,7 +36,28 @@
|
||||
<div th:if="${items.isEmpty()}">
|
||||
<div class="alert alert-info" role="alert" th:text="#{cart.empty}"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-xl-8 col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p th:text="#{checkout.shipping.info}"></p>
|
||||
<div
|
||||
class="form-check form-switch form-switch-custom form-switch-presupuesto mb-3 d-flex align-items-center">
|
||||
<input type="checkbox" class="form-check-input datos-generales-data me-2"
|
||||
id="onlyOneShipping" name="onlyOneShipping" checked />
|
||||
<label for="onlyOneShipping" class="form-label d-flex align-items-center mb-0">
|
||||
<span th:text="#{checkout.shipping.onlyOneShipping}" class="me-2"></span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" id="addOrderAddress"
|
||||
th:text="#{checkout.shipping.add}">Añadir dirección</button>
|
||||
|
||||
<div id="orderShippingAddressesContainer" class="mt-4"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:each="item : ${items}" th:insert="~{imprimelibros/cart/_cartItem :: cartItem(${item})}">
|
||||
</div>
|
||||
</div>
|
||||
@ -67,13 +88,14 @@
|
||||
<th><span th:text="#{cart.resumen.total}"></span>:</th>
|
||||
<td class="text-end">
|
||||
<span id="total-cesta" class="fw-semibold">
|
||||
|
||||
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="button" class="btn btn-secondary w-100 mt-2"
|
||||
th:onclick="location.href='/checkout'"
|
||||
th:text="#{cart.resumen.tramitar}">Checkout</button>
|
||||
</div>
|
||||
<!-- end table-responsive -->
|
||||
@ -83,7 +105,8 @@
|
||||
<div class="alert border-dashed alert-danger" role="alert">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="ms-2">
|
||||
<h5 class="fs-14 text-danger fw-semibold" th:text="#{cart.resumen.fidelizacion}"></h5>
|
||||
<h5 class="fs-14 text-danger fw-semibold"
|
||||
th:text="#{cart.resumen.fidelizacion}"></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
<div>
|
||||
<div
|
||||
th:replace="imprimelibros/partials/modal-form :: modal('direccionFormModal', 'direcciones.add', 'modal-md', 'direccionFormModalBody')">
|
||||
</div>
|
||||
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow">
|
||||
<div class="card-body">
|
||||
<div class="ribbon ribbon-primary ribbon-shape" th:text="#{checkout.shipping.order}">Envio del pedido
|
||||
</div>
|
||||
</div>
|
||||
<div class="ribbon-content mt-4">
|
||||
<div class="px-2 mb-2">
|
||||
<p th:text="#{checkout.shipping.info}"></p>
|
||||
<div
|
||||
class="form-check form-switch form-switch-custom form-switch-presupuesto mb-3 d-flex align-items-center">
|
||||
<input type="checkbox" class="form-check-input datos-generales-data me-2" id="onlyOneShipping"
|
||||
name="onlyOneShipping" checked />
|
||||
<label for="onlyOneShipping" class="form-label d-flex align-items-center mb-0">
|
||||
<span th:text="#{checkout.shipping.onlyOneShipping}" class="me-2"></span>
|
||||
</label>
|
||||
</div>
|
||||
<button type="button" class="btn btn-secondary" id="addOrderAddress"
|
||||
th:text="#{checkout.shipping.add}">Añadir dirección</button>
|
||||
|
||||
<div id="orderShippingAddressesContainer" class="mt-4"></div>
|
||||
<div id="orderShippingMultipleAddressesContainer d-none" class="mt-4"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card ribbon-box border shadow-none mb-lg-0 material-shadow mt-4" th:if="${hasSample}">
|
||||
<div class="card-body">
|
||||
<div class="ribbon ribbon-primary ribbon-shape" th:text="#{checkout.shipping.samples}">Envio de pruebas
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ribbon-content mt-4">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Ribbon Shape -->
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
|
||||
</div>
|
||||
@ -0,0 +1,175 @@
|
||||
<!doctype html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="~{imprimelibros/layout}">
|
||||
|
||||
<head>
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/libs/datatables/dataTables.bootstrap5.min.css}" rel="stylesheet" />
|
||||
</th:block>
|
||||
<th:block layout:fragment="pagecss">
|
||||
<link th:href="@{/assets/css/presupuestador.css}" rel="stylesheet" />
|
||||
</th:block>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div th:replace="~{imprimelibros/partials/topbar :: topbar}" />
|
||||
<div th:replace="~{imprimelibros/partials/sidebar :: sidebar}"
|
||||
sec:authorize="isAuthenticated() and hasAnyRole('SUPERADMIN','ADMIN')">
|
||||
|
||||
<th:block layout:fragment="content">
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
|
||||
<div class="container-fluid">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/"><i class="ri-home-5-fill"></i></a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" th:text="#{checkout.title}">Finalizar
|
||||
compra</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-8 col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="step-arrow-nav mt-n3 mx-n3 mb-3">
|
||||
|
||||
<ul class="nav nav-pills nav-justified custom-nav" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link fs-15 p-3 active" id="pills-shipping-tab"
|
||||
data-bs-target="#pills-shipping" type="button" role="tab"
|
||||
aria-controls="pills-shipping" aria-selected="true">
|
||||
<i
|
||||
class="ri-truck-line fs-5 p-1 bg-soft-primary text-primary rounded-circle align-middle me-2"></i>
|
||||
<label class="fs-13 my-2" th:text="#{checkout.shipping}">Envío</label>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link fs-15 p-3" id="pills-payment-tab"
|
||||
data-bs-target="#pills-payment" type="button" role="tab"
|
||||
aria-controls="pills-payment" aria-selected="false">
|
||||
<i
|
||||
class="ri-money-euro-box-line fs-5 p-1 bg-soft-primary text-primary rounded-circle align-middle me-2"></i>
|
||||
<label class="fs-13 my-2" th:text="#{checkout.payment}">Método de
|
||||
pago</label>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade show active" id="pills-shipping" role="tabpanel"
|
||||
aria-labelledby="pills-shipping-tab">
|
||||
|
||||
<div th:include="~{imprimelibros/checkout/_envio.html}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
|
||||
<div class="tab-pane fade" id="pills-payment" role="tabpanel"
|
||||
aria-labelledby="pills-payment-tab">
|
||||
|
||||
<div th:include="~{imprimelibros/checkout/_pago.html}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- end tab pane -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-4">
|
||||
<div class="sticky-side-div">
|
||||
<div class="card">
|
||||
<div class="card-header border-bottom-dashed">
|
||||
<h5 th:text="#{checkout.summay}" class="card-title mb-1"></h5>
|
||||
</div>
|
||||
<div class="card-body pt-2">
|
||||
<div class="table-responsive table-card">
|
||||
<table class="table table-borderless align-middle mb-0">
|
||||
<thead class="table-light text-muted">
|
||||
<tr>
|
||||
<th style="width: 90px;" scope="col"
|
||||
th:text="#{checkout.summary.presupuesto}">Presupuesto</th>
|
||||
<th scope="col" th:text="#{checkout.summary.titulo}">Título</th>
|
||||
<th scope="col" class="text-end" th:text="#{checkout.summary.base}">
|
||||
Base</th>
|
||||
<th class="d-none"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="item : ${items}">
|
||||
<td>
|
||||
<span th:text="${item.presupuestoId}">PRESUPUESTO-001</span>
|
||||
</td>
|
||||
<td>
|
||||
<span th:text="${item.titulo}">Título del presupuesto</span>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span th:text="${item.baseTotal}">
|
||||
0,00</span>
|
||||
</td>
|
||||
<td class="d-none">
|
||||
<span th:text="${item.tirada}"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td colspan="2"><span th:text="#{cart.resumen.base}"></span></td>
|
||||
<td class="text-end" id="base-cesta"></td>
|
||||
</tr>
|
||||
<tr id="tr-iva-4">
|
||||
<td colspan="2"><span th:text="#{cart.resumen.iva-4}"></span> : </td>
|
||||
<td class="text-end" id="iva-4-cesta"></td>
|
||||
</tr>
|
||||
<tr id="tr-iva-21">
|
||||
<td colspan="2"><span th:text="#{cart.resumen.iva-21}"></span> : </td>
|
||||
<td class="text-end" id="iva-21-cesta"></td>
|
||||
</tr>
|
||||
<tr class="table-active">
|
||||
<td colspan="2"><span th:text="#{cart.resumen.total}"></span>:</td>
|
||||
<td class="text-end">
|
||||
<span id="total-cesta" class="fw-semibold">
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<button type="button" class="btn btn-secondary w-100 mt-2"
|
||||
th:text="#{cart.resumen.tramitar}">Checkout</button>
|
||||
</div>
|
||||
<!-- end table-responsive -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert border-dashed alert-danger" role="alert">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="ms-2">
|
||||
<h5 class="fs-14 text-danger fw-semibold"
|
||||
th:text="#{cart.resumen.fidelizacion}"></h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end stickey -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</th:block>
|
||||
|
||||
<th:block th:replace="~{theme/partials/vendor-scripts :: scripts}" />
|
||||
<th:block layout:fragment="pagejs">
|
||||
<script th:inline="javascript">
|
||||
window.languageBundle = /*[[${languageBundle}]]*/ {};
|
||||
</script>
|
||||
|
||||
<script type="module" th:src="@{/assets/js/pages/imprimelibros/checkout/checkout.js}"></script>
|
||||
</th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -0,0 +1,169 @@
|
||||
<div th:fragment="direccionForm">
|
||||
<form id="direccionForm" novalidate th:action="${action}" th:object="${dirForm}" method="post"
|
||||
th:data-add="#{direcciones.add}" th:data-edit="#{direcciones.editar}">
|
||||
|
||||
<div class="alert alert-danger" th:if="${#fields.hasGlobalErrors()}" th:each="err : ${#fields.globalErrors()}">
|
||||
<span th:text="${err}">Error</span>
|
||||
</div>
|
||||
|
||||
<input type="hidden" th:field="*{user.id}" />
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="alias">
|
||||
<span th:text="#{direcciones.alias}">Alias</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="alias" th:field="*{alias}" maxlength="100" required
|
||||
th:classappend="${#fields.hasErrors('alias')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('alias')}" th:errors="*{alias}"></div>
|
||||
<label th:text="#{direcciones.alias-descripcion}" class="form-text text-muted"></label>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="att">
|
||||
<span th:text="#{direcciones.nombre}">Nombre y Apellidos</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="att" th:field="*{att}" maxlength="150" required
|
||||
th:classappend="${#fields.hasErrors('att')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('att')}" th:errors="*{att}"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="direccion">
|
||||
<span th:text="#{direcciones.direccion}">Dirección</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<textarea class="form-control direccion-item" id="direccion" th:field="*{direccion}" maxlength="255"
|
||||
required style="max-height: 125px;"
|
||||
th:classappend="${#fields.hasErrors('direccion')} ? ' is-invalid'"></textarea>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('direccion')}" th:errors="*{direccion}"></div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="form-group col-lg-6 col-md-6 col-sm-12 ml-0">
|
||||
<label for="cp">
|
||||
<span th:text="#{direcciones.cp}">Código Postal</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input type="number" class="form-control direccion-item" id="cp" th:field="*{cp}" min="1" max="99999"
|
||||
required th:classappend="${#fields.hasErrors('cp')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('cp')}" th:errors="*{cp}"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-lg-6 col-md-6 col-sm-12 mr-0">
|
||||
<label for="ciudad">
|
||||
<span th:text="#{direcciones.ciudad}">Ciudad</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="ciudad" th:field="*{ciudad}" maxlength="100" required
|
||||
th:classappend="${#fields.hasErrors('ciudad')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('ciudad')}" th:errors="*{ciudad}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-2">
|
||||
<div class="form-group col-lg-6 col-md-6 col-sm-12 ml-0">
|
||||
<label for="provincia">
|
||||
<span th:text="#{direcciones.provincia}">Provincia</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="provincia" th:field="*{provincia}" maxlength="100"
|
||||
required th:classappend="${#fields.hasErrors('provincia')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('provincia')}" th:errors="*{provincia}"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-lg-6 col-md-6 col-sm-12 mr-0">
|
||||
<label for="pais">
|
||||
<span th:text="#{direcciones.pais}">País</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<select class="form-control select2 direccion-item" id="paisCode3" th:field="*{paisCode3}"
|
||||
th:classappend="${#fields.hasErrors('paisCode3')} ? ' is-invalid'">
|
||||
<option th:each="pais : ${paises}" th:value="${pais.id}" th:text="${pais.text}"
|
||||
th:selected="${pais.id} == ${dirForm.paisCode3}">
|
||||
</option>
|
||||
</select>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('paisCode3')}" th:errors="*{paisCode3}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="telefono">
|
||||
<span th:text="#{direcciones.telefono}">Teléfono</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="telefono" th:field="*{telefono}" maxlength="50"
|
||||
th:classappend="${#fields.hasErrors('telefono')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('telefono')}" th:errors="*{telefono}"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group mt-2">
|
||||
<label for="instrucciones">
|
||||
<span th:text="#{direcciones.instrucciones}">Instrucciones</span>
|
||||
</label>
|
||||
<textarea class="form-control direccion-item" id="instrucciones" th:field="*{instrucciones}" maxlength="255"
|
||||
style="max-height: 125px;"
|
||||
th:classappend="${#fields.hasErrors('instrucciones')} ? ' is-invalid'"></textarea>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('instrucciones')}" th:errors="*{instrucciones}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch form-switch-custom my-2">
|
||||
<input type="checkbox"
|
||||
class="form-check-input form-switch-custom-primary direccion-item direccionFacturacion"
|
||||
id="direccionFacturacion" th:field="*{direccionFacturacion}">
|
||||
<label for="direccionFacturacion" class="form-check-label" th:text="#{direcciones.isFacturacion}">
|
||||
Usar también como dirección de facturación
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:class="'form-group direccionFacturacionItems' + (${direccion != null and direccion.direccionFacturacion} ? '' : ' d-none')">
|
||||
<label for="razonSocial">
|
||||
<span th:text="#{direcciones.razon_social}">Razón Social</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="razonSocial" th:field="*{razonSocial}" maxlength="150"
|
||||
th:classappend="${#fields.hasErrors('razonSocial')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('razonSocial')}" th:errors="*{razonSocial}"></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
th:class="'row mt-2 direccionFacturacionItems' + (${direccion != null and direccion.direccionFacturacion} ? '' : ' d-none')">
|
||||
<div class="form-group col-lg-6 col-md-6 col-sm-12 ml-0">
|
||||
<label for="tipoIdentificacionFiscal">
|
||||
<span th:text="#{direcciones.tipo_identificacion_fiscal}">Tipo de identificación fiscal</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<select class="form-control select2 direccion-item" id="tipoIdentificacionFiscal"
|
||||
th:field="*{tipoIdentificacionFiscal}"
|
||||
th:classappend="${#fields.hasErrors('tipoIdentificacionFiscal')} ? ' is-invalid'">
|
||||
<option th:value="DNI" th:text="#{direcciones.dni}">DNI</option>
|
||||
<option th:value="NIE" th:text="#{direcciones.nie}">NIE</option>
|
||||
<option th:value="Pasaporte" th:text="#{direcciones.pasaporte}">Pasaporte</option>
|
||||
<option th:value="CIF" th:text="#{direcciones.cif}">CIF</option>
|
||||
<option th:value="VAT_ID" th:text="#{direcciones.vat_id}">VAT ID</option>
|
||||
</select>
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('tipoIdentificacionFiscal')}"
|
||||
th:errors="*{tipoIdentificacionFiscal}"></div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-lg-6 col-md-6 col-sm-12 ml-0">
|
||||
<label for="identificacionFiscal">
|
||||
<span th:text="#{direcciones.identificacion_fiscal}">Número de identificación fiscal</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="identificacionFiscal" th:field="*{identificacionFiscal}"
|
||||
maxlength="50" th:classappend="${#fields.hasErrors('identificacionFiscal')} ? ' is-invalid'">
|
||||
<div class="invalid-feedback" th:if="${#fields.hasErrors('identificacionFiscal')}"
|
||||
th:errors="*{identificacionFiscal}"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center justify-content-center">
|
||||
<button type="submit" class="btn btn-secondary mt-3" th:text="#{direcciones.save}"></button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@ -103,6 +103,7 @@
|
||||
<div class="form-group mt-2">
|
||||
<label for="telefono">
|
||||
<span th:text="#{direcciones.telefono}">Teléfono</span>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
<input class="form-control direccion-item" id="telefono" th:field="*{telefono}" maxlength="50"
|
||||
th:classappend="${#fields.hasErrors('telefono')} ? ' is-invalid'">
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
<div th:fragment="direccionCard(direccion)">
|
||||
<div class="card mb-3 direccion-card"
|
||||
th:attr="data-id=${direccion.id},
|
||||
data-cp=${direccion.cp},
|
||||
data-pais-code3=${direccion.pais.code3}">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title" th:text="${direccion.alias}">Alias</h5>
|
||||
|
||||
<h3 class="card-text mb-0"
|
||||
th:if="${direccion.att != null and !#strings.isEmpty(direccion.att)}"
|
||||
th:text="${direccion.att}">Att</h3>
|
||||
|
||||
<p class="card-text mb-0" th:text="${direccion.direccion}">Calle</p>
|
||||
<p class="card-text mb-0" th:text="${direccion.cp} + ' ' + ${direccion.ciudad}">CP Ciudad</p>
|
||||
<p class="card-text mb-0" th:text="${pais}">País</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -6,6 +6,9 @@
|
||||
<head>
|
||||
<!--page title-->
|
||||
<th:block layout:fragment="pagetitle" />
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
|
||||
<!-- Page CSS -->
|
||||
<th:block th:replace="~{imprimelibros/partials/head-css :: head-css}" />
|
||||
|
||||
Reference in New Issue
Block a user