package com.ejie.ad74a.control;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.zip.ZipOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.tools.zip.ZipEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.support.ByteArrayMultipartFileEditor;

import com.ejie.ad74a.exceptions.Ad74aException;
import com.ejie.ad74a.exceptions.Ad74aWebserviceException;
import com.ejie.ad74a.exceptions.ErrorField;
import com.ejie.ad74a.exceptions.ValidatorException;
import com.ejie.ad74a.model.NotifPostales;
import com.ejie.ad74a.service.NotifPostalesService;
import com.ejie.ad74a.service.interoperabilidad.RemesasService;
import com.ejie.ad74a.util.comun.UtilLiterales;
import com.ejie.ad74a.util.comun.UtilValidaciones;
import com.ejie.ad74a.util.comun.UtilWeb;
import com.ejie.ad74a.util.comun.UtilZip;
import com.ejie.ad74a.util.constantes.TipoNotificacionComunicacionEnum;
import com.ejie.ad74a.util.pif.Ad74aPIFws;
import com.ejie.x38.control.bind.annotation.RequestJsonBody;
import com.ejie.x38.dto.TableRequestDto;
import com.ejie.x38.dto.TableResponseDto;
import com.ejie.x38.util.DateTimeManager;

/**
 * NotifPostalesController generated by UDA, 09-ene-2024 16:08:24.
 * 
 * @author UDA
 */

@Controller
@RequestMapping(value = "/notifpostales")

public class NotifPostalesController {

	private static final String RUTA_DATOS_TEMPORAL = "ruta.datos.temporal";

	private static final Logger logger = LoggerFactory.getLogger(NotifPostalesController.class);

	@Autowired
	private NotifPostalesService notifPostalesService;
	@Autowired
	private RemesasService remesasService;
	@Autowired
	private Properties appConfiguration;
	@Autowired
	private ReloadableResourceBundleMessageSource messageSource;

	private DateFormat dfListFile = new SimpleDateFormat("yyyyMMdd");

	@InitBinder
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
		binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
		binder.registerCustomEditor(Date.class,
				new CustomDateEditor(DateTimeManager.getDateTimeFormat(LocaleContextHolder.getLocale()), true));
	}

	/*
	 * OPERACIONES CRUD (Create, Read, Update, Delete)
	 * 
	 */

	/**
	 * Operacion CRUD Read. Devuelve el bean correspondiente al identificador
	 * indicado.
	 * 
	 * @param idNotifPostal88 BigDecimal
	 * @return NotifPostales Objeto correspondiente al identificador indicado.
	 */
	@GetMapping(value = "/{idNotifPostal88}")
	public @ResponseBody NotifPostales get(@PathVariable Long idNotifPostal88) {
		NotifPostales notifPostales = new NotifPostales();
		notifPostales.setIdNotifPostal88(idNotifPostal88);
		notifPostales = this.notifPostalesService.find(notifPostales);
		NotifPostalesController.logger.info("[GET - findBy_PK] : Obtener NotifPostales por PK");
		return notifPostales;
	}

	/**
	 * Devuelve una lista de beans correspondientes a los valores de filtrados
	 * indicados en el objeto pasado como parametro.
	 *
	 * @param filterNotifPostales NotifPostales Objeto que contiene los parametros
	 *                            de filtrado utilizados en la busqueda.
	 * @return List<NotifPostales> Lista de objetos correspondientes a la busqueda
	 *         realizada.
	 */
	@GetMapping
	public @ResponseBody List<NotifPostales> getAll(@ModelAttribute NotifPostales filterNotifPostales) {
		NotifPostalesController.logger.info("[GET - find_ALL] : Obtener NotifPostales por filtro");
		prepareFilter(filterNotifPostales);
		return this.notifPostalesService.findAllLike(filterNotifPostales, null, false);
	}

	/**
	 * Descarga el listado a correspondencia para las notificaciones realizada entre
	 * dos fechas.
	 * 
	 * @param fechaInicio
	 * @param fechaFin
	 * @param response
	 * @throws IOException
	 */
	@PostMapping(value = "/listadocorrespondenciaParams")
	public @ResponseBody Map<String, Object> obtenerParametrosListadoCorrespondencia(
			@RequestJsonBody NotifPostales notifPostales, @RequestJsonBody(param = "fechaFin") Date fechaFin,
			HttpServletResponse response) throws IOException {
		NotifPostalesController.logger.info(
				"[POST - listadocorrespondenciaParams] : Obtiene los datos del listado a correspondencia entre dos fechas");
		validateDescargaListadoCorrespondencia(notifPostales);
		// Prepara filtro
		NotifPostales filter = new NotifPostales();
		filter.setFechaRegistroInicio(notifPostales.getFechaRegistroInicio());
		filter.setFechaRegistroFin(notifPostales.getFechaRegistroFin());
		// Recuperar notificaciones seleccionadas
		return this.notifPostalesService.obtenerParametrosListadoCorrespondenciaPorFechas(filter);
	}

	/*
	 * Valida que los parametros para lanzar la operación de descarga de listado a
	 * correspondencia, sean válidos. En caso contrario lanza un ValidatorException.
	 */
	private void validateDescargaListadoCorrespondencia(NotifPostales notifPostales) {
		List<ErrorField> errors = new ArrayList<>();
		if (notifPostales.getFechaRegistroInicio() == null) {
			errors.add(new ErrorField("fechaRegistroInicio", UtilValidaciones.LABEL_ERROR_OBLIGATORIO));
		}
		if (notifPostales.getFechaRegistroFin() == null) {
			errors.add(new ErrorField("fechaRegistroFin", UtilValidaciones.LABEL_ERROR_OBLIGATORIO));
		}
		if (CollectionUtils.isNotEmpty(errors)) {
			throw new ValidatorException(errors);
		}
	}

	/**
	 * Descarga los documentos de las notificaciones seleccionadas
	 *
	 * @param filterNotifPostales NotifPostales Bean que contiene los parametros de
	 *                            filtrado a emplear.
	 * @param tableRequestDto     Dto que contiene los parametros de configuracion
	 *                            propios del RUP_TABLE a aplicar en la busqueda.
	 * @throws Ad74aWebserviceException
	 * @throws IOException
	 */
	@PostMapping(value = "/descargardocumentos")
	public @ResponseBody void descargarDocumentos(@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto, HttpServletResponse response) {
		NotifPostalesController.logger
				.info("[POST - descargarDocumentos] : Descargar los documentos de las notificaciones");
		try {
			this.prepareFilter(filterNotifPostales);
			// Recuperar notificaciones seleccionadas
			List<NotifPostales> notifPostalesList = this.notifPostalesService.getMultiple(filterNotifPostales,
					tableRequestDto, false);
			// llamar al servicio de dokusi y descargar los documentos de las notificaciones
			// seleccionadas. (compatible tambien con comunicaciones)
			notifPostalesList = this.notifPostalesService.getDocumentsFromPlatea(notifPostalesList, true);
			// En funcion de lo que se haya obtenido devolvemos una respuesta diferente
			if (CollectionUtils.isEmpty(notifPostalesList)) {
				// Si no se ha encontrado ninguna notificacion, se devuelve un error
				throw new Ad74aException(UtilLiterales.getLiteralMessage(messageSource, "error.documentoNoEncontrado"));
			} else if (notifPostalesList.size() > 1) {
				// Si se ha recuperado mas de una notificacion, se devuelven en un zip
				File f = zipNotifPostales(notifPostalesList);
				sendFile2Response(response, f, "documentos.zip", f.length(), f.toPath());
			} else {
				// Si solo hay una notificacion, descargarla tal cual
				Ad74aPIFws pifWS = Ad74aPIFws.getInstance();
				sendFile2Response(response, pifWS.downloadDocument(notifPostalesList.get(0).getPifDocumentPath()),
						notifPostalesList.get(0).getTareasTramite().getTramitesExpediente().getExpediente()
								.getNumExpediente00() + "-" + notifPostalesList.get(0).getPlateaDocumentName(),
						notifPostalesList.get(0).getPifDocumentSize(), null);
			}
			response.flushBuffer();
		} catch (IOException | Ad74aWebserviceException e) {
			throw new Ad74aException(e, "Error al descargar documentos de PLATEA");
		}
	}

	/*
	 * Comprime en un solo fichero todos los documentos de notificacion postal que
	 * se hayan pasado por parametro.
	 */
	private File zipNotifPostales(List<NotifPostales> notifPostalesList) throws IOException, Ad74aWebserviceException {

		// Crear el directorio temporal si no existe
		String rutaTemp = this.appConfiguration.getProperty(RUTA_DATOS_TEMPORAL);
		File tmpDir = new File(rutaTemp);
		if (!tmpDir.exists()) {
			tmpDir.mkdirs();
		}

		File file = File.createTempFile("docs", ".zip",
				new File(this.appConfiguration.getProperty(RUTA_DATOS_TEMPORAL)));
		try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(file))) {
			Ad74aPIFws pifWS = Ad74aPIFws.getInstance();
			byte[] bytes = new byte[1024];

			for (NotifPostales notifPostales : notifPostalesList) {
				InputStream is = pifWS.downloadDocument(notifPostales.getPifDocumentPath());
				ZipEntry zipEntry = new ZipEntry(
						notifPostales.getTareasTramite().getTramitesExpediente().getExpediente().getNumExpediente00()
								+ "-" + notifPostales.getPlateaDocumentName());
				zipOut.putNextEntry(zipEntry);
				int length;
				while ((length = is.read(bytes)) >= 0) {
					zipOut.write(bytes, 0, length);
				}
				is.close();
			}
		}
		return file;
	}

	/**
	 * Descarga los documentos "Adjunto-remito" de las notificaciones seleccionadas
	 *
	 * @param filterNotifPostales NotifPostales Bean que contiene los parametros de
	 *                            filtrado a emplear.
	 * @param tableRequestDto     Dto que contiene los parametros de configuracion
	 *                            propios del RUP_TABLE a aplicar en la busqueda.
	 * @throws Ad74aWebserviceException
	 * @throws IOException
	 */
	@PostMapping(value = "/descargaradjuntoremito")
	public @ResponseBody void descargarAdjuntoRemito(
			@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto, HttpServletResponse response) {
		NotifPostalesController.logger
				.info("[POST - descargarDocumentos] : Descargar los documentos 'adjunto-remito' de las notificaciones");
		try {
			this.prepareFilter(filterNotifPostales);
			// Recuperar notificaciones seleccionadas
			List<NotifPostales> notifPostalesList = this.notifPostalesService.getMultiple(filterNotifPostales,
					tableRequestDto, false);
			// llamar al servicio de dokusi y descargar los documentos de las notificaciones
			// seleccionadas.
			File file = this.notifPostalesService.getAdjuntoRemitoFromPlatea(notifPostalesList);
			// En funcion de lo que se haya obtenido devolvemos una respuesta diferente
			if (file == null) {
				// Si no se ha encontrado el documento
				throw new Ad74aException(UtilLiterales.getLiteralMessage(messageSource, "error.documentoNoEncontrado"));
			} else {
				// Si se ha encontrado
				sendFile2Response(
						response, file, UtilLiterales.getLiteralMessageWithParams(messageSource,
								"notifpostales.ficheroAdjuntoRemito", new Object[] { dfListFile.format(new Date()) }),
						file.length(), file.toPath());
			}
			response.flushBuffer();
		} catch (IOException | Ad74aWebserviceException e) {
			throw new Ad74aException(e, "Error al descargar documentos de PLATEA");
		}
	}

	/**
	 * Obtiene los ids para los sobres/etiquetas de las notificaciones seleccionadas
	 *
	 * @param filterNotifPostales NotifPostales Bean que contiene los parametros de
	 *                            filtrado a emplear.
	 * @param tableRequestDto     Dto que contiene los parametros de configuracion
	 *                            propios del RUP_TABLE a aplicar en la busqueda.
	 * @throws IOException
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	@PostMapping(value = "/obtenerNotificacionesParaSobres")
	public @ResponseBody List<NotifPostales> obtenerNotificacionesParaSobres(
			@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto, HttpServletRequest request,
			HttpServletResponse response) {
		NotifPostalesController.logger.info("[POST - descargarSobres] : Descargar los sobres de las notificaciones");
		this.prepareFilter(filterNotifPostales);
		// Recuperar notificaciones seleccionadas
		filterNotifPostales.setTipoNot88(TipoNotificacionComunicacionEnum.NOTIFICACION.getValor());
		return this.notifPostalesService.getMultiple(filterNotifPostales, tableRequestDto, false);

	}

	@PostMapping(value = "/descargarsobres/{tipoSobre}")
	public @ResponseBody void descargarSobres(@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto, @PathVariable(name = "tipoSobre") String tipoSobre,
			HttpServletRequest request, HttpServletResponse response) {
		NotifPostalesController.logger.info("[POST - descargarSobres] : Descargar los sobres de las notificaciones");
		try {
			this.prepareFilter(filterNotifPostales);
			// Recuperar notificaciones seleccionadas
			List<NotifPostales> notifPostalesList = this.notifPostalesService.getMultiple(filterNotifPostales,
					tableRequestDto, false);
			// Por cada una de ellas llamar al servicio de etiquetas/sobres

			final MessageFormat urlFormat = new MessageFormat(this.appConfiguration.getProperty("url.aa66.sobresPost"));
			Locale locale = LocaleContextHolder.getLocale();
			String prefix = tipoSobre.equals("E") ? messageSource.getMessage("notifpostales.etiqueta", null, locale)
					: messageSource.getMessage("notifpostales.sobre", null, locale);
			StringBuilder ids = new StringBuilder();
			for (NotifPostales not : notifPostalesList) {
				if (TipoNotificacionComunicacionEnum.NOTIFICACION.getValor().equalsIgnoreCase(not.getTipoNot88())) {
					// solo se descargan las notificaciones, las comunicaciones no.
					ids.append(not.getIdEnvioPostal88()).append(",");
				}
			}
			ids.deleteCharAt(ids.length() - 1);
			URL urlAA66 = new URL(urlFormat.format(new String[] { ids.toString(), tipoSobre }));
			// Crear el directorio temporal si no existe
			String rutaTemp = this.appConfiguration.getProperty(RUTA_DATOS_TEMPORAL);
			File tmpDir = new File(rutaTemp);
			if (!tmpDir.exists()) {
				tmpDir.mkdirs();
			}

			File file = downloadFileFromUrl(urlAA66, Paths.get(this.appConfiguration.getProperty(RUTA_DATOS_TEMPORAL),
					prefix + "_" + System.currentTimeMillis() + ".pdf").toString());
			sendFile2Response(response, file, file.getName(), file.length(), file.toPath());
		} catch (IOException e) {
			throw new Ad74aException(e, "Error al descargar los sobres/etiquetas de PNP");
		}

	}

	/*
	 * Descarga un fichero desde una url dada. Se modifica la cabecera "prohibida"
	 * Origin, para evitar errores de CORS.
	 */
	private File downloadFileFromUrl(URL url, String filePath) throws IOException {
		File file = new File(filePath);
		if (!file.exists() && !file.createNewFile()) {
			logger.error("No se puede crear el fichero {}", file);
		}
		final StringBuilder trace = new StringBuilder();
		trace.append("\r\nurl");
		HttpURLConnection httpConn = UtilWeb.sendHttpURLConnection(url, "POST", true, true);
		int responseCode = httpConn.getResponseCode();
		httpConn.getHeaderFields().forEach((k, v) -> {
			trace.append("\r\n").append(k).append("=").append(v);
		});
		trace.append("\r\n").append(responseCode);
		if (responseCode == HttpURLConnection.HTTP_OK) {
			InputStream inputStream = httpConn.getInputStream();
			try (FileOutputStream outputStream = new FileOutputStream(filePath)) {
				boolean tracear = logger.isDebugEnabled();
				int bytesRead = -1;
				byte[] buffer = new byte[1024];
				while ((bytesRead = inputStream.read(buffer)) != -1) {
					outputStream.write(buffer, 0, bytesRead);
					if (tracear) {// Primeros 1024bytes van a la traza...
						trace.append("\r\nComienzo de response:").append(new String(buffer, StandardCharsets.UTF_8));
						tracear = false;
					}
				}
			}
			inputStream.close();
		} else {
			logger.error("Error {} en la obtencion del sobre/etiqueta: {}. Cabeceras devueltas: {}", responseCode,
					httpConn.getResponseMessage(), httpConn.getHeaderFields());
		}
		if (logger.isDebugEnabled()) {
			logger.debug(trace.toString());
		}
		httpConn.disconnect();
		return file;
	}

	// Encapsula la logica de mandar un fichero de vuelta en la response
	private void sendFile2Response(HttpServletResponse response, File file, String fileName, Long fileSize,
			Path filePathToRemove) throws IOException {
		try (InputStream is = new FileInputStream(file)) {
			sendFile2Response(response, is, fileName, fileSize, filePathToRemove);
		}
	}

	// Encapsula la logica de mandar un inputstream de vuelta en la response
	private void sendFile2Response(HttpServletResponse response, InputStream is, String fileName, Long fileSize,
			Path filePathToRemove) throws IOException {

		response.setStatus(HttpStatus.OK.value());
		response.setContentLengthLong(fileSize);
		response.setHeader("Content-disposition", "attachment; filename=" + fileName);
		IOUtils.copy(is, response.getOutputStream());
		response.flushBuffer();
		if (filePathToRemove != null) {
			Files.deleteIfExists(filePathToRemove);
		}
	}

	/**
	 * Descarga la prueba de entrega electronica de las notificaciones seleccionadas
	 *
	 * @param filterNotifPostales NotifPostales Bean que contiene los parametros de
	 *                            filtrado a emplear.
	 * @param tableRequestDto     Dto que contiene los parametros de configuracion
	 *                            propios del RUP_TABLE a aplicar en la busqueda.
	 * @throws IOException
	 */
	@PostMapping(value = "/descargarpee")
	public @ResponseBody void descargarPEE(@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto, HttpServletResponse response) throws IOException {
		NotifPostalesController.logger.info("[POST - descargarPEE] : Descargar las pruebas de entrega electronicas");
		prepareFilter(filterNotifPostales);
		// Recuperar notificaciones seleccionadas
		List<NotifPostales> notifPostalesList = this.notifPostalesService.getMultiple(filterNotifPostales,
				tableRequestDto, false);
		if (CollectionUtils.isEmpty(notifPostalesList)) {
			throw new ValidatorException("notifpostales.error.noseleccionregistro");
		}
		// TODO ¿LIMITE MAXIMO DE REGISTROS QUE SE PUEDAN SELECCIONAR PARA DESCARGAR SU
		// PEE?
		// llamar al servicio web de aa66 y descargar todas las pruebas
		// de entrega electronicas.
		List<File> fileList = new ArrayList<>();
		try {
			for (NotifPostales item : notifPostalesList) {
				fileList.add(remesasService.obtenerPruebaEntregaEnvio(item));
			}
		} catch (Throwable e) {// NOSONAR necesario capturar todo
			throw new ValidatorException("notifpostales.error.peenodisponible", e);
		}
		NotifPostalesController.logger.debug("Se han descargado todas las PEE ({}).", fileList.size());
		if (CollectionUtils.size(fileList) == 1) {
			// Descargar ese fichero por la response (y borrarlo despues)
			sendFile2Response(response, fileList.get(0), fileList.get(0).getName(), fileList.get(0).length(),
					fileList.get(0).toPath());
		} else {
			// Juntar todos los ficheros en un zip
			String rutaTemp = this.appConfiguration.getProperty(RUTA_DATOS_TEMPORAL);
			File zipFile = File.createTempFile("pee_", ".zip", new File(rutaTemp));
			UtilZip.zipFiles(fileList, zipFile, true);
			// Descargar ese fichero por la response (y borrarlo despues)
			sendFile2Response(response, zipFile, zipFile.getName(), zipFile.length(), zipFile.toPath());
		}
	}

	/**
	 * Crea una nuevas notificacion partiendo de una notificacion ya existente.
	 *
	 * @param filterNotifPostales NotifPostales Bean que contiene la informacion con
	 *                            la que se va a crear el nuevo registro.
	 * @return NotifPostales .
	 */
	@PostMapping(value = "/retramitarnotificacion")
	public @ResponseBody NotifPostales retramitarNotificacion(
			@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto) {
		NotifPostalesController.logger
				.info("[POST - retramitarNotificacion] : Se vuelve a lanzar la notificacion seleccionada");
		prepareFilter(filterNotifPostales);
		// Recuperar notificaciones seleccionadas
		List<NotifPostales> notifPostalesList = this.notifPostalesService.getMultiple(filterNotifPostales,
				tableRequestDto, false);
		if (CollectionUtils.isEmpty(notifPostalesList)) {
			throw new ValidatorException("notifpostales.error.noseleccionregistro");
		}
		return this.notifPostalesService.retramitarNotificacion(notifPostalesList.get(0));
	}

	/**
	 * Refrescar la situacion de las notificaciones seleccionadas
	 * 
	 * @param filterNotifPostales NotifPostales Bean que contiene los parametros de
	 *                            filtrado a emplear.
	 * @param tableRequestDto     Dto que contiene los parametros de configuracion
	 *                            propios del RUP_TABLE a aplicar en la busqueda.
	 * 
	 * @return "OK" cuando ha finalizado sin errores
	 */
	@PostMapping(value = "/refrescarsituacion")
	public @ResponseBody String refrescarSituacion(@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto) {
		NotifPostalesController.logger
				.info("[GET - refrescarSituacion] : Refrescar la situacion de las notificaciones seleccionadas");
		prepareFilter(filterNotifPostales);
		// Recuperar notificaciones seleccionadas (SOLO SE REFRESCARAN LOS REGISTROS
		// TIPO 'N' QUE NO ESTEN EN SITUACION FINAL)
		List<NotifPostales> notifPostalesList = this.notifPostalesService.getMultiple(filterNotifPostales,
				tableRequestDto, false);
		// TODO ¿LIMITE MAXIMO DE REGISTROS QUE SE PUEDA REFRESCAR SU SITUACION?

		// llamar al servicio de AA66 para consultar la situacion de cada
		// notificacion seleccionada, y guardar el resultado en bbdd.
		this.notifPostalesService.updateMultipleSituacionEnvio(notifPostalesList);
		return "OK";
	}

	/*
	 * METODOS COMPONENTE RUP_TABLE
	 * 
	 */

	/**
	 * Metodo de presentacion del RUP_TABLE.
	 * 
	 * @param model Model
	 * @return String
	 */
	@GetMapping(value = "/maint")
	public String getFormEdit(Model model) {
		NotifPostalesController.logger.info("[GET - View] : notifpostales");
		model.addAttribute("notifpostales", new NotifPostales());
		model.addAttribute("url_aa66_sobresPost", appConfiguration.getProperty("url.aa66.sobresPost"));
		model.addAttribute("url_aa66_sobres", appConfiguration.getProperty("url.aa66.sobres"));
		model.addAttribute("url_aa66_etiquetas", appConfiguration.getProperty("url.aa66.etiquetas"));
		model.addAttribute("url_aa66_envios", appConfiguration.getProperty("url.aa66.app_envios"));
		return "notifpostales";
	}

	/**
	 * Operacion de filtrado del componente RUP_TABLE.
	 * 
	 * @param filterNotifPostales NotifPostales Bean que contiene los parametros de
	 *                            filtrado a emplear.
	 * @param tableRequestDto     Dto que contiene los parametros de configuracion
	 *                            propios del RUP_TABLE a aplicar en el filtrado.
	 * @return TableResponseDto<NotifPostales> Dto que contiene el resultado del
	 *         filtrado realizado por el componente RUP_TABLE.
	 */
	@PostMapping(value = "/filter")
	public @ResponseBody TableResponseDto<NotifPostales> filter(
			@RequestJsonBody(param = "filter") NotifPostales filterNotifPostales,
			@RequestJsonBody TableRequestDto tableRequestDto) {
		NotifPostalesController.logger.info("[POST - filter] : Obtener NotifPostaless");
		prepareFilter(filterNotifPostales);
		return this.notifPostalesService.filter(filterNotifPostales, tableRequestDto, false);
	}

	/*
	 * Preparar el filtro para que se haga en todos los sitios igual
	 */
	private void prepareFilter(NotifPostales filterNotifPostales) {
		/*
		 * [jbhg] se adapta el filtro de pantalla, para que en los intervalos
		 * "desde-hasta" de fechas, la fecha "hasta" tenga la ultima hora del día, para
		 * que se recuperen todos los registros que estén dentro de esa fecha "hasta".
		 */
		filterNotifPostales.setFechaRegistroFin(lastHourDate(filterNotifPostales.getFechaRegistroFin()));
		filterNotifPostales.setFechaSituacionFin(lastHourDate(filterNotifPostales.getFechaSituacionFin()));
		/*
		 * filtro de "mostrar finalizadas". Si no viene informado, se le indica valor 0
		 * (solo "pendientes"). Si viene informado, solo puede venir con valor 1
		 * ("finalizadas"). En este caso se quiere mostrar tanto "pendientes" como
		 * "finalizadas", por lo que se le quita el valor para no filtrar por ello.
		 */
		filterNotifPostales.setFinalizada88(filterNotifPostales.getFinalizada88() == null ? 0 : null);
	}

	/**
	 * Establece en una fecha dada, la última hora del día. (Para usar en las fechas
	 * "hasta" de los intervalos de filtro)
	 * 
	 * @param d Date
	 * @return Date
	 */
	private Date lastHourDate(Date d) {
		if (d == null) {
			return d;
		}
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		c.set(Calendar.HOUR_OF_DAY, 23);
		c.set(Calendar.MINUTE, 59);
		c.set(Calendar.SECOND, 59);
		return c.getTime();
	}

}
