package com.rjconsultores.ventaboletos.dao.hibernate;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.SessionFactory;
import org.hibernate.transform.AliasToBeanResultTransformer;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.BooleanType;
import org.hibernate.type.DateType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.LongType;
import org.hibernate.type.StringType;
import org.hibernate.type.TimestampType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.rjconsultores.ventaboletos.dao.CajaDAO;
import com.rjconsultores.ventaboletos.dao.sqlbuilder.SQLBuilder;
import com.rjconsultores.ventaboletos.entidad.Aidf;
import com.rjconsultores.ventaboletos.entidad.Caja;
import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.entidad.Marca;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
import com.rjconsultores.ventaboletos.enums.TipoFormapago;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.exception.VendaEmbarcadaBoletoException;
import com.rjconsultores.ventaboletos.exception.VendaEmbarcadaBoletoFormapagoException;
import com.rjconsultores.ventaboletos.exception.VendaEmbarcadaCajaException;
import com.rjconsultores.ventaboletos.exception.VendaEmbarcadaCajaFormapagoException;
import com.rjconsultores.ventaboletos.utilerias.OcdUtil;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.DadosBancarioVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.NotaCreditoVendaPacoteVO;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.DatosDadosBancarioResultTransformer;
import com.rjconsultores.ventaboletos.vo.busquedapacotes.transformer.RelatorioVendaCartaoCashMonitorResultTransformer;
import com.rjconsultores.ventaboletos.vo.caja.CajaCerradoVO;
import com.rjconsultores.ventaboletos.vo.caja.CajaDetalleVO;
import com.rjconsultores.ventaboletos.vo.caja.CajaVO;
import com.rjconsultores.ventaboletos.vo.caja.PagamentoCartaoVO;
import com.rjconsultores.ventaboletos.vo.caja.PagamentoVO;
import com.rjconsultores.ventaboletos.vo.caja.ReceitaDespesaVO;
import com.rjconsultores.ventaboletos.vo.caja.UsuarioVO;
import com.rjconsultores.ventaboletos.vo.caja.VendaEmbarcadaVO;
import com.rjconsultores.ventaboletos.vo.cashmonitor.RelatorioVendaCartaoCashMonitorVO;

@Repository("cajaDAO")
@SuppressWarnings("unchecked")
public class CajaHibernateDAO extends GenericHibernateDAO<Object, Long> implements CajaDAO {

	private static Logger log = LogManager.getLogger(CajaHibernateDAO.class);

	@Autowired
	private SQLBuilder sqlBuilder;

	@Autowired
	public CajaHibernateDAO(@Qualifier("sessionFactory") SessionFactory factory) {
		setSessionFactory(factory);
	}

	@Override
	public List<CajaVO> buscarCajaFecha(boolean yaCerrado, Date fechaDesde, Date fechaHasta) {
		List<CajaVO> list = new ArrayList<CajaVO>();
		HashMap<Long, CajaVO> map = new HashMap<Long, CajaVO>();

		String sqlBuscarCajaFecha = sqlBuilder.getSQLBuscarCajaFecha(yaCerrado, fechaDesde, fechaHasta);
		SQLQuery sql = getSession().createSQLQuery(sqlBuscarCajaFecha)
				.addScalar("cajaId", LongType.INSTANCE)
				.addScalar("numAsiento", StringType.INSTANCE)
				.addScalar("categoriaId", IntegerType.INSTANCE)
				.addScalar("numFolioSistema", StringType.INSTANCE)
				.addScalar("claseServicioId", IntegerType.INSTANCE)
				.addScalar("marcaId", IntegerType.INSTANCE)
				.addScalar("origenId", IntegerType.INSTANCE)
				.addScalar("destinoId", IntegerType.INSTANCE)
				.addScalar("corridaId", IntegerType.INSTANCE)
				.addScalar("fecCorrida", DateType.INSTANCE)
				.addScalar("nombPasajero", StringType.INSTANCE)
				.addScalar("precioBase", BigDecimalType.INSTANCE)
				.addScalar("precioPagado", BigDecimalType.INSTANCE)
				.addScalar("tipoVentaId", IntegerType.INSTANCE)
				.addScalar("numSeriePreimpresa", StringType.INSTANCE)
				.addScalar("numFolioPreImpreso", StringType.INSTANCE)
				.addScalar("fecHorViaje", TimestampType.INSTANCE)
				.addScalar("fecHorVenta", TimestampType.INSTANCE)
				.addScalar("puntoVentaId", IntegerType.INSTANCE)
				.addScalar("numPuntoVenta", StringType.INSTANCE)
				.addScalar("numKmViaje", BigDecimalType.INSTANCE)
				.addScalar("numOperacion", StringType.INSTANCE)
				.addScalar("motivoCancelacionId", IntegerType.INSTANCE)
				.addScalar("empresaPuntoVentaId", IntegerType.INSTANCE)
				.addScalar("empresaCorridaId", IntegerType.INSTANCE)
				.addScalar("turnoId", IntegerType.INSTANCE)
				.addScalar("importeTaxaEmbarque", BigDecimalType.INSTANCE)
				.addScalar("importePedagio", BigDecimalType.INSTANCE)
				.addScalar("importeOutros", BigDecimalType.INSTANCE)
				.addScalar("importeSeguro", BigDecimalType.INSTANCE)
				.addScalar("rutaId", IntegerType.INSTANCE)
				.addScalar("usuarioId", IntegerType.INSTANCE)
				.addScalar("numAutorizacion", StringType.INSTANCE)
				.addScalar("ordenSevicio", StringType.INSTANCE);

		sql.setResultTransformer(new AliasToBeanResultTransformer(CajaVO.class));

		for (CajaVO cv : (List<CajaVO>) sql.list()) {
			if (map.containsKey(cv.getCajaId()) && map.get(cv.getCajaId()).getImporteTaxaEmbarque() != null &&
					!map.get(cv.getCajaId()).getImporteTaxaEmbarque().equals(0)) {
				cv.setImporteTaxaEmbarque(new BigDecimal(0));
			} else {
				map.put(cv.getCajaId(), cv);
			}
			list.add(cv);
		}

		return list;
	}

	@Override
	public List<CajaDetalleVO> buscarDetalleCaja(Date fechaDesde, Date fechaHasta, Boolean sembilhetesPacote) {

		String sqlBuscarCajaFecha = sqlBuilder.getSQLBuscarDatosCaja(fechaDesde, fechaHasta, sembilhetesPacote);

		SQLQuery sql = getSession().createSQLQuery(sqlBuscarCajaFecha)
				.addScalar("cajaId", LongType.INSTANCE)
				.addScalar("numAsiento", StringType.INSTANCE)
				.addScalar("categoriaId", IntegerType.INSTANCE)
				.addScalar("numFolioSistema", StringType.INSTANCE)
				.addScalar("claseServicioId", IntegerType.INSTANCE)
				.addScalar("marcaId", IntegerType.INSTANCE)
				.addScalar("origenId", IntegerType.INSTANCE)
				.addScalar("destinoId", IntegerType.INSTANCE)
				.addScalar("corridaId", IntegerType.INSTANCE)
				.addScalar("fecCorrida", DateType.INSTANCE)
				.addScalar("nombPasajero", StringType.INSTANCE)
				.addScalar("precioBase", BigDecimalType.INSTANCE)
				.addScalar("precioPagado", BigDecimalType.INSTANCE)
				.addScalar("tipoVentaId", IntegerType.INSTANCE)
				.addScalar("numSeriePreimpresa", StringType.INSTANCE)
				.addScalar("numFolioPreImpreso", StringType.INSTANCE)
				.addScalar("fecHorViaje", TimestampType.INSTANCE)
				.addScalar("fecHorVenta", TimestampType.INSTANCE)
				.addScalar("puntoVentaId", IntegerType.INSTANCE)
				.addScalar("numPuntoVenta", StringType.INSTANCE)
				.addScalar("numKmViaje", BigDecimalType.INSTANCE)
				.addScalar("numOperacion", StringType.INSTANCE)
				.addScalar("motivoCancelacionId", IntegerType.INSTANCE)
				.addScalar("empresaPuntoVentaId", IntegerType.INSTANCE)
				.addScalar("empresaCorridaId", IntegerType.INSTANCE)
				.addScalar("turnoId", IntegerType.INSTANCE)
				.addScalar("importeTaxaEmbarque", BigDecimalType.INSTANCE)
				.addScalar("importePedagio", BigDecimalType.INSTANCE)
				.addScalar("importeOutros", BigDecimalType.INSTANCE)
				.addScalar("importeSeguro", BigDecimalType.INSTANCE)
				.addScalar("rutaId", IntegerType.INSTANCE)
				.addScalar("usuarioId", IntegerType.INSTANCE)
				.addScalar("numAutorizacion", StringType.INSTANCE)
				.addScalar("ordenSevicio", StringType.INSTANCE)
				.addScalar("descPago", StringType.INSTANCE)
				.addScalar("cveCategoria", StringType.INSTANCE)
				.addScalar("formaPagoId", IntegerType.INSTANCE)
				.addScalar("vlrFormaPago", BigDecimalType.INSTANCE)
				.addScalar("descMotivo", StringType.INSTANCE)
				.addScalar("transacaoId", LongType.INSTANCE)
				.addScalar("transacaooriginalId", LongType.INSTANCE)
				.addScalar("descnumdoc", StringType.INSTANCE)
				.addScalar("descnumdoc2", StringType.INSTANCE)
				.addScalar("desctipodoc", StringType.INSTANCE)
				.addScalar("desctipodoc2", StringType.INSTANCE)
				.addScalar("desctelefono", StringType.INSTANCE)
				.addScalar("tipotarjeta", StringType.INSTANCE)
				.addScalar("cantparcelas", IntegerType.INSTANCE)
				.addScalar("numtarjeta", StringType.INSTANCE)
				.addScalar("fecoperacion", TimestampType.INSTANCE)
				.addScalar("nombtitular", StringType.INSTANCE)
				.addScalar("ocdId", LongType.INSTANCE)
				.addScalar("numoperacionOcd", StringType.INSTANCE)
				.addScalar("notacreditovendapacoteId", LongType.INSTANCE)
				.addScalar("operadoracartao", StringType.INSTANCE)
				.addScalar("cvesecretaria", StringType.INSTANCE)
				.addScalar("tipoPago", IntegerType.INSTANCE)
				.addScalar("indEncargoVenta", BooleanType.INSTANCE)
				.addScalar("descconvenio", StringType.INSTANCE)
				.addScalar("cveconvenio", StringType.INSTANCE)
				.addScalar("descsecretaria", StringType.INSTANCE);

		sql.setResultTransformer(new AliasToBeanResultTransformer(CajaDetalleVO.class));

		List<CajaDetalleVO> lsBusca = sql.list();

		List<CajaDetalleVO> lsResultado = new ArrayList<CajaDetalleVO>();

		for (CajaDetalleVO cd : lsBusca) {

			int indexOf = lsResultado.indexOf(cd);

			CajaDetalleVO cajaDetalleVO = null;

			if (indexOf != -1) {
				cajaDetalleVO = lsResultado.get(indexOf);
			} else {
				cajaDetalleVO = cd;
			}

			if (cajaDetalleVO.getFormaspagamento() == null) {
				cajaDetalleVO.setFormaspagamento(new ArrayList<PagamentoVO>());
			}

			if (!cd.getDescPago().equalsIgnoreCase("TROCA DE PASSAGEM")) {
				PagamentoVO pagamentoVO = new PagamentoVO();
				pagamentoVO.setFormapagamento(cd.getDescPago());
				pagamentoVO.setMoeda("R$");
				pagamentoVO.setValor(cd.getVlrFormaPago());
				pagamentoVO.setIdentificacaoEmpresa(cd.getCvesecretaria());
				pagamentoVO.setRazaoSocial(cd.getDescsecretaria());

				if (cd.getNotacreditovendapacoteId() != null) {
					NotaCreditoVendaPacoteVO notacredito = new NotaCreditoVendaPacoteVO();
					notacredito.setVouchernotacredito(cd.getNotacreditovendapacoteId().toString());
					pagamentoVO.setNotacredito(notacredito);
				}

				if (cd.getOcdId() != null) {
					NotaCreditoVendaPacoteVO notacredito = new NotaCreditoVendaPacoteVO();
					notacredito.setVouchernotacredito(OcdUtil.generaLocalizadorOCD(cd.getNumoperacionOcd(), cd.getOcdId()));
					pagamentoVO.setNotacredito(notacredito);
				}

				if (StringUtils.isNotBlank(cd.getNumAutorizacion())) {
					PagamentoCartaoVO cartao = new PagamentoCartaoVO();
					cartao.setNumautorizacao(cd.getNumAutorizacion());
					cartao.setBandeira(cd.getTipotarjeta());
					cartao.setDatapagamento(cd.getFecoperacion());
					cartao.setNumcartao(cd.getNumtarjeta());
					cartao.setParcelas(cd.getCantparcelas());
					cartao.setTitular(cd.getNombtitular());
					cartao.setOperadoracartao(cd.getOperadoracartao());

					pagamentoVO.setCartao(cartao);
				}

				cajaDetalleVO.getFormaspagamento().add(pagamentoVO);

				if (pagamentoVO.getDadosBancarios() == null) {
					pagamentoVO.setDadosBancarios(new ArrayList<DadosBancarioVO>());
				}

				if (isPagamentoDeposito(TipoFormapago.getTipoFormapagoByValor(cd.getTipoPago()))) {
					pagamentoVO.getDadosBancarios().addAll(carregarDadosDeposito(cd.getCajaId(), cd.getFormaPagoId()));
				}

				if (pagamentoVO.getDadosBancarios().isEmpty()) {
					pagamentoVO.setDadosBancarios(null);
				}
			}
			if (indexOf == -1) {
				lsResultado.add(cajaDetalleVO);
			}
		}

		List<CajaDetalleVO> filtrados = new ArrayList<CajaDetalleVO>();
		for (CajaDetalleVO c : lsResultado) {
			if (c.getFormaspagamento() != null && !c.getFormaspagamento().isEmpty() && !existeApenasFpReserva(c)) {
				filtrados.add(c);
			}
		}

		return filtrados;
	}

	private Boolean existeApenasFpReserva(CajaDetalleVO c) {
		if (c.getFormaspagamento().size() == 1
				&& c.getFormaspagamento().get(0).getFormapagamento().equals("RESERVA")) {
			return true;
		}

		return false;
	}

	@Override
	public List<UsuarioVO> buscarCajaCerrado(Date fecha, String cveusuario, String turnoid) {
		return buscarCajaCerrado(fecha, cveusuario, turnoid, false);
	}

	@Override
	public List<UsuarioVO> buscarUsuarioCerrado(Date fecha) {
		return buscarCajaCerrado(fecha, "*", "*", true);
	}

	private List<UsuarioVO> buscarCajaCerrado(Date fecha, String cveusuario, String turnoid, boolean sinDatosCaja) {
		List<CajaCerradoVO> list = new ArrayList<CajaCerradoVO>();
		HashMap<Long, CajaCerradoVO> map = new HashMap<Long, CajaCerradoVO>();

		try {
			String sqlBuscarUsuariosCajaCerrado = sqlBuilder.getSQLBuscarUsuariosCajaCerrado(fecha, cveusuario, turnoid);

			SQLQuery sql = getSession().createSQLQuery(sqlBuscarUsuariosCajaCerrado)
					.addScalar("usuarioId", IntegerType.INSTANCE)
					.addScalar("cveusuario", StringType.INSTANCE)
					.addScalar("puntoVentaId", IntegerType.INSTANCE)
					.addScalar("numPuntoVenta", StringType.INSTANCE)
					.addScalar("fecCorte", DateType.INSTANCE)
					.addScalar("turnoId", IntegerType.INSTANCE)
					.addScalar("importeTotal", BigDecimalType.INSTANCE);

			sql.setResultTransformer(new AliasToBeanResultTransformer(UsuarioVO.class));

			List<UsuarioVO> usuarios = sql.list();
			if (sinDatosCaja) {
				return usuarios;
			}
			for (UsuarioVO u : usuarios) {
				String sqlBuscarCajaFecha = sqlBuilder.getSQLBuscarCajaCerrado(u.getUsuarioId(), fecha, turnoid);

				sql = getSession().createSQLQuery(sqlBuscarCajaFecha)
						.addScalar("cajaId", LongType.INSTANCE)
						.addScalar("numFolioSistema", StringType.INSTANCE)
						.addScalar("origen", StringType.INSTANCE)
						.addScalar("destino", StringType.INSTANCE)
						.addScalar("corridaId", IntegerType.INSTANCE)
						.addScalar("precioPagado", BigDecimalType.INSTANCE)
						.addScalar("fecHorVenta", DateType.INSTANCE)
						.addScalar("importeTaxaEmbarque", BigDecimalType.INSTANCE)
						.addScalar("ruta", StringType.INSTANCE)
						.addScalar("numAutorizacion", StringType.INSTANCE)
						.addScalar("ordenSevicio", StringType.INSTANCE)
						.addScalar("secretaria", StringType.INSTANCE)
						.addScalar("cvesecretaria", StringType.INSTANCE)
						.addScalar("emissorTarjeta", StringType.INSTANCE)
						.addScalar("tipoPasaje", StringType.INSTANCE)
						.addScalar("formaPago", StringType.INSTANCE);

				sql.setResultTransformer(new AliasToBeanResultTransformer(CajaCerradoVO.class));

				for (CajaCerradoVO cv : (List<CajaCerradoVO>) sql.list()) {
					if (map.containsKey(cv.getCajaId()) && map.get(cv.getCajaId()).getImporteTaxaEmbarque() != null &&
							!map.get(cv.getCajaId()).getImporteTaxaEmbarque().equals(0)) {
						cv.setImporteTaxaEmbarque(new BigDecimal(0));
					} else {
						map.put(cv.getCajaId(), cv);
					}
					list.add(cv);
				}

				u.setPasajes(list);

				String sqlBuscarReceitaDespesa = sqlBuilder.getSQLBuscarReceitasDespesasCaja(u.getUsuarioId(), fecha);
				sql = getSession().createSQLQuery(sqlBuscarReceitaDespesa)
						.addScalar("precio", BigDecimalType.INSTANCE)
						.addScalar("tipoEvento", StringType.INSTANCE);
				sql.setResultTransformer(new AliasToBeanResultTransformer(ReceitaDespesaVO.class));
				u.setDiversos(sql.list());
			}
			return usuarios;
		} catch (Exception e) {
			log.error("", e);

			return null;
		}
	}

	@Override
	@Transactional(rollbackFor = { BusinessException.class, VendaEmbarcadaBoletoException.class, VendaEmbarcadaBoletoFormapagoException.class, VendaEmbarcadaCajaException.class, VendaEmbarcadaCajaFormapagoException.class })
	public void gerarVendaEmbarcada(VendaEmbarcadaVO vendaEmbarcada) throws VendaEmbarcadaBoletoException, VendaEmbarcadaBoletoFormapagoException, VendaEmbarcadaCajaException, VendaEmbarcadaCajaFormapagoException {
		inserirBoletoVendaEmbarcada(vendaEmbarcada);
		inserirBoletoFormaPagoVendaEmbarcada(vendaEmbarcada);
		inserirCajaVendaEmbarcada(vendaEmbarcada);
		inserirCajaFormaPagoVendaEmbarcada(vendaEmbarcada);
	}

	private void inserirCajaVendaEmbarcada(VendaEmbarcadaVO vendaEmbarcada) throws VendaEmbarcadaCajaException {

		try {

			SQLQuery query = getSession().createSQLQuery(sqlBuilder.getSQLInserirCajaVendaEmbarcada());

			vendaEmbarcada.setCajaId(obterIdCaja().longValue());

			query.setLong("cajaId", vendaEmbarcada.getCajaId());
			query.setString("numAsiento", vendaEmbarcada.getNumAsiento());
			query.setInteger("categoriaId", vendaEmbarcada.getCategoriaId());
			query.setInteger("claseServicioId", vendaEmbarcada.getClaseServicioId());
			query.setInteger("marcaId", vendaEmbarcada.getMarcaId());
			query.setInteger("origemId", vendaEmbarcada.getOrigemId());
			query.setInteger("destinoId", vendaEmbarcada.getDestinoId());
			query.setInteger("corridaId", vendaEmbarcada.getCorridaId());
			query.setDate("fecCorrida", vendaEmbarcada.getFecCorrida());
			query.setBigDecimal("precioBase", vendaEmbarcada.getPrecio());
			query.setBigDecimal("precioPagado", vendaEmbarcada.getPrecio());
			query.setInteger("tipoVentaId", vendaEmbarcada.getTipoVentaId());
			query.setDate("fechorViaje", vendaEmbarcada.getFechorViaje());
			query.setDate("fechorVenta", vendaEmbarcada.getFechorVenta());
			query.setInteger("puntoVentaId", vendaEmbarcada.getPuntoVentaId());
			query.setString("numOperacion", vendaEmbarcada.getNumOperacion());
			query.setBigInteger("empresaPuntoVentaId", vendaEmbarcada.getEmpresaId());
			query.setBigInteger("empresaCorridaId", vendaEmbarcada.getEmpresaId());
			query.setInteger("estacionId", vendaEmbarcada.getEstacionId());
			query.setInteger("usuarioId", vendaEmbarcada.getUsuarioId());
			query.setBigDecimal("importeTaxaEmbarque", vendaEmbarcada.getImporteTaxaEmbarque());
			query.setBigDecimal("importePedagio", vendaEmbarcada.getImportePedagio());
			query.setBigDecimal("importeOutros", vendaEmbarcada.getImporteOutros());
			query.setBigDecimal("importeSeguro", vendaEmbarcada.getImporteSeguro());
			query.setDate("fecCreacion", vendaEmbarcada.getFechorVenta());
			query.setInteger("rutaId", vendaEmbarcada.getRutaId());
			query.setTimestamp("fecModIf", vendaEmbarcada.getFecModIf());
			query.setString("numFolioPreimpresso", vendaEmbarcada.getNumFolioPreimpresso());
			query.setString("serieImpFiscal", vendaEmbarcada.getSerieImpFiscal());

			if (query.executeUpdate() != 1) {
				throw new VendaEmbarcadaCajaException("Erro ao gerar caixa venda embarcada");
			}

		} catch (VendaEmbarcadaCajaException e) {
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new VendaEmbarcadaCajaException(e.getMessage(), e);
		}

	}

	private void inserirCajaFormaPagoVendaEmbarcada(VendaEmbarcadaVO vendaEmbarcada) throws VendaEmbarcadaCajaFormapagoException {
		try {
			SQLQuery query = getSession().createSQLQuery(sqlBuilder.getSQLInserirCajaFormaPagoVendaEmbarcada());

			query.setInteger("formaPagoId", vendaEmbarcada.getFormaPagoId());
			query.setLong("cajaId", vendaEmbarcada.getCajaId());
			query.setBigDecimal("importe", vendaEmbarcada.getPrecio());
			query.setInteger("usuarioId", vendaEmbarcada.getUsuarioId());
			query.setLong("cajaFormaPagoId", obterIdCajaFormaPago().longValue());
			query.setTimestamp("fecModIf", vendaEmbarcada.getFecModIf());

			if (query.executeUpdate() != 1) {
				throw new VendaEmbarcadaCajaFormapagoException("Erro ao gerar forma de pagamento do caixa venda embarcada");
			}

		} catch (VendaEmbarcadaCajaFormapagoException e) {
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new VendaEmbarcadaCajaFormapagoException(e.getMessage(), e);
		}
	}

	private void inserirBoletoVendaEmbarcada(VendaEmbarcadaVO vendaEmbarcada) throws VendaEmbarcadaBoletoException {
		try {

			SQLQuery query = getSession().createSQLQuery(sqlBuilder.getSQLInserirBoletoVendaEmbarcada());

			vendaEmbarcada.setBoletoId(obterIdBoleto().longValue());
			vendaEmbarcada.setNumOperacion(obterNumOperacion().toString());

			query.setBigInteger("empresaCorridaId", vendaEmbarcada.getEmpresaId());
			query.setInteger("destinoId", vendaEmbarcada.getDestinoId());
			query.setInteger("tipoVentaId", vendaEmbarcada.getTipoVentaId());
			query.setInteger("categoriaId", vendaEmbarcada.getCategoriaId());
			query.setInteger("corridaId", vendaEmbarcada.getCorridaId());
			query.setInteger("claseServicioId", vendaEmbarcada.getClaseServicioId());
			query.setDate("fecCorrida", vendaEmbarcada.getFecCorrida());
			query.setInteger("puntoVentaId", vendaEmbarcada.getPuntoVentaId());
			query.setBigInteger("empresaPuntoVentaId", vendaEmbarcada.getEmpresaId());
			query.setInteger("origemId", vendaEmbarcada.getOrigemId());
			query.setInteger("marcaId", vendaEmbarcada.getMarcaId());
			query.setString("numAsiento", vendaEmbarcada.getNumAsiento());
			query.setBigDecimal("precioPagado", vendaEmbarcada.getPrecio());
			query.setDate("fechorViaje", vendaEmbarcada.getFechorViaje());
			query.setDate("fechorVenta", vendaEmbarcada.getFechorVenta());
			query.setString("numOperacion", vendaEmbarcada.getNumOperacion());
			query.setInteger("usuarioId", vendaEmbarcada.getUsuarioId());
			query.setBigDecimal("precioBase", vendaEmbarcada.getPrecio());
			query.setInteger("estacionId", vendaEmbarcada.getEstacionId());
			query.setBigDecimal("importeTaxaEmbarque", vendaEmbarcada.getImporteTaxaEmbarque());
			query.setBigDecimal("importePedagio", vendaEmbarcada.getImportePedagio());
			query.setBigDecimal("importeOutros", vendaEmbarcada.getImporteOutros());
			query.setBigDecimal("importeSeguro", vendaEmbarcada.getImporteSeguro());
			query.setInteger("rutaId", vendaEmbarcada.getRutaId());
			query.setLong("boletoId", vendaEmbarcada.getBoletoId());
			query.setTimestamp("fecModIf", vendaEmbarcada.getFecModIf());
			query.setBigDecimal("precioPricing", vendaEmbarcada.getPrecio());
			query.setString("numFolioPreimpresso", vendaEmbarcada.getNumFolioPreimpresso());
			query.setString("serieImpFiscal", vendaEmbarcada.getSerieImpFiscal());

			if (query.executeUpdate() != 1) {
				throw new VendaEmbarcadaBoletoException("Erro ao gerar boleto venda embarcada");
			}

		} catch (VendaEmbarcadaBoletoException e) {
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new VendaEmbarcadaBoletoException(e.getMessage(), e);
		}
	}

	private void inserirBoletoFormaPagoVendaEmbarcada(VendaEmbarcadaVO vendaEmbarcada) throws VendaEmbarcadaBoletoFormapagoException {
		try {

			SQLQuery query = getSession().createSQLQuery(sqlBuilder.getSQLInserirBoletoFormaPagoVendaEmbarcada());

			query.setInteger("formaPagoId", vendaEmbarcada.getFormaPagoId());
			query.setLong("boletoId", vendaEmbarcada.getBoletoId());
			query.setBigDecimal("importe", vendaEmbarcada.getPrecio());
			query.setTimestamp("fecModIf", vendaEmbarcada.getFecModIf());
			query.setInteger("usuarioId", vendaEmbarcada.getUsuarioId());
			query.setBigDecimal("boletoFormaPagoId", obterIdBoletoFormaPago());

			if (query.executeUpdate() != 1) {
				throw new VendaEmbarcadaBoletoFormapagoException("Erro ao gerar forma de pagamento do boleto venda embarcada");
			}

		} catch (VendaEmbarcadaBoletoFormapagoException e) {
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new VendaEmbarcadaBoletoFormapagoException(e.getMessage(), e);
		}
	}

	private BigDecimal obterIdBoletoFormaPago() {
		SQLQuery sql = getSession().createSQLQuery(sqlBuilder.getSQLObterSequenceBoletoFormaPago());

		return gerarChave((BigDecimal) sql.uniqueResult());
	}

	private BigDecimal obterIdCajaFormaPago() {
		SQLQuery sql = getSession().createSQLQuery(sqlBuilder.getSQLObterSequenceCajaFormaPago());

		return gerarChave((BigDecimal) sql.uniqueResult());
	}

	private BigDecimal obterIdBoleto() {
		SQLQuery sql = getSession().createSQLQuery(sqlBuilder.getSQLObterSequenceCajaFormaPago());

		return gerarChave((BigDecimal) sql.uniqueResult());
	}

	private BigDecimal obterIdCaja() {
		SQLQuery sql = getSession().createSQLQuery(sqlBuilder.getSQLObterSequenceCaja());

		return gerarChave((BigDecimal) sql.uniqueResult());
	}

	private BigDecimal obterNumOperacion() {
		SQLQuery sql = getSession().createSQLQuery(sqlBuilder.getSQLObterSequenciaNumOperacion());

		return gerarChave((BigDecimal) sql.uniqueResult());
	}

	private BigDecimal gerarChave(BigDecimal seq) {
		Integer tamChave = 13;

		String chave = "1";

		--tamChave;

		while ((seq.toString().length() + chave.length()) <= (tamChave)) {
			chave += "0";
		}

		return new BigDecimal(chave += seq);
	}

	private List<DadosBancarioVO> carregarDadosDeposito(Long cajaId, Integer formapagoId) {
		StringBuilder sQuery = new StringBuilder();
		sQuery.append("SELECT CDDP.IDENTIFICACAO_DEPOSITO, CDDP.IMPORTE, CDDP.FECDEPOSITO ")
				.append("FROM CAJA_DET_DEPOSITO_PAGO CDDP ")
				.append("JOIN CAJA_FORMAPAGO CFP ON CFP.CAJAFORMAPAGO_ID = CDDP.CAJAFORMAPAGO_ID ")
				.append("WHERE CDDP.ACTIVO = 1 ")
				.append("AND CFP.CAJA_ID = :cajaId ")
				.append("AND CFP.FORMAPAGO_ID = :formapagoId ");

		SQLQuery query = getSession().createSQLQuery(sQuery.toString())
				.addScalar("IDENTIFICACAO_DEPOSITO", StringType.INSTANCE)
				.addScalar("IMPORTE", BigDecimalType.INSTANCE)
				.addScalar("FECDEPOSITO", DateType.INSTANCE);

		query.setResultTransformer(new DatosDadosBancarioResultTransformer());
		query.setParameter("cajaId", cajaId);
		query.setParameter("formapagoId", formapagoId);

		return query.list();
	}

	private boolean isPagamentoDeposito(TipoFormapago tipoFormapago) {
		return TipoFormapago.DEPOSITO.equals(tipoFormapago);
	}

	@Override
	public Map<String, List<Caja>> buscarCajaYTarjeta(String... numoperacionList) {

		String queryString = "SELECT DISTINCT c FROM Caja c "
				+ "LEFT JOIN FETCH c.cajaFormaPago cfp "
				+ "LEFT JOIN FETCH cfp.cajaDetPago cdp "
				+ "LEFT JOIN FETCH cdp.cajaTarjetas ct "
				+ "WHERE c.numoperacion IN(:numoperacion) ";

		Query query = getSession().createQuery(queryString);
		query.setParameterList("numoperacion", numoperacionList);

		List<Caja> cajaList = query.list();
		HashMap<String, List<Caja>> result = new HashMap<String, List<Caja>>();
		for (Caja caja : cajaList) {
			String numoperacion = caja.getNumoperacion();
			List<Caja> cajaListTemp = result.get(numoperacion);
			if (cajaListTemp == null) {
				cajaListTemp = new ArrayList<Caja>();
				result.put(numoperacion, cajaListTemp);
			}
			cajaListTemp.add(caja);
		}

		return result;

	}

	@Override
	@Transactional(rollbackFor = { BusinessException.class })
	public Integer atualizaCajasIntegracaoTotvs(Marca marca, Date dataIncial, Date dataFinal, PuntoVenta puntoVenta) throws BusinessException {

		// update caja set integradototvs = 0 where PUNTOVENTA_ID = 269 and FECHORVENTA >= '30/03/2018' and FECHORVENTA <= '01/04/2018';
		StringBuilder sb = new StringBuilder();
		sb.append("  update caja set integradototvs = 2, CONTADORINTEGRADOTOTVS = 0 ");
		sb.append("  where FECHORVENTA >= :fechorInicial ");
		sb.append(" and  FECHORVENTA <= :fechorFinal ");
		sb.append(" and PUNTOVENTA_ID = :puntoVentaId ");
		if (marca != null) {
			sb.append(" and  MARCA_ID = :marcaId  ");
		}
		SQLQuery query = getSession().createSQLQuery(sb.toString());
		if (marca != null) {
			query.setInteger("marcaId", marca.getMarcaId());
		}
		query.setInteger("puntoVentaId", puntoVenta.getPuntoventaId());
		query.setTimestamp("fechorInicial", dataIncial);
		query.setTimestamp("fechorFinal", dataFinal);
		Integer result = query.executeUpdate();
		return result;
	}

	@Override
	public List<RelatorioVendaCartaoCashMonitorVO> buscarVendaCartaoCashMonitor(Date dataIncial, Date dataFinal, Empresa empresa, PuntoVenta puntoVenta) {
		SimpleDateFormat formatadorData = new SimpleDateFormat("dd/MM/yyyy");

		StringBuilder sql = new StringBuilder();
		sql.append("select to_char(ct.fecoperacion, 'dd/mm/yyyy') as data_transacao, ");
		sql.append("pv.nombpuntoventa as loja, ");
		sql.append("ct.nombtitular as adquirente, ");
		sql.append("ct.nsu as nsu, ");
		sql.append("ct.numautorizacion as autorizacao, ");
		sql.append("sum(cfp.importe) as valor_bruto, ");
		sql.append("fp.formapago_id as formapago_id, ");
		sql.append("ct.tipotarjeta as bandeira, ");
		sql.append("c.numoperacion as codigo_pedido, ");
		sql.append("cfp.importe valor_parcela, ");
		sql.append("count(ct.cajatarjeta_id) as parcelas ");
		sql.append("from caja c ");
		sql.append("inner join caja_formapago cfp on c.caja_id = cfp.caja_id and cfp.activo = 1 ");
		sql.append("inner join marca ma           on ma.marca_id = c.marca_id ");
		sql.append("inner join forma_pago fp      on cfp.formapago_id = fp.formapago_id ");
		sql.append("inner join caja_det_pago cdp  on c.caja_id = cdp.caja_id and cdp.cajaformapago_id = cfp.cajaformapago_id ");
		sql.append("inner join caja_tarjeta ct    on ct.cajadetpago_id = cdp.cajadetpago_id ");
		sql.append("inner join punto_venta pv     on pv.puntoventa_id = c.puntoventa_id ");
		sql.append("where c.activo = 1 ");
		sql.append("and c.indreimpresion = 0 ");
		sql.append("and fp.formapago_id in (2, 3) "); // Débito e Crédito
		sql.append("and ct.fecoperacion between to_date('" + formatadorData.format(dataIncial) + " 00:00', 'dd/mm/yyyy hh24:mi') and to_date('" + formatadorData.format(dataFinal) + " 23:59', 'dd/mm/yyyy hh24:mi') ");
		
		if (empresa!=null) {
			sql.append(" and ma.empresa_id = " + empresa.getEmpresaId());
		}
		
		if (puntoVenta!=null) {
			sql.append(" and c.puntoventa_id = " + puntoVenta.getPuntoventaId());
		}
		
		sql.append(" group by to_char(ct.fecoperacion, 'dd/mm/yyyy'), pv.nombpuntoventa, ct.nombtitular, ct.nsu, ct.numautorizacion, fp.formapago_id, ct.tipotarjeta, c.numoperacion, cfp.importe");
		sql.append(" order by 1, 2, 3, 4, 5");

		SQLQuery query = getSession().createSQLQuery(sql.toString())
				.addScalar("data_transacao", StringType.INSTANCE)
				.addScalar("loja", StringType.INSTANCE)
				.addScalar("adquirente", StringType.INSTANCE)
				.addScalar("nsu", StringType.INSTANCE)
				.addScalar("autorizacao", StringType.INSTANCE)
				.addScalar("valor_bruto", BigDecimalType.INSTANCE)
				.addScalar("formapago_id", IntegerType.INSTANCE)
				.addScalar("bandeira", StringType.INSTANCE)
				.addScalar("codigo_pedido", StringType.INSTANCE)
				.addScalar("valor_parcela", BigDecimalType.INSTANCE)
				.addScalar("parcelas", IntegerType.INSTANCE);

		query.setResultTransformer(new RelatorioVendaCartaoCashMonitorResultTransformer());

		return query.list();
	}

	@Override
	public String validarEstoqueUtilizado(Aidf aidf, String folioInicial, String folioFinal) {
		StringBuilder sql = new StringBuilder();
		sql.append(" SELECT tb.folio from ( ");
		sql.append(" SELECT coalesce(min( numfoliopreimpreso), '0') as folio ");
		sql.append(" FROM caja "); 
		sql.append(" where activo = 1 ");
		sql.append(" and numseriepreimpresa = :serie ");
		sql.append(" and numfoliopreimpreso between :folioInicial and :folioFinal ");
		sql.append(" union all ");
		sql.append(" SELECT coalesce(min( numfoliopreimpreso), '0') as folio ");
		sql.append(" FROM caja_diversos "); 
		sql.append(" where activo = 1 ");
		sql.append(" and numseriepreimpresa = :serie ");
		sql.append(" and numfoliopreimpreso between :folioInicial and :folioFinal ");
		sql.append(" )tb ");
		sql.append(" where tb.folio > 0 ");
		sql.append(" group by tb.folio ");

		
		SQLQuery query = getSession().createSQLQuery(sql.toString());
		query.setString("serie", aidf.obterSerieSubserieFormatada());
		query.setString("folioInicial", folioInicial);
		query.setString("folioFinal", folioFinal);
		return (String)query.uniqueResult();
	}
}
