package com.rjconsultores.ventaboletos.service.impl;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.zkoss.util.resource.Labels;

import com.rjconsultores.ventaboletos.constantes.Constantes;
import com.rjconsultores.ventaboletos.constantes.TipoEventoExtra;
import com.rjconsultores.ventaboletos.dao.ComissaoDAO;
import com.rjconsultores.ventaboletos.dao.ConferenciaComissaoDAO;
import com.rjconsultores.ventaboletos.entidad.Comissao;
import com.rjconsultores.ventaboletos.entidad.Conferencia;
import com.rjconsultores.ventaboletos.entidad.Constante;
import com.rjconsultores.ventaboletos.entidad.DescontoComissao;
import com.rjconsultores.ventaboletos.entidad.Empresa;
import com.rjconsultores.ventaboletos.entidad.EmpresaEmailConfig;
import com.rjconsultores.ventaboletos.entidad.EmpresaImposto;
import com.rjconsultores.ventaboletos.entidad.PtovtaComissao;
import com.rjconsultores.ventaboletos.entidad.PtovtaComissao.Receita;
import com.rjconsultores.ventaboletos.entidad.PuntoVenta;
import com.rjconsultores.ventaboletos.enums.CtrlFechamentoCaixaStatus;
import com.rjconsultores.ventaboletos.enums.IndStatusBoleto;
import com.rjconsultores.ventaboletos.enums.MimeType;
import com.rjconsultores.ventaboletos.enums.ModeloComissaoImpressaoPosterior;
import com.rjconsultores.ventaboletos.exception.BusinessException;
import com.rjconsultores.ventaboletos.exception.ComissaoException;
import com.rjconsultores.ventaboletos.service.CalculoComissaoService;
import com.rjconsultores.ventaboletos.service.ComissaoReceitaService;
import com.rjconsultores.ventaboletos.service.ComissaoService;
import com.rjconsultores.ventaboletos.service.ConferenciaComissaoService;
import com.rjconsultores.ventaboletos.service.ConstanteService;
import com.rjconsultores.ventaboletos.service.CtrlFechamentoCaixaService;
import com.rjconsultores.ventaboletos.service.DescontoComissaoService;
import com.rjconsultores.ventaboletos.service.EmpresaEmailConfigService;
import com.rjconsultores.ventaboletos.service.EmpresaImpostoService;
import com.rjconsultores.ventaboletos.service.EmpresaService;
import com.rjconsultores.ventaboletos.service.PtovtaComissaoService;
import com.rjconsultores.ventaboletos.service.PuntoVentaService;
import com.rjconsultores.ventaboletos.utilerias.DateUtil;
import com.rjconsultores.ventaboletos.utilerias.MoneyHelper;
import com.rjconsultores.ventaboletos.utilerias.SendMail;
import com.rjconsultores.ventaboletos.utilerias.SendMail.AuthType;
import com.rjconsultores.ventaboletos.utilerias.UsuarioLogado;
import com.rjconsultores.ventaboletos.vo.comissao.BoletoComissao;
import com.rjconsultores.ventaboletos.vo.comissao.ComissaoDesconto;
import com.rjconsultores.ventaboletos.vo.comissao.ComissaoDesconto.TipoDesconto;
import com.rjconsultores.ventaboletos.vo.comissao.ComissaoLogVO;
import com.rjconsultores.ventaboletos.vo.comissao.ComissaoReceita;
import com.rjconsultores.ventaboletos.vo.comissao.EmailConfigVO;
import com.rjconsultores.ventaboletos.vo.comissao.EventosFinanceirosVO;
import com.rjconsultores.ventaboletos.vo.comissao.FormapagoVO;
import com.rjconsultores.ventaboletos.vo.comissao.HistoricoComissao;
import com.rjconsultores.ventaboletos.vo.comissao.RegistroCalculo;

@Service("calculoComissaoService")
public class CalculoComissaoServiceImpl implements CalculoComissaoService {

	private static final Logger log = LogManager.getLogger(CalculoComissaoServiceImpl.class);
	private static final BigDecimal CEM = BigDecimal.TEN.multiply(BigDecimal.TEN);
	
	@Autowired
	private PtovtaComissaoService ptovtaComissaoService;

	@Autowired
	private EmpresaImpostoService empresaImpostoService;

	@Autowired
	private ComissaoService comissaoService;

	@Autowired
	private ComissaoDAO comissaoDAO;

	@Autowired
	private ConferenciaComissaoDAO conferenciaComissaoDAO;
	
	@Autowired
	private ConferenciaComissaoService conferenciaComissaoService; 

	@Autowired
	private DescontoComissaoService descontoComissaoService;
	
	@Autowired
	private ConstanteService constanteService;
	
	@Autowired
	private ComissaoReceitaService comissaoReceitaService;
	
	@Autowired
	private EmpresaService empresaService;
	
	@Autowired
	private PuntoVentaService puntoVentaService;
	
	@Autowired
	private CtrlFechamentoCaixaService ctrlFechamentoCaixaService;
	
	@Autowired
	private EmpresaEmailConfigService empresaEmailConfigService;	
	
	public boolean validaCompetencia(Date periodo) {
		Calendar calendario = Calendar.getInstance();
		calendario.setTime(periodo);

		int mes = calendario.get(Calendar.MONTH) + 1;
		int ano = calendario.get(Calendar.YEAR);

		Calendar now = Calendar.getInstance();
		int mesNow = now.get(Calendar.MONTH) + 1;
		int anoNow = now.get(Calendar.YEAR);

		if (anoNow == ano) {
			if (mesNow > mes) {
				return true;
			}

		} else if (anoNow > ano) {
			return true;
		}

		return false;
	}
	
	public boolean validaPeriodo(Date dataInicial, Date dataFinal) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(dataInicial);
		int monthInicial = cal.get(Calendar.MONTH);
		int yearInicial = cal.get(Calendar.YEAR);
		
		cal.setTime(dataFinal);
		int monthFinal = cal.get(Calendar.MONTH);
		int yearFinal = cal.get(Calendar.YEAR);
		
		if(monthInicial != monthFinal || yearFinal != yearInicial){
			return false;
		}

		return true;
	}

	@Override
	public void registrarCalculoComissao(PuntoVenta puntoVenta, Empresa empresa, Date periodo, boolean ignorarComissaoGerada, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo) throws ComissaoException {
		
		try {
			
			if (validaCompetencia(periodo)) {
	
				String competencia = DateUtil.getStringDate(periodo, "MM/yyyy");
				
				if(isRetencaoDiaria || conferenciaComissaoService.isConferenciaCompetenciaEncerrada(competencia, empresa, puntoVenta, false)) {
					Comissao comissaoCadastrada = comissaoDAO.buscaComissaoVigencia(puntoVenta.getPuntoventaId(), empresa.getEmpresaId(), competencia);
					if (comissaoCadastrada == null) {
		
						RegistroCalculo rc = realizarCalculoComissao(puntoVenta.getPuntoventaId(), empresa.getEmpresaId(), periodo, isRetencaoDiaria, usuarioId, isRefazerCalculo);
		
						gravarComissao(puntoVenta, empresa, rc, competencia, null, null);
					} else if(!ignorarComissaoGerada){
						throw new ComissaoException("busquedaCalculoComissaoController.registro.exception", null, comissaoCadastrada.getPuntoVenta().getNombpuntoventa());
					}
				} else {
					throw new ComissaoException("busquedaCalculoComissaoController.conferenciaNaoEncerrada.exception", null, puntoVenta.getNombpuntoventa());
				}
			} else {
				throw new ComissaoException("busquedaCalculoComissaoController.competencia.exception");
			}
		
		} catch (ComissaoException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new ComissaoException(e.getMessage(), e);
		}
	}

	/**
	 * Grava a comissao gerada
	 * @param puntoVenta
	 * @param empresa
	 * @param registroCalculo
	 * @param competencia
	 * @throws ComissaoException 
	 */
	private void gravarComissao(PuntoVenta puntoVenta, Empresa empresa, RegistroCalculo registroCalculo, String competencia, Date dataInicial, Date dataFinal) throws ComissaoException {
		try {
			Comissao comissao = new Comissao();
			
			if(StringUtils.isNotBlank(competencia)) {
				comissao.setCompetencia(competencia);
			} else if(dataInicial != null && dataFinal != null){
				comissao.setDataInicial(dataInicial);
				comissao.setDataFinal(dataFinal);
			}
			
			comissao.setEmpresaId(empresa.getEmpresaId());
			comissao.setPuntoVenta(puntoVenta);
			comissao.setBonificacaoMetas(registroCalculo.getComissaoBonificaoMetas());
			comissao.setComissaoBpr(registroCalculo.getComissaoBPR());
			comissao.setEntregasPassagem(registroCalculo.getComissaoEntregaPassagem());
			comissao.setReceitaExcessobagagem(registroCalculo.getComissaoExcessoBagagem());
			comissao.setReceitaSeguroopcional(registroCalculo.getComissaoSegOpcional());
			comissao.setReceitaSeguro(registroCalculo.getComissaoSeguro());
			comissao.setReceitaOutros(registroCalculo.getComissaoOutros());
			comissao.setRoyaties(registroCalculo.getRoyaties());
			comissao.setIssRetido(registroCalculo.getRetidoISS());

			comissao.setIndPago(false);
			comissao.setUsuarioPagamentoId(null);
			comissao.setDataPagamento(null);
			comissao.setDescontosEventuais(BigDecimal.ZERO);
			comissao.setDescontosFixos(BigDecimal.ZERO);

			for (ComissaoDesconto cd : registroCalculo.getLsDescontos()) {
				if (cd.getTipo().equals(TipoDesconto.EVENTUAL)) {
					comissao.setDescontosEventuais(MoneyHelper.somar(comissao.getDescontosEventuais(), cd.getValorDesconto()));
				} else if (cd.getTipo().equals(TipoDesconto.FIXO)) {
					comissao.setDescontosFixos(MoneyHelper.somar(comissao.getDescontosFixos(), cd.getValorDesconto()));
				}
			}
			
			for (ComissaoReceita comissaoReceita : registroCalculo.getLsReceitas()) {
				comissao.setReceitaBPR(MoneyHelper.somar(comissao.getReceitaBPR(), comissaoReceita.getReceitaBPR(), 2));
				comissao.setReceitaGAP(MoneyHelper.somar(comissao.getReceitaGAP(), comissaoReceita.getReceitaGAP(), 2));
				comissao.setDevolvidos(MoneyHelper.somar(comissao.getDevolvidos(), comissaoReceita.getDevolvidosRelatorio(), 2));
				comissao.setDevolvidos(MoneyHelper.somar(comissao.getDevolvidos(), comissaoReceita.getDevolvidosGAPRelatorio(), 2));
				comissao.setDevolvidos(MoneyHelper.somar(comissao.getDevolvidos(), comissaoReceita.getCancelados(), 2));
				comissao.setDevolvidos(MoneyHelper.somar(comissao.getDevolvidos(), comissaoReceita.getCanceladosGAP(), 2));
				comissao.setDevolvidos(MoneyHelper.somar(comissao.getDevolvidos(), comissaoReceita.getCanceladosGAP(), 2));
				comissao.setReceitaBrutaExcessoBagagem(MoneyHelper.somar(comissao.getReceitaBrutaExcessoBagagem(), comissaoReceita.getReceitaExcessoBagagem(), 2));
				comissao.setReceitaBrutaSeguroopcional(MoneyHelper.somar(comissao.getReceitaBrutaSeguroopcional(), comissaoReceita.getReceitaSeguroOpcional(), 2));
				comissao.setReceitaBrutaSeguro(MoneyHelper.somar(comissao.getReceitaBrutaSeguro(), comissaoReceita.getReceitaSeguro(), 2));
			}

			comissao = comissaoService.suscribir(comissao);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new ComissaoException(e.getMessage(), e);
		}
	}

	@Override
	public void cancelarCalculoComissao(Integer puntoVentaId, Integer empresaId, Date periodo) throws ComissaoException, BusinessException {
		try {
			String competencia = DateUtil.getStringDate(periodo, "MM/yyyy");
			Comissao comissao = comissaoDAO.buscaComissaoVigencia(puntoVentaId, empresaId, competencia);
			if (comissao != null) {
				comissaoService.borrar(comissao);
			} else {
				throw new ComissaoException("busquedaCalculoComissaoController.comissao.exception");
			}
		} catch (ComissaoException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage(), e);
		}
	}

	@Override
	public RegistroCalculo relatorioCalculoComissao(Integer puntoVentaId, Integer empresaId, Date periodo, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo) throws ComissaoException, BusinessException {
		return realizarCalculoComissao(puntoVentaId, empresaId, periodo, isRetencaoDiaria, usuarioId, isRefazerCalculo);
	}

	private BigDecimal calculoComisssaoBPR(boolean isAltaTemporada, PtovtaComissao ptovtaComissao, BigDecimal bpr, BigDecimal gap, boolean isBilheteGap, ComissaoLogVO comissaoLog) {

		// comissão BPR = Receita comissão * (% Com BPR)
		BigDecimal recbpr = BigDecimal.ZERO;
		BigDecimal receitaBPR = MoneyHelper.somar(bpr, gap, 2);
		
		BigDecimal percentualComissao = BigDecimal.ZERO;
		if (isAltaTemporada) {
			percentualComissao = ptovtaComissao.getPassagemAlta() != null ? ptovtaComissao.getPassagemAlta() : BigDecimal.ZERO;
		} else {
			percentualComissao = ptovtaComissao.getPassagemBaixa() != null ? ptovtaComissao.getPassagemBaixa() : BigDecimal.ZERO;
		}
		
		log.info(String.format(":: Percentual comissão: %s ::", percentualComissao));

		if(isBilheteGap && ModeloComissaoImpressaoPosterior.COMPARTILHADA.equals(ptovtaComissao.getModeloComissaoImpressaoPosterior())) {
			if (isAltaTemporada) {
				percentualComissao = ptovtaComissao.getValorVendaGapCompAlta() != null ? ptovtaComissao.getValorVendaGapCompAlta() : BigDecimal.ZERO;
			} else {
				percentualComissao = ptovtaComissao.getValorVendaGapComp() != null ? ptovtaComissao.getValorVendaGapComp() : BigDecimal.ZERO;
			}
			log.info(String.format(":: Comissao Compartilhada Configurada para Bilhetes Imp. Post. - Percentual comissão Alterado para: %s ::", percentualComissao));
		}
		
		comissaoLog.setPorcComissao(percentualComissao);
		
		recbpr = MoneyHelper.multiplicar(receitaBPR, MoneyHelper.dividir(percentualComissao,CEM,4), 4);

		return recbpr;
	}

	private BigDecimal calculoEntregaPassagem(boolean isAltaTemporada, PtovtaComissao ptovtaComissao, BigDecimal gapImpressa, BigDecimal internet, int contImpressa) {

		// EntregaPassagem (Internet/Venda impressão Posterior/Outros)
		BigDecimal entregaPassagem = BigDecimal.ZERO;
		BigDecimal receitaEntrega = MoneyHelper.somar(gapImpressa, internet, 2);
		
		log.info(String.format(":: Modelo Comissao Configurado Para Entrega Passagem: %s ::", ptovtaComissao.getModeloComissaoImpressaoPosterior()));
		if(ModeloComissaoImpressaoPosterior.PADRAO.equals(ptovtaComissao.getModeloComissaoImpressaoPosterior())) {
			if(isAltaTemporada) {
				if(ptovtaComissao.getValorImpressaoGapAlta() != null) {
					if (BooleanUtils.toBoolean(ptovtaComissao.getIndimpressaogapporc())) {
						entregaPassagem = MoneyHelper.multiplicar(receitaEntrega, ptovtaComissao.getValorImpressaoGapAlta() != null ? MoneyHelper.dividir(ptovtaComissao.getValorImpressaoGapAlta(),CEM,4) : BigDecimal.ZERO, 4);
					} else {
						entregaPassagem = ptovtaComissao.getValorImpressaoGapAlta() != null ? MoneyHelper.multiplicar(ptovtaComissao.getValorImpressaoGapAlta(),new BigDecimal(contImpressa), 2) : BigDecimal.ZERO;
					}
				}
			} else {
				if(ptovtaComissao.getValorImpressaoGap() != null) {
					if (BooleanUtils.toBoolean(ptovtaComissao.getIndimpressaogapporc())) {
						entregaPassagem = MoneyHelper.multiplicar(receitaEntrega, ptovtaComissao.getValorImpressaoGap() != null ? MoneyHelper.dividir(ptovtaComissao.getValorImpressaoGap(),CEM,4) : BigDecimal.ZERO, 4);
					} else {
						entregaPassagem = ptovtaComissao.getValorImpressaoGap() != null ? MoneyHelper.multiplicar(ptovtaComissao.getValorImpressaoGap(),new BigDecimal(contImpressa), 2) : BigDecimal.ZERO;
					}
				}
			}
		} else if(ModeloComissaoImpressaoPosterior.COMPARTILHADA.equals(ptovtaComissao.getModeloComissaoImpressaoPosterior())) {
			if(isAltaTemporada) {
				entregaPassagem = MoneyHelper.multiplicar(receitaEntrega, ptovtaComissao.getValorImpGapCompAlta() != null ? MoneyHelper.dividir(ptovtaComissao.getValorImpGapCompAlta(),CEM,4) : BigDecimal.ZERO, 4);
			} else {
				entregaPassagem = MoneyHelper.multiplicar(receitaEntrega, ptovtaComissao.getValorImpGapComp() != null ? MoneyHelper.dividir(ptovtaComissao.getValorImpGapComp(),CEM,4) : BigDecimal.ZERO, 4);
			}
		}

		return entregaPassagem;
	}

	private BigDecimal calculoExcessoBagagem(boolean isAltaTemporada, PtovtaComissao ptovtaComissao, BigDecimal excBag, ComissaoLogVO comissaoLog) {

		// comissão Excesso = Receita Excesso Bagagem * (% Com. Exc. Bag)
		BigDecimal excessoBagagem = BigDecimal.ZERO;
		if (isAltaTemporada) {
			comissaoLog.setPorcComissao(ptovtaComissao.getExcessoAlta());
			excessoBagagem = MoneyHelper.multiplicar(excBag, ptovtaComissao.getExcessoAlta() != null ? MoneyHelper.dividir(ptovtaComissao.getExcessoAlta(), CEM, 4) : BigDecimal.ZERO, 4);
		} else {
			comissaoLog.setPorcComissao(ptovtaComissao.getExcessoBaixa());
			excessoBagagem = MoneyHelper.multiplicar(excBag, ptovtaComissao.getExcessoBaixa() != null ? MoneyHelper.dividir(ptovtaComissao.getExcessoBaixa(), CEM, 4) : BigDecimal.ZERO, 4);
		}

		return excessoBagagem;
	}
	
	private BigDecimal calculoSeguroObrigatorio(boolean isAltaTemporada, PtovtaComissao ptovtaComissao, BigDecimal seguroObrigatorio) {
		
		// comissão Seg. Obrigatorio = Receita Seguro Obrigatorio * (% Com. Seg. Pol)
		BigDecimal recSeguroObrigatorio = BigDecimal.ZERO;
		if (isAltaTemporada) {
			recSeguroObrigatorio = MoneyHelper.multiplicar(seguroObrigatorio, ptovtaComissao.getSeguroobrigatorioAlta() != null ? MoneyHelper.dividir(ptovtaComissao.getSeguroobrigatorioAlta(), CEM, 4) : BigDecimal.ZERO, 4);
		} else {
			recSeguroObrigatorio = MoneyHelper.multiplicar(seguroObrigatorio, ptovtaComissao.getSeguroobrigatorioBaixa() != null ? MoneyHelper.dividir(ptovtaComissao.getSeguroobrigatorioBaixa(), CEM, 4) : BigDecimal.ZERO, 4);
		}
		return recSeguroObrigatorio;
	}

	private BigDecimal calculoSeguroOpcional(boolean isAltaTemporada, PtovtaComissao ptovtaComissao, BigDecimal segOpcional, ComissaoLogVO comissaoLog) {

		// comissão Seg. Opcional = Receita Seguro Opcional * (% Com. Seg. Pol)
		BigDecimal recsegOpcional = BigDecimal.ZERO;
		if (isAltaTemporada) {
			comissaoLog.setPorcComissao(ptovtaComissao.getSeguroAlta());
			recsegOpcional = MoneyHelper.multiplicar(segOpcional, ptovtaComissao.getSeguroAlta() != null ? MoneyHelper.dividir(ptovtaComissao.getSeguroAlta(), CEM, 4) : BigDecimal.ZERO, 4);
		} else {
			comissaoLog.setPorcComissao(ptovtaComissao.getSeguroBaixa());
			recsegOpcional = MoneyHelper.multiplicar(segOpcional, ptovtaComissao.getSeguroBaixa() != null ? MoneyHelper.dividir(ptovtaComissao.getSeguroBaixa(), CEM, 4) : BigDecimal.ZERO, 4);
		}
		return recsegOpcional;
	}

	private BigDecimal calculoOutros(boolean isAltaTemporada, PtovtaComissao ptovtaComissao, BigDecimal outros, ComissaoLogVO comissaoLog) {

		// comissão Seg. Opcional = Receita Seguro Opcional * (% Com. Seg. Pol)
		BigDecimal recoutros = BigDecimal.ZERO;
		if (isAltaTemporada) {
			comissaoLog.setPorcComissao(ptovtaComissao.getOutrosAlta());
			recoutros = MoneyHelper.multiplicar(outros, ptovtaComissao.getOutrosAlta() != null ? MoneyHelper.dividir(ptovtaComissao.getOutrosAlta(), CEM, 4) : BigDecimal.ZERO, 4);
		} else {
			comissaoLog.setPorcComissao(ptovtaComissao.getOutrosBaixa());
			recoutros = MoneyHelper.multiplicar(outros, ptovtaComissao.getOutrosBaixa() != null ? MoneyHelper.dividir(ptovtaComissao.getOutrosBaixa(), CEM, 4) : BigDecimal.ZERO, 4);
		}
		return recoutros;
	}

	private Map<String, Object> calculoDescontos(Integer puntoVentaId, Integer empresaId, Date dataInicial, Date dataFinal, PtovtaComissao ptovtaComissao) {

		List<ComissaoDesconto> lsDescontos = new ArrayList<ComissaoDesconto>();
		BigDecimal valorDescontoTotal = BigDecimal.ZERO;

		List<DescontoComissao> itensDescontos = descontoComissaoService.buscaDescontoComissaoPeriodo(puntoVentaId, empresaId, dataInicial, dataFinal);

		for (DescontoComissao dc : itensDescontos) {

			BigDecimal valorDesconto = dc.getPreco();
			valorDescontoTotal = MoneyHelper.somar(valorDescontoTotal, valorDesconto, 2);

			ComissaoDesconto desconto = new ComissaoDesconto();
			if (dc.getDatafinal() == null) {
				desconto.setTipo(TipoDesconto.FIXO);
			} else {
				desconto.setTipo(TipoDesconto.EVENTUAL);
			}
			desconto.setNomeDesconto(dc.getItemDesconto().getNomitemdesconto());
			desconto.setValorDesconto(valorDesconto);

			lsDescontos.add(desconto);
		}

		Map<String, Object> respDescontos = new HashMap<String, Object>();
		respDescontos.put("LISTA_DESCONTOS", lsDescontos);
		respDescontos.put("VALOR_DESCONTOS", valorDescontoTotal);

		return respDescontos;
	}

	@Override
	public RegistroCalculo realizarCalculoComissao(Integer puntoVentaId, Integer empresaId, Date periodo, Boolean isRetencaoDiaria, Integer usuarioId, Boolean isRefazerCalculo) throws ComissaoException, BusinessException {

		Conferencia conferencia = new Conferencia();
		conferencia.setPuntoVenta(new PuntoVenta(puntoVentaId));
		conferencia.setEmpresa(new Empresa(empresaId));

		Calendar calendario = Calendar.getInstance();
		calendario.setTime(periodo);
		int diaInicial = -1;
		int diaFinal = -1;
		int mes = calendario.get(Calendar.MONTH);
		int ano = calendario.get(Calendar.YEAR);
		
		if(isRetencaoDiaria) {
			conferencia.setDatamovimento(periodo);
			diaInicial = calendario.get(Calendar.DAY_OF_MONTH);
			diaFinal = calendario.get(Calendar.DAY_OF_MONTH);
		} else {
			conferencia.setCompetencia(DateUtil.getStringDate(periodo, "MM/yyyy"));
			diaInicial = calendario.getActualMinimum(Calendar.DAY_OF_MONTH);
			diaFinal = calendario.getActualMaximum(Calendar.DAY_OF_MONTH);
		}
		
		Date dataInicial = getDate(diaInicial, mes, ano);
		Date dataFinal = getDate(diaFinal, mes, ano);
		
		return realizarCalculoComissao(puntoVentaId, empresaId, usuarioId, isRefazerCalculo, conferencia, dataInicial, dataFinal, isRetencaoDiaria);
			
	}

	/**
	 * Realiza calculo da comissao
	 * @param puntoVentaId
	 * @param empresaId
	 * @param usuarioId
	 * @param isRefazerCalculo
	 * @param conferencia
	 * @param dataInicial
	 * @param dataFinal
	 * @param isRetencaoDiaria 
	 * @return
	 * @throws BusinessException
	 * @throws ComissaoException 
	 */
	private RegistroCalculo realizarCalculoComissao(Integer puntoVentaId, Integer empresaId, Integer usuarioId, Boolean isRefazerCalculo, Conferencia conferencia, Date dataInicial, Date dataFinal, boolean isRetencaoDiaria) throws BusinessException, ComissaoException {
		try {
			PtovtaComissao ptovtaComissao = ptovtaComissaoService.buscarPuntaVentaEmpresa(puntoVentaId, empresaId);
			if (ptovtaComissao != null && (ptovtaComissao.getIndretercomissao() == null || !ptovtaComissao.getIndretercomissao())) {
				//Abate no valor da comissão bpr as saídas de caixa
				boolean consideraBilhetesDevolvidosEmOutraAgencia = (ptovtaComissao.getIndbilhetesdevcanorigem() == null)?false:ptovtaComissao.getIndbilhetesdevcanorigem();
				
				List<ComissaoReceita> receitas = null;
				if(isRefazerCalculo) {
					comissaoReceitaService.limparComissaoReceita(empresaId, puntoVentaId, dataInicial, dataFinal);
					List<BoletoComissao> receitasBoleto = conferenciaComissaoDAO.carregarBilhetesComissao(conferencia, true, consideraBilhetesDevolvidosEmOutraAgencia);
					log.info("Total de bilhetes: " + receitasBoleto.size());
					List<EventosFinanceirosVO> eventosFinanceirosVOs = conferenciaComissaoDAO.carregarEventosFinanceiros(conferencia);
					log.info("Total de eventos extras: " + eventosFinanceirosVOs.size());
					receitas = calculaReceitaComissao(empresaId, ptovtaComissao, receitasBoleto, eventosFinanceirosVOs, dataInicial, dataFinal);
					reterComissaoReceitaDiaria(empresaId, puntoVentaId, usuarioId,  receitas);
				} else {
					receitas = recuperarComissaoReceita(empresaId, puntoVentaId, dataInicial, dataFinal);
				}
				
				if(!isRetencaoDiaria) {
					return calcularRegistroCalculo(ptovtaComissao, puntoVentaId, empresaId, dataInicial, dataFinal, receitas);
				}
			} else {
				if(ptovtaComissao != null && ptovtaComissao.getIndretercomissao() != null && ptovtaComissao.getIndretercomissao()) {
					throw new ComissaoException("busquedaCalculoComissaoController.PtovtaComissaoReterComissao.exception", null, ptovtaComissao.getDescComissaoId() != null ? ptovtaComissao.getPuntoventaId().getNombpuntoventa() : "");
				} else if(!isRefazerCalculo) {
					throw new ComissaoException("busquedaCalculoComissaoController.PtovtaComissao.exception");
				}
			}
			
		}catch(ComissaoException e ){
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException("busquedaCalculoComissaoController.PtovtaComissao.exception");
		}
		
		return null;
	}

	private List<ComissaoReceita> recuperarComissaoReceita(Integer empresaId, Integer puntoVentaId, Date dataInicial, Date dataFinal) {
		return comissaoReceitaService.recuperarComissaoReceita(empresaId, puntoVentaId, dataInicial, dataFinal);
	}

	/**
	 * Retem dados para calculo da comissao
	 * @param empresaId
	 * @param puntoVentaId
	 * @param usuarioId 
	 * @param receitas
	 * @throws BusinessException 
	 */
	private void reterComissaoReceitaDiaria(Integer empresaId, Integer puntoVentaId, Integer usuarioId, List<ComissaoReceita> receitas) throws BusinessException {
		comissaoReceitaService.reterComissaoReceitaDiaria(empresaId, puntoVentaId, usuarioId, receitas);
	}

	/**
	 * Carrega os dados de registro de calculo, conforme receitas
	 * @param ptovtaComissao
	 * @param puntoVentaId
	 * @param empresaId
	 * @param dataInicial 
	 * @param dataFinal
	 * @param receitas
	 * @return
	 * @throws BusinessException
	 */
	@SuppressWarnings("unchecked")
	private RegistroCalculo calcularRegistroCalculo(PtovtaComissao ptovtaComissao, Integer puntoVentaId, Integer empresaId, Date dataInicial, Date dataFinal, List<ComissaoReceita> receitas) throws BusinessException {
		try {
			RegistroCalculo rc = new RegistroCalculo();
			rc.setNombpuntoventa(ptovtaComissao.getPuntoventaId().getNombpuntoventa());
			rc.setNumPuntoVenta(ptovtaComissao.getPuntoventaId().getNumPuntoVenta());

			BigDecimal comissaoBPR = BigDecimal.ZERO;
			BigDecimal comissaoExcessoBagagem = BigDecimal.ZERO;
			BigDecimal comissaoSegOpcional = BigDecimal.ZERO;
			BigDecimal comissaoSeguro = BigDecimal.ZERO;
			BigDecimal comissaoEntregaPassagem = BigDecimal.ZERO;
			BigDecimal comissaoOutros = BigDecimal.ZERO;
			BigDecimal receitaTotal = BigDecimal.ZERO;
			BigDecimal comissaoTotal = BigDecimal.ZERO;

			for (ComissaoReceita cr : receitas) {
				receitaTotal = MoneyHelper.somar(receitaTotal, cr.getReceitaComissao());
				comissaoBPR = MoneyHelper.somar(comissaoBPR, cr.getComissaoBPRDiaria());
				comissaoEntregaPassagem = MoneyHelper.somar(comissaoEntregaPassagem, cr.getComissaoEntregaPassagemDiaria());
				comissaoExcessoBagagem = MoneyHelper.somar(comissaoExcessoBagagem, cr.getComissaoExcessoBagagemDiaria());
				comissaoSegOpcional = MoneyHelper.somar(comissaoSegOpcional, cr.getComissaoSegOpcionalDiaria());
				comissaoSeguro = MoneyHelper.somar(comissaoSeguro, cr.getComissaoSeguroObrigatorioDiaria());
				comissaoOutros = MoneyHelper.somar(comissaoOutros, cr.getComissaoOutrosDiaria());
				comissaoTotal = MoneyHelper.somar(comissaoTotal, cr.getTotalComissao());
			}

			rc.setLsReceitas(receitas);

			rc.setComissaoBPR(comissaoBPR);
			rc.setComissaoExcessoBagagem(comissaoExcessoBagagem);
			rc.setComissaoSegOpcional(comissaoSegOpcional);
			rc.setComissaoSeguro(comissaoSeguro);
			rc.setComissaoEntregaPassagem(comissaoEntregaPassagem);
			rc.setComissaoOutros(comissaoOutros);

			// Descontos (Fixos e Eventuais)
			Map<String, Object> respDescontos = calculoDescontos(puntoVentaId, empresaId, dataInicial, dataFinal, ptovtaComissao);
			rc.setDescontos((BigDecimal) respDescontos.get("VALOR_DESCONTOS"));
			rc.setLsDescontos((List<ComissaoDesconto>) respDescontos.get("LISTA_DESCONTOS"));

			/**
			 * Bonificação Metas - Meta = Eh o valor estipulado de receita dentro do periodo que a agencia deve alcançar. - Bonificação = Eh uma porcentagem paga encima da comissao, por alcançar a meta.
			 */
			BigDecimal comissaoBonificaoMetas = BigDecimal.ZERO;
			rc.setComissaoBonificaoMetas(comissaoBonificaoMetas);

			// Royaties
			BigDecimal royaties = BigDecimal.ZERO;
			if(ptovtaComissao.getRoyalties() != null) {
				royaties = MoneyHelper.multiplicar(receitaTotal, MoneyHelper.dividir(ptovtaComissao.getRoyalties(), CEM));
			}
			rc.setRoyaties(royaties);

			// ISS retido
			BigDecimal issRetido = BigDecimal.ZERO;
			if(ptovtaComissao.getIssretido() != null) {
				issRetido = MoneyHelper.multiplicar(comissaoTotal, MoneyHelper.dividir(ptovtaComissao.getIssretido(), CEM));
			}
			rc.setRetidoISS(issRetido);

			// comissão é pagar = comissão BPR + comissão Excesso Bagagem + comissão Seg. Opcional + Bonificação Metas + Internet(EntregaPassagem)
			BigDecimal comissaoPagar = BigDecimal.ZERO;
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoBPR);
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoExcessoBagagem);
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoSeguro);
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoSegOpcional);
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoEntregaPassagem);
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoOutros);
			comissaoPagar = MoneyHelper.somar(comissaoPagar,comissaoBonificaoMetas);

			// - Descontos (Fixos e Eventuais) - Royaties - ISS retido
			comissaoPagar = MoneyHelper.subtrair(comissaoPagar,rc.getDescontos());
			comissaoPagar = MoneyHelper.subtrair(comissaoPagar,royaties);
			comissaoPagar = MoneyHelper.subtrair(comissaoPagar,issRetido);
			rc.setComissaoPagar(comissaoPagar);
			
			return rc;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage(), e);
		}
	}

	private boolean validaAltaTemporada(List<EmpresaImposto> impostos, Integer mes, Integer estadoId) {
		if(impostos != null && mes != null && estadoId != null) {
		
			for (EmpresaImposto ei : impostos) {
				if(ei.getEstado() != null) {
					if (ei.getEstado().getEstadoId().equals(estadoId)) {
						switch (mes) {
						case Calendar.JANUARY:
							return ei.getIndJaneiro() == null ? false : ei.getIndJaneiro();
						case Calendar.FEBRUARY:
							return ei.getIndFevereiro() == null ? false : ei.getIndFevereiro();
						case Calendar.MARCH:
							return ei.getIndMarco() == null ? false : ei.getIndMarco();
						case Calendar.APRIL:
							return ei.getIndAbril() == null ? false : ei.getIndAbril();
						case Calendar.MAY:
							return ei.getIndMaio() == null ? false : ei.getIndMaio();
						case Calendar.JUNE:
							return ei.getIndJunho() == null ? false : ei.getIndJunho();
						case Calendar.JULY:
							return ei.getIndJulho() == null ? false : ei.getIndJulho();
						case Calendar.AUGUST:
							return ei.getIndAgosto() == null ? false : ei.getIndAgosto();
						case Calendar.SEPTEMBER:
							return ei.getIndSetembro() == null ? false : ei.getIndSetembro();
						case Calendar.OCTOBER:
							return ei.getIndOutubro() == null ? false : ei.getIndOutubro();
						case Calendar.NOVEMBER:
							return ei.getIndNovembro() == null ? false : ei.getIndNovembro();
						case Calendar.DECEMBER:
							return ei.getIndDezembro() == null ? false : ei.getIndDezembro();
						default:
							break;
						}
					}
				}
			}
		
		}

		return false;
	}

	private List<ComissaoReceita> calculaReceitaComissao(Integer empresaId, PtovtaComissao ptovtaComissao, List<BoletoComissao> receitasBoleto, List<EventosFinanceirosVO> eventosFinanceirosVOs, Date dataInicial, Date dataFinal) {
		
		Calendar cDataInicial = Calendar.getInstance();
		cDataInicial.setTime(dataInicial);
		Integer diaInicial = cDataInicial.get(Calendar.DAY_OF_MONTH);
		
		Calendar cDataFinal = Calendar.getInstance();
		cDataFinal.setTime(dataInicial);
		Integer diaFinal = cDataFinal.get(Calendar.DAY_OF_MONTH);
		
		Integer mes = cDataInicial.get(Calendar.MONTH);
		Integer ano = cDataInicial.get(Calendar.YEAR);

		List<EmpresaImposto> impostos = empresaImpostoService.buscarEmpresaImposto(empresaId);
		boolean isConsideraBilhetesDevolvidosEmOutraAgencia = ptovtaComissao.getIndbilhetesdevcanorigem() == null ? false : ptovtaComissao.getIndbilhetesdevcanorigem();
		boolean isPagaComissaoBilheteOrdemServico = ptovtaComissao.getIndPagaComissaoBilheteOS() != null ? ptovtaComissao.getIndPagaComissaoBilheteOS() : false;
		boolean isDevolucaoComissaoTransferenciaGeraCaja = ptovtaComissao.getEmpresaId().getIndComTransfGeraCaja();
		boolean isSeguroObrigatorioReceitaBPR = ptovtaComissao.getSeguroReceita() || ptovtaComissao.getSeguroDev();

		List<ComissaoReceita> receitas = new ArrayList<ComissaoReceita>();
		for (int dia = diaInicial; dia <= diaFinal; dia++) {
			Calendar cDataRegistro = Calendar.getInstance();
			cDataRegistro.set(Calendar.DAY_OF_MONTH, dia);
			cDataRegistro.set(Calendar.MONTH, mes); 
			cDataRegistro.set(Calendar.YEAR, ano);
			
			Date dataRegistro = DateUtil.normalizarToFecha(cDataRegistro.getTime());

			List<BoletoComissao> list = verificaCalculoComissaoProDia(receitasBoleto, dataRegistro);

			ComissaoReceita cr = new ComissaoReceita();
			cr.setData(dataRegistro);

			BigDecimal receitaComissao = BigDecimal.ZERO;

			BigDecimal receitaBPR = BigDecimal.ZERO;
			BigDecimal receitaGAP = BigDecimal.ZERO;
			BigDecimal internet = BigDecimal.ZERO;
			BigDecimal receitaSeguroObrigatorio = BigDecimal.ZERO;
			BigDecimal receitaExcessoBagagem = BigDecimal.ZERO;
			BigDecimal receitaSeguroOpcional = BigDecimal.ZERO;
			BigDecimal receitaSeguroOutros = BigDecimal.ZERO;

			BigDecimal cancelados = BigDecimal.ZERO;
			BigDecimal canceladosOrigem = BigDecimal.ZERO;
			BigDecimal devolvidos = BigDecimal.ZERO;
			BigDecimal devolvidosOrigem = BigDecimal.ZERO;
			BigDecimal canceladosGAP = BigDecimal.ZERO;
			BigDecimal canceladosGAPOrigem = BigDecimal.ZERO;
			BigDecimal devolvidosGAP = BigDecimal.ZERO;
			BigDecimal devolvidosGAPOrigem = BigDecimal.ZERO;

			BigDecimal gapImpressa = BigDecimal.ZERO;
			int contImpressa = 0;

			BigDecimal comissaoBPR = BigDecimal.ZERO;
			BigDecimal comissaoExcessoBagagem = BigDecimal.ZERO;
			BigDecimal comissaoSegOpcional = BigDecimal.ZERO;
			BigDecimal comissaoEntregaPassagem = BigDecimal.ZERO;
			BigDecimal comissaoOutros = BigDecimal.ZERO;
			BigDecimal comissaoSeguroObrigatorio = BigDecimal.ZERO;

			// Receita Total -- bruta/liquida - abatimento do valor do icms
			boolean isReceitaLiquida = false;
			Receita receita = Receita.getByValor(ptovtaComissao.getReceita());
			if (receita.equals(Receita.RECEITALIQUIDA)) {
				isReceitaLiquida = true;
			}

			/* Calculando comissão para os boletos */
			for (BoletoComissao rcc : list) {
				
				/* 
				 * Mantis #12391
				 * Verifica se a agencia paga comissão para bilhete de ordem de servico,
				 * caso não faça pagamento, o bilhete é ignorado */
				if(!isPagaComissaoBilheteOrdemServico && isBilheteOrdemServico(rcc)) {
					continue;
				}
				
				boolean isAltaTemporada = validaAltaTemporada(impostos, mes, rcc.getEstadoId());

				IndStatusBoleto statusBoleto = IndStatusBoleto.valueOf(rcc.getIndstatusboleto());
				boolean isSaidaCaixa = rcc.getMotivoCancelacionId() != null;
				boolean isEntregaPassagem = statusBoleto.equals(IndStatusBoleto.E) && (rcc.getMotivoCancelacionId() == null);
				
				/*
				 * Exclui os bilhetes que não foram entregues na agencia da comissão que está sendo calculada
				 */
				if(isEntregaPassagem && !ptovtaComissao.getPuntoventaId().getPuntoventaId().equals(rcc.getPuntoVentaId())) {
					continue;
				}
				
				if(rcc.isMotivocancelacionQuitacaoOcd() || rcc.isDiferencaTrocaGeracaoOcd()) {
					continue;
				}
				
				if(rcc.isMotivocancelacionTransferido() && (rcc.getIndreimpresion() || !isDevolucaoComissaoTransferenciaGeraCaja)) {
					continue;
				}
				
				ComissaoLogVO comissaoLog = new ComissaoLogVO();
				comissaoLog.setFeccorte(dataRegistro);
				comissaoLog.setCajaId(rcc.getCajaId());
				comissaoLog.setEmpresaId(empresaId);
				comissaoLog.setPuntoventaId(rcc.getPuntoVentaId());
				comissaoLog.setTurnoId(rcc.getTurnoId());
				comissaoLog.setUsuarioId(rcc.getUsuarioId());
				comissaoLog.setOrigem("ADM");
				
				StringBuilder sTextoLog = new StringBuilder();
						sTextoLog.append("[CAJA_ID: ")
								 .append(rcc.getCajaId())
								 .append("] ")
								 .append("[BILHETE: ")
								 .append(rcc.getNumFolioSistema())
								 .append("] ")
								 .append("[INDSTATUSBOLETO: ")
								 .append(rcc.getIndstatusboleto())
								 .append("] ")
								 .append("[MOTIVO_CANCELAMENTO: ")
								 .append(rcc.getMotivoCancelacionId() != null ? rcc.getMotivoCancelacionId() : "")
								 .append("] ")
								 .append("[TIPO_VENDA: ")
								 .append(rcc.getTipoVenta())
								 .append("] ");

				BigDecimal receitaItem = BigDecimal.ZERO;
				BigDecimal receitaDevItem = BigDecimal.ZERO;
				BigDecimal receitaSeguroObrigatorioItem = BigDecimal.ZERO;
				BigDecimal receitaSeguroObrigatorioDevItem = BigDecimal.ZERO;

				if (!isSaidaCaixa){
					// Totais
					if (BooleanUtils.toBoolean(ptovtaComissao.getTarifaReceita())) {
						receitaItem = MoneyHelper.somar(receitaItem, rcc.getValorpagado());
					}
	
					if (BooleanUtils.toBoolean(ptovtaComissao.getTaxaReceita())) {
						receitaItem = MoneyHelper.somar(receitaItem, rcc.getEmbarque());
					}
	
					if (BooleanUtils.toBoolean(ptovtaComissao.getPedagioReceita())) {
						receitaItem = MoneyHelper.somar(receitaItem, rcc.getPedagio());
					}
					
					if(isSeguroObrigatorioReceitaBPR) {
						if (BooleanUtils.toBoolean(ptovtaComissao.getSeguroReceita())) {
							receitaItem = MoneyHelper.somar(receitaItem, rcc.getSeguro());
						}
					} else {
						receitaSeguroObrigatorioItem = MoneyHelper.somar(receitaSeguroObrigatorioItem, rcc.getSeguro());
					}
					
				}

				if (isSaidaCaixa){
					// Totais de devolução / Cancelamento
					if (BooleanUtils.toBoolean(ptovtaComissao.getTarifaDev())) {
						receitaDevItem = MoneyHelper.somar(receitaDevItem, rcc.getValorpagado());
					}
	
					if (BooleanUtils.toBoolean(ptovtaComissao.getTaxaDev())) {
						receitaDevItem = MoneyHelper.somar(receitaDevItem, rcc.getEmbarque());
					}

					if (BooleanUtils.toBoolean(ptovtaComissao.getPedagioDev())) {
						receitaDevItem = MoneyHelper.somar(receitaDevItem, rcc.getPedagio());
					}
					
					if(isSeguroObrigatorioReceitaBPR) {
						if (BooleanUtils.toBoolean(ptovtaComissao.getSeguroDev())) {
							receitaDevItem = MoneyHelper.somar(receitaDevItem, rcc.getSeguro());
						}
					} else {
						receitaSeguroObrigatorioDevItem = MoneyHelper.somar(receitaSeguroObrigatorioDevItem, rcc.getSeguro());
					}
					
				}
				
				// Calculo de ICMS sobre o valor do bilhete
				if (isReceitaLiquida) {
					BigDecimal icms = MoneyHelper.multiplicar(receitaItem, MoneyHelper.dividir(rcc.getIcmsBase() != null ? rcc.getIcmsBase() : BigDecimal.ZERO, CEM));
					receitaItem = MoneyHelper.subtrair(receitaItem, icms);

					BigDecimal icmsDev = MoneyHelper.multiplicar(receitaDevItem, MoneyHelper.dividir(rcc.getIcmsBase() != null ? rcc.getIcmsBase() : BigDecimal.ZERO, CEM));
					receitaDevItem = MoneyHelper.subtrair(receitaDevItem,icmsDev);
					
					icms = MoneyHelper.multiplicar(receitaSeguroObrigatorioItem, MoneyHelper.dividir(rcc.getIcmsBase() != null ? rcc.getIcmsBase() : BigDecimal.ZERO, CEM));
					receitaSeguroObrigatorioItem = MoneyHelper.subtrair(receitaSeguroObrigatorioItem, icms);
					
					icmsDev = MoneyHelper.multiplicar(receitaSeguroObrigatorioDevItem, MoneyHelper.dividir(rcc.getIcmsBase() != null ? rcc.getIcmsBase() : BigDecimal.ZERO, CEM));
					receitaSeguroObrigatorioDevItem = MoneyHelper.subtrair(receitaSeguroObrigatorioDevItem,icmsDev);

				}

				BigDecimal bpr = BigDecimal.ZERO;
				BigDecimal tmpComissaoSeguroObrigatorio = BigDecimal.ZERO;
				// Boletos impressos no punto venta
				if (isEntregaPassagem) {
					contImpressa++;
					gapImpressa = MoneyHelper.somar(gapImpressa, receitaItem, receitaSeguroObrigatorioItem);
					
					BigDecimal receitaTotalPassagem = MoneyHelper.somar(receitaItem, receitaSeguroObrigatorioItem);

					BigDecimal entregaPassagem = calculoEntregaPassagem(isAltaTemporada, ptovtaComissao, receitaTotalPassagem, BigDecimal.ZERO, 1);
					comissaoEntregaPassagem = MoneyHelper.somar(comissaoEntregaPassagem, entregaPassagem, 4);
					
					sTextoLog.append("[RECEITA_IMPRESSAO_IMP_POS: ")
					 		 .append(receitaTotalPassagem)
					 		 .append("] ")
					 		 .append("[COMISSAO_IMPRESSAO_IMP_POS: ")
					 		 .append(comissaoEntregaPassagem)
					 		 .append("] ");
					
				} else {

					// Receita GAP
					if (rcc.getTipoVenta().equals(Constantes.TPV_BOLETO_REMOTO.intValue()) || rcc.getTipoVenta().equals(Constantes.TPV_CALL_CENTER.intValue())) {
						receitaGAP = MoneyHelper.somar(receitaGAP, receitaItem);
						receitaGAP = MoneyHelper.somar(receitaGAP, receitaSeguroObrigatorioItem);

						bpr = calculoComisssaoBPR(isAltaTemporada, ptovtaComissao, BigDecimal.ZERO, receitaItem, rcc.isBilheteGap(), comissaoLog);
						
					}
					// Internet
					else if (rcc.getTipoVenta().equals(Constantes.TPV_POR_INTERNET.intValue())) {
						internet = MoneyHelper.somar(internet, receitaItem);
						internet = MoneyHelper.somar(internet, receitaSeguroObrigatorioItem);

						bpr = calculoComisssaoBPR(isAltaTemporada, ptovtaComissao, BigDecimal.ZERO, receitaItem, rcc.isBilheteGap(), comissaoLog);
						
					}

					// Receita BPR
					else {
						receitaBPR = MoneyHelper.somar(receitaBPR, receitaItem);
						receitaSeguroObrigatorio = MoneyHelper.somar(receitaSeguroObrigatorio, receitaSeguroObrigatorioItem);

						bpr = calculoComisssaoBPR(isAltaTemporada, ptovtaComissao, receitaItem, BigDecimal.ZERO, rcc.isBilheteGap(), comissaoLog);
						
					}
					
					tmpComissaoSeguroObrigatorio = calculoSeguroObrigatorio(isAltaTemporada, ptovtaComissao, receitaSeguroObrigatorioItem);
					comissaoSeguroObrigatorio = MoneyHelper.somar(comissaoSeguroObrigatorio, tmpComissaoSeguroObrigatorio, 4);
					
					comissaoBPR = MoneyHelper.somar(comissaoBPR, bpr, 4);
					
					if(!isSaidaCaixa) {
						BigDecimal valorBase = MoneyHelper.somar(receitaItem, receitaSeguroObrigatorioItem);
						BigDecimal valorComissao = MoneyHelper.somar(bpr, tmpComissaoSeguroObrigatorio);
						
						comissaoLog.setValorBase(valorBase);
						comissaoLog.setValorComissao(valorComissao);						
						
						sTextoLog.append("[RECEITA_ITEM: ")
				 		 		 .append(receitaItem)
				 		 		 .append("] ")						
				 		 		 .append("[COMISSAO_BPR: ")
		 		 		 		 .append(bpr)
		 		 		 		 .append("] ")						
		 		 		 		 .append("[COMISSAO_BPR_ATUAL: ")
				 		 		 .append(comissaoBPR)
				 		 		 .append("] ")
				 		 		 .append("[RECEITA_SEGURO_OBRIGATORIO: ")
				 		 		 .append(receitaSeguroObrigatorioItem)
				 		 		 .append("] ")
				 		 		 .append("[COMISSAO_SEGURO_OBRIGATORIO: ")
				 		 		 .append(tmpComissaoSeguroObrigatorio)
				 		 		 .append("] ")
				 		 		 .append("[COMISSAO_SEGURO_OBRIGATORIO_ATUAL: ")
				 		 		 .append(comissaoSeguroObrigatorio)
				 		 		 .append("] ");
					}
				}

				if (isSaidaCaixa) {
					receitaSeguroObrigatorio = MoneyHelper.somar( receitaSeguroObrigatorio , receitaSeguroObrigatorioDevItem.negate(), 4 );
					// devolução Receita
					if (isBilheteDevolucao(rcc, isDevolucaoComissaoTransferenciaGeraCaja)) {

						// devolução Receita GAP
						if (rcc.getTipoVenta().equals(Constantes.TPV_BOLETO_REMOTO.intValue()) || rcc.getTipoVenta().equals(Constantes.TPV_CALL_CENTER.intValue()) || rcc.getTipoVenta().equals(Constantes.TPV_POR_INTERNET.intValue())) {

							// Impresso Venta de otro punto venta
							if (!rcc.getPtoVtaOrigem()) {
								devolvidosGAPOrigem = MoneyHelper.somar(devolvidosGAPOrigem, receitaDevItem);
								//devolvidosGAPOrigem = MoneyHelper.somar(devolvidosGAPOrigem, receitaSeguroObrigatorioDevItem);
							}
							
							/* 
							 * Adiciona o valor nos devolvidos caso o bilhete seja do proprio ponto de venda,
							 * ou caso o parametro de considerar cancelamento/devolução no ponto de venda onde
							 * foi feita a operação esteja desmarcado
							 * Mantis #11015
							 */
							if(rcc.getPtoVtaOrigem() || !isConsideraBilhetesDevolvidosEmOutraAgencia) {
								devolvidosGAP = MoneyHelper.somar(devolvidosGAP, receitaDevItem);
								//devolvidosGAP = MoneyHelper.somar(devolvidosGAP, receitaSeguroObrigatorioDevItem);
							}

						} else {
							// Impresso Venta de otro punto venta
							if (!rcc.getPtoVtaOrigem()) {
								devolvidosOrigem = MoneyHelper.somar(devolvidosOrigem, receitaDevItem);
								//devolvidosOrigem = MoneyHelper.somar(devolvidosOrigem, receitaSeguroObrigatorioDevItem);
							}
							
							/* 
							 * Adiciona o valor nos devolvidos caso o bilhete seja do proprio ponto de venda,
							 * ou caso o parametro de considerar cancelamento/devolução no ponto de venda onde
							 * foi feita a operação esteja desmarcado
							 * Mantis #11015
							 */
							if(rcc.getPtoVtaOrigem() || !isConsideraBilhetesDevolvidosEmOutraAgencia) {
								devolvidos = MoneyHelper.somar(devolvidos, receitaDevItem);
								//devolvidos = MoneyHelper.somar(devolvidos, receitaSeguroObrigatorioDevItem);
							}
						}

					}

					// Cancelamento Receita
					else {
						// Cancelamento Receita GAP
						if (rcc.getTipoVenta().equals(Constantes.TPV_BOLETO_REMOTO.intValue()) || rcc.getTipoVenta().equals(Constantes.TPV_CALL_CENTER.intValue()) || rcc.getTipoVenta().equals(Constantes.TPV_POR_INTERNET.intValue())) {
							if (!rcc.getPtoVtaOrigem()) {
								canceladosGAPOrigem = MoneyHelper.somar(canceladosGAPOrigem, receitaDevItem);
								//canceladosGAPOrigem = MoneyHelper.somar(canceladosGAPOrigem, receitaSeguroObrigatorioDevItem);
							}
							
							/* 
							 * Adiciona o valor nos devolvidos caso o bilhete seja do proprio ponto de venda,
							 * ou caso o parametro de considerar cancelamento/devolução no ponto de venda onde
							 * foi feita a operação esteja desmarcado
							 * Mantis #11015
							 */
							if(rcc.getPtoVtaOrigem() || !isConsideraBilhetesDevolvidosEmOutraAgencia) {
								canceladosGAP = MoneyHelper.somar(canceladosGAP, receitaDevItem);
								//canceladosGAP = MoneyHelper.somar(canceladosGAP, receitaSeguroObrigatorioDevItem);
							}
						} else {
							if (!rcc.getPtoVtaOrigem()) {
								canceladosOrigem = MoneyHelper.somar(canceladosOrigem, receitaDevItem);
								//canceladosOrigem = MoneyHelper.somar(canceladosOrigem, receitaSeguroObrigatorioDevItem);
							}
							
							/* 
							 * Adiciona o valor nos devolvidos caso o bilhete seja do proprio ponto de venda,
							 * ou caso o parametro de considerar cancelamento/devolução no ponto de venda onde
							 * foi feita a operação esteja desmarcado
							 * Mantis #11015
							 */
							if(rcc.getPtoVtaOrigem() || !isConsideraBilhetesDevolvidosEmOutraAgencia) {
								cancelados = MoneyHelper.somar(cancelados, receitaDevItem);
								//cancelados = MoneyHelper.somar(cancelados, receitaSeguroObrigatorioDevItem);
							}
						}
					}
					
					/* 
					 * Calcula a comissão caso o bilhete seja do proprio ponto de venda,
					 * ou caso o parametro de considerar cancelamento/devolução no ponto de venda onde
					 * foi feita a operação esteja desmarcado
					 * Mantis #11015
					 */
					if(rcc.getPtoVtaOrigem() || !isConsideraBilhetesDevolvidosEmOutraAgencia) {
						bpr = calculoComisssaoBPR(isAltaTemporada, ptovtaComissao, receitaDevItem, BigDecimal.ZERO, rcc.isBilheteGap(), comissaoLog);
						
						tmpComissaoSeguroObrigatorio = calculoSeguroObrigatorio(isAltaTemporada, ptovtaComissao, receitaSeguroObrigatorioDevItem);
						comissaoSeguroObrigatorio = MoneyHelper.somar(comissaoSeguroObrigatorio, tmpComissaoSeguroObrigatorio.negate(), 4);
						
						//bpr = MoneyHelper.somar(bpr, tmpComissaoSeguroObrigatorio, 4);
						
						comissaoBPR = MoneyHelper.somar(comissaoBPR, bpr.negate(), 4);
						
						BigDecimal valorBase = MoneyHelper.somar(receitaDevItem.negate(), receitaSeguroObrigatorioDevItem.negate());
						BigDecimal valorComissao = MoneyHelper.somar(bpr.negate(), tmpComissaoSeguroObrigatorio.negate());
						
						comissaoLog.setValorBase(valorBase);
						comissaoLog.setValorComissao(valorComissao);
						
						sTextoLog.append("[RECEITA_DEV_ITEM: ")
				 		 		 .append(receitaDevItem.negate())
				 		 		 .append("] ")
				 		 		 .append("[COMISSAO_BPR_DEV: ")
				 		 		 .append(bpr.negate())
				 		 		 .append("] ")						
				 		 		 .append("[COMISSAO_BPR_ATUAL: ")
				 		 		 .append(comissaoBPR)
				 		 		 .append("] ")
				 		 		 .append("[RECEITA_SEGURO_OBRIGATORIO_DEV: ")
				 		 		 .append(receitaSeguroObrigatorioDevItem.negate())
				 		 		 .append("] ")
				 		 		 .append("[COMISSAO_SEGURO_OBRIGATORIO_DEV: ")
				 		 		 .append(tmpComissaoSeguroObrigatorio.negate())
				 		 		 .append("] ")
				 		 		 .append("[COMISSAO_SEGURO_OBRIGATORIO_ATUAL: ")
				 		 		 .append(comissaoSeguroObrigatorio)
				 		 		 .append("] ");
					}
				}
				
				comissaoLog.setTexto(sTextoLog.toString());
				cr.getLsComissaoLog().add(comissaoLog);
				
				/*
				log.info("---------");
				log.info("CajaId=" + rcc.getCajaId() + ", numFolioSistema=" + rcc.getNumFolioSistema() + ", nombpasajero=" + rcc.getNombpasajero() + ", indstatusboleto=" + rcc.getIndstatusboleto() + ", motivocancelacionId=" + rcc.getMotivoCancelacionId() + ", PuntoventaId=" + rcc.getPuntoVentaId() + ", PtovtaventaId=" + rcc.getPtovtaventaId());
				log.info("Total Bilhete: " + rcc.getTotal());
				log.info("PtoVtaOrigem: " + rcc.getPtoVtaOrigem());
				log.info("Status: " + rcc.getIndstatusboleto());
				log.info("receitaItem: " + receitaItem);
				log.info("receitaDevItem: " + receitaDevItem);
				log.info("receitaSeguroObrigatorioItem: " + receitaSeguroObrigatorioItem);
				log.info("receitaSeguroObrigatorioDevItem: " + receitaSeguroObrigatorioDevItem);
				log.info("comissaoBPRItem: " + bpr);
				log.info("receitaGAP: " + receitaGAP);
				log.info("receitaBPR: " + receitaBPR);
				log.info("ComissaoBPR: " + comissaoBPR);
				log.info("comissaoSeguroObrigatorio: " + comissaoSeguroObrigatorio);
				log.info("cancelados: " + cancelados);
				log.info("canceladosOrigem: " + canceladosOrigem);
				log.info("devolvidos: " + devolvidos);
				log.info("devolvidosOrigem: " + devolvidosOrigem);
				log.info("canceladosGAP: " + canceladosGAP);
				log.info("canceladosGAPOrigem: " + canceladosGAPOrigem);
				log.info("devolvidosGAP: " + devolvidosGAP);
				log.info("devolvidosGAPOrigem: " + devolvidosGAPOrigem);
				*/
			}
			
			/* Calculando comissão para os eventos extras */
			List<EventosFinanceirosVO> listEventosFinanceiros = verificaEventoFinanceiroProDia(eventosFinanceirosVOs, dataRegistro);
			for (EventosFinanceirosVO eventosFinanceiros : listEventosFinanceiros) {
				ComissaoLogVO comissaoLog = new ComissaoLogVO();
				comissaoLog.setFeccorte(dataRegistro);
				comissaoLog.setCajadiversosId(eventosFinanceiros.getCajaDiversosId());
				comissaoLog.setEmpresaId(empresaId);
				comissaoLog.setPuntoventaId(ptovtaComissao.getPuntoventaId().getPuntoventaId());
				comissaoLog.setTurnoId(eventosFinanceiros.getTurnoId());
				comissaoLog.setUsuarioId(eventosFinanceiros.getUsuarioId());
				comissaoLog.setOrigem("ADM");				
				
				boolean isAltaTemporada = validaAltaTemporada(impostos, mes, eventosFinanceiros.getEstadoId());
				
				if(TipoEventoExtra.EXCESSO_BAGAGEM.toString().equals(eventosFinanceiros.getCvetipoevento())) {
					receitaExcessoBagagem = MoneyHelper.somar(receitaExcessoBagagem, eventosFinanceiros.getImpingreso());
					BigDecimal excessoBagagem = calculoExcessoBagagem(isAltaTemporada, ptovtaComissao, eventosFinanceiros.getImpingreso(), comissaoLog);
					comissaoExcessoBagagem = MoneyHelper.somar(comissaoExcessoBagagem, excessoBagagem, 4);
					
					adicionarTextoComissaoLog(comissaoLog, TipoEventoExtra.EXCESSO_BAGAGEM.toString(), receitaExcessoBagagem, excessoBagagem);
				} else if(TipoEventoExtra.SEGURO_OPCIONAL.toString().equals(eventosFinanceiros.getCvetipoevento())) {
					receitaSeguroOpcional = MoneyHelper.somar(receitaSeguroOpcional, eventosFinanceiros.getImpingreso());
					BigDecimal segOpcional = calculoSeguroOpcional(isAltaTemporada, ptovtaComissao, eventosFinanceiros.getImpingreso(), comissaoLog);
					comissaoSegOpcional = MoneyHelper.somar(comissaoSegOpcional, segOpcional, 4);
					
					adicionarTextoComissaoLog(comissaoLog, TipoEventoExtra.SEGURO_OPCIONAL.toString(), receitaSeguroOpcional, segOpcional);
				} else {
					receitaSeguroOutros = MoneyHelper.somar(receitaSeguroOutros, eventosFinanceiros.getImpingreso());
					BigDecimal outros = calculoOutros(isAltaTemporada, ptovtaComissao, eventosFinanceiros.getImpingreso(), comissaoLog);
					comissaoOutros = MoneyHelper.somar(comissaoOutros, outros, 4);
					
					adicionarTextoComissaoLog(comissaoLog, "OUTROS", receitaSeguroOutros, outros);
				}
				
				cr.getLsComissaoLog().add(comissaoLog);
			}

			cr.setCancelados(cancelados);
			cr.setCanceladosGAP(canceladosGAP);
			cr.setDevolvidos(devolvidos);
			cr.setDevolvidosGAP(devolvidosGAP);
			cr.setDevolucoesOrigem(devolvidosOrigem);
			cr.setDevolucoesOrigemGAP(devolvidosGAPOrigem);

			cr.setReceitaBPR(receitaBPR);
			cr.setReceitaSeguro(receitaSeguroObrigatorio);
			cr.setReceitaExcessoBagagem(receitaExcessoBagagem);
			cr.setReceitaGAP(receitaGAP);
			cr.setReceitaSeguroOpcional(receitaSeguroOpcional);
			cr.setReceitaSeguroOutros(receitaSeguroOutros);
			cr.setInternet(internet);

			cr.setGapImpressa(gapImpressa);
			cr.setContImpressa(contImpressa);

			// Receita comissão = Receita BPR + Receita GAP + Internet - Cancelados - Cancelados GAP - Devoluções - Devoluções GAP
			receitaComissao = MoneyHelper.somar(receitaComissao,receitaBPR);
			receitaComissao = MoneyHelper.somar(receitaComissao,receitaGAP);
			receitaComissao = MoneyHelper.somar(receitaComissao,internet);

			receitaComissao = MoneyHelper.subtrair(receitaComissao,cancelados);
			receitaComissao = MoneyHelper.subtrair(receitaComissao,devolvidos);
			receitaComissao = MoneyHelper.subtrair(receitaComissao,devolvidosGAP);
			receitaComissao = MoneyHelper.subtrair(receitaComissao,canceladosGAP);
			
			cr.setReceitaComissao(receitaComissao);

			cr.setComissaoBPRDiaria(comissaoBPR);
			cr.setComissaoEntregaPassagemDiaria(comissaoEntregaPassagem);
			cr.setComissaoExcessoBagagemDiaria(comissaoExcessoBagagem);
			cr.setComissaoSegOpcionalDiaria(comissaoSegOpcional);
			cr.setComissaoOutrosDiaria(comissaoOutros);
			cr.setComissaoSeguroObrigatorioDiaria(comissaoSeguroObrigatorio);

			receitas.add(cr);
		}

		return receitas;

	}

	private void adicionarTextoComissaoLog(ComissaoLogVO comissaoLog, String campo, BigDecimal receitaComissao, BigDecimal comissao) {
		comissaoLog.setValorBase(receitaComissao);
		comissaoLog.setValorComissao(comissao);
		
		StringBuilder sTexto = new StringBuilder();
		sTexto.append("[CAJADIVERSOS_ID: ")
		  	  .append(comissaoLog.getCajadiversosId())
		  	  .append(": ")		
		  	  .append("[RECEITA_")
			  .append(campo)
			  .append(": ")
			  .append(receitaComissao)
			  .append("] [COMISSAO_")
			  .append(campo)
			  .append(": ")
			  .append(comissao)
			  .append("]");
		
		comissaoLog.setTexto(sTexto.toString());
	}

	private boolean isBilheteDevolucao(BoletoComissao rcc, boolean isDevolucaoComissaoTransferenciaGeraCaja) {
		return rcc.isMotivocancelacionDevolvido() ||
			   rcc.isMotivocancelacionGeracaoOcd() ||
			   rcc.isMotivocancelacionTrocado() ||
			   rcc.isMotivocancelacionQuitacaoOcd() ||
			   (rcc.isMotivocancelacionTransferido() && !rcc.getIndreimpresion() && isDevolucaoComissaoTransferenciaGeraCaja);
	}

	/**
	 * Verifica se o bilhete possui forma de pagamento Orden de serviço
	 * Mantis #12391
	 * @param rcc
	 * @return
	 */
	private boolean isBilheteOrdemServico(BoletoComissao rcc) {
		for (FormapagoVO formapago : rcc.getFormapagos()) {
			if(formapago.getFormapagoId() == Constantes.FORMA_PAGO_ORDEN_SERVICIO.intValue()) {
				return true;
			}
		}
		return false;
	}

	private List<EventosFinanceirosVO> verificaEventoFinanceiroProDia(List<EventosFinanceirosVO> eventosFinanceirosVOs, Date dataRegistro) {
		List<EventosFinanceirosVO> aux = new ArrayList<EventosFinanceirosVO>();
		if(eventosFinanceirosVOs != null) {
			for (EventosFinanceirosVO rcc : eventosFinanceirosVOs) {
				if(rcc.getFeccorte() != null) {
					if (DateUtil.compareOnlyDate(rcc.getFeccorte(), dataRegistro) == 0) {
						aux.add(rcc);
					}
				}
			}
		}
		return aux;
	}

	private List<BoletoComissao> verificaCalculoComissaoProDia(List<BoletoComissao> list, Date dataRegistro) {
		List<BoletoComissao> aux = new ArrayList<BoletoComissao>();
		for (BoletoComissao rcc : list) {
			if (DateUtil.compareOnlyDate(rcc.getFeccorte(), dataRegistro) == 0) {
				aux.add(rcc);
			}
		}
		return aux;
	}

	@Override
	public List<RegistroCalculo> relatorioCalculoComissao(Integer empresaId, Date competencia, Date dataInicial, Date dataFinal, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo) throws ComissaoException, BusinessException {
		List<RegistroCalculo> registrosCalculo = new ArrayList<RegistroCalculo>();
		List<PuntoVenta> puntoventas = comissaoDAO.buscaPuntoVentasEmpresaComComissaoParametrizada(empresaId);
		Empresa empresa = empresaService.obtenerID(empresaId);
		boolean indExibeComissaoZeradaAgencia = empresa.getIndExibeComissaoZeradaAgencia() != null ? empresa.getIndExibeComissaoZeradaAgencia() : false;
		for (PuntoVenta puntoVenta : puntoventas) {
			RegistroCalculo registroCalculo = null;
			if(competencia != null) {
				registroCalculo = relatorioCalculoComissao(puntoVenta.getPuntoventaId(), empresaId, competencia, usuarioId, isRetencaoDiaria, isRefazerCalculo);
			} else if(dataInicial != null && dataFinal != null) {
				registroCalculo = relatorioCalculoComissao(puntoVenta.getPuntoventaId(), empresaId, usuarioId, isRetencaoDiaria, isRefazerCalculo, dataInicial, dataFinal);
			}
			
			if(registroCalculo == null) {
				continue;
			}
			
			/*
			 * Caso parametro de não exibir as agencias com comissão zerada esteja ativado
			 * o registro de calculo não deverá  ser adicionado
			 * Mantis #12260
			 */
			totalizarRegistroCalculo(registroCalculo, indExibeComissaoZeradaAgencia);
			if(registroCalculo.getLsReceitas() != null && !registroCalculo.getLsReceitas().isEmpty()) {
				registrosCalculo.add(registroCalculo);
			}
		}
		ordernarResultado(registrosCalculo);
		return registrosCalculo;
	}

	private void ordernarResultado(List<RegistroCalculo> registrosCalculo) {
		Collections.sort(registrosCalculo, new Comparator<RegistroCalculo>() {
			@Override
			public int compare(RegistroCalculo o1, RegistroCalculo o2) {
				return o1.getNombpuntoventa().compareToIgnoreCase(o2.getNombpuntoventa());
			}
		});
	}

	private void totalizarRegistroCalculo(RegistroCalculo registroCalculo, boolean indExibeComissaoZeradaAgencia) {
		ComissaoReceita comissaoReceitaTotal = new ComissaoReceita();
		for (ComissaoReceita comissaoReceita : registroCalculo.getLsReceitas()) {
			comissaoReceitaTotal.setNumPuntoVenta(registroCalculo.getNumPuntoVenta());
			comissaoReceitaTotal.setNombpuntoventa(registroCalculo.getNombpuntoventa());
			comissaoReceitaTotal.setReceitaComissao(comissaoReceitaTotal.getReceitaComissao().add(comissaoReceita.getReceitaComissao()));
			comissaoReceitaTotal.setReceitaBPR(comissaoReceitaTotal.getReceitaBPR().add(comissaoReceita.getReceitaBPR()));
			comissaoReceitaTotal.setReceitaGAP(comissaoReceitaTotal.getReceitaGAP().add(comissaoReceita.getReceitaGAP()));
			comissaoReceitaTotal.setGapImpressa(comissaoReceitaTotal.getGapImpressa().add(comissaoReceita.getGapImpressa()));
			comissaoReceitaTotal.setInternet(comissaoReceitaTotal.getInternet().add(comissaoReceita.getInternet()));
			comissaoReceitaTotal.setCancelados(comissaoReceitaTotal.getCancelados().add(comissaoReceita.getCancelados()));
			comissaoReceitaTotal.setCanceladosGAP(comissaoReceitaTotal.getCanceladosGAP().add(comissaoReceita.getCanceladosGAP()));
			comissaoReceitaTotal.setDevolvidos(comissaoReceitaTotal.getDevolvidos().add(comissaoReceita.getDevolvidos()));
			comissaoReceitaTotal.setDevolvidosGAP(comissaoReceitaTotal.getDevolvidosGAP().add(comissaoReceita.getDevolvidosGAP()));
			comissaoReceitaTotal.setDevolucoesOrigem(comissaoReceitaTotal.getDevolucoesOrigem().add(comissaoReceita.getDevolucoesOrigem()));
			comissaoReceitaTotal.setDevolucoesOrigemGAP(comissaoReceitaTotal.getDevolucoesOrigemGAP().add(comissaoReceita.getDevolucoesOrigemGAP()));
			comissaoReceitaTotal.setReceitaExcessoBagagem(comissaoReceitaTotal.getReceitaExcessoBagagem().add(comissaoReceita.getReceitaExcessoBagagem()));
			comissaoReceitaTotal.setReceitaSeguroOpcional(comissaoReceitaTotal.getReceitaSeguroOpcional().add(comissaoReceita.getReceitaSeguroOpcional()));
			comissaoReceitaTotal.setReceitaSeguroOutros(comissaoReceitaTotal.getReceitaSeguroOutros().add(comissaoReceita.getReceitaSeguroOutros()));
			comissaoReceitaTotal.setContImpressa(comissaoReceitaTotal.getContImpressa() + comissaoReceita.getContImpressa());
			comissaoReceitaTotal.setComissaoBPRDiaria(comissaoReceitaTotal.getComissaoBPRDiaria().add(comissaoReceita.getComissaoBPRDiaria()));
			comissaoReceitaTotal.setComissaoExcessoBagagemDiaria(comissaoReceitaTotal.getComissaoExcessoBagagemDiaria().add(comissaoReceita.getComissaoExcessoBagagemDiaria()));
			comissaoReceitaTotal.setComissaoSegOpcionalDiaria(comissaoReceitaTotal.getComissaoSegOpcionalDiaria().add(comissaoReceita.getComissaoSegOpcionalDiaria()));
			comissaoReceitaTotal.setComissaoEntregaPassagemDiaria(comissaoReceitaTotal.getComissaoEntregaPassagemDiaria().add(comissaoReceita.getComissaoEntregaPassagemDiaria()));
			comissaoReceitaTotal.setComissaoOutrosDiaria(comissaoReceitaTotal.getComissaoOutrosDiaria().add(comissaoReceita.getComissaoOutrosDiaria()));
		}
		registroCalculo.getLsReceitas().clear();
		if(indExibeComissaoZeradaAgencia ||
		  (MoneyHelper.isMaior(comissaoReceitaTotal.getTotal(), BigDecimal.ZERO) || MoneyHelper.isMaior(comissaoReceitaTotal.getTotalComissao(), BigDecimal.ZERO))) {
			registroCalculo.getLsReceitas().add(comissaoReceitaTotal);
		}
	}

	@Override
	public void registrarCalculoComissao(Empresa empresa, Date periodo, boolean ignorarComissaoGerada, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo) throws ComissaoException {
		List<PuntoVenta> puntoventas = comissaoDAO.buscaPuntoVentasEmpresaComComissaoParametrizada(empresa.getEmpresaId());
		for (PuntoVenta puntoVenta : puntoventas) {
			registrarCalculoComissao(puntoVenta, empresa, periodo, ignorarComissaoGerada, usuarioId, isRetencaoDiaria, isRefazerCalculo);
		}
	}

	@Override
	public void cancelarCalculoComissao(Integer empresaId, Date periodo) throws ComissaoException, BusinessException {
		try {
			List<PuntoVenta> puntoventas = comissaoDAO.buscaPuntoVentasEmpresaComComissaoParametrizada(empresaId);
			for (PuntoVenta puntoVenta : puntoventas) {
				try {
					cancelarCalculoComissao(puntoVenta.getPuntoventaId(), empresaId, periodo);
				} catch (ComissaoException e) {
					/* Ignora a comissa quando o cancelamento é feito para todas as agencias */
				} catch (Exception e) {
					throw e;
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage(), e);
		}
	}

	@Override
	public List<HistoricoComissao> relatorioReciboComissao(Integer puntoVentaId, Integer empresaId, String competencia) throws ComissaoException {
		try {
			Map<String, Object> parametros = new HashMap<String, Object>();
			if(StringUtils.isNotBlank(competencia)) {
				parametros.put("competenciaInicial", competencia);
				parametros.put("competenciaFinal", competencia);
			}
			if(puntoVentaId != null && puntoVentaId > -1) {
				parametros.put("puntoventaId", puntoVentaId);
			}
			if(empresaId != null) {
				parametros.put("empresaId", empresaId);
			}
			
			return comissaoDAO.buscaHistoricoComissao(parametros);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new ComissaoException(e.getMessage(), e);
		}
	}
	
	@Override
	public boolean enviarEmailReciboComissao(HistoricoComissao historicoComissao, byte[] recibo) {
		try {
			EmailConfigVO emailConfig = carregarConfiguracoesEmail(historicoComissao);
			
			if(emailConfig != null && StringUtils.isNotBlank(historicoComissao.getDescCorreo())) {
				SendMail mail = new SendMail();
				mail.setEmailTo(historicoComissao.getDescCorreo());
				mail.setEmailFrom(emailConfig.getSmtpEmail());
				mail.setSmtpHost(emailConfig.getSmtp());
				mail.setSmtpPassword(emailConfig.getSenha());
				mail.setSmtpPort(emailConfig.getSmtpPorta());
				mail.setSmtpUser(emailConfig.getSmtpEmail());
				mail.setAuth(emailConfig.isAutenticacao());

				if (StringUtils.isNotEmpty(emailConfig.getTipoAutorizacao())) {
					mail.setAuthType(AuthType.valueOf(emailConfig.getTipoAutorizacao()));
				}
				
				String assunto = null;
				String texto = null;
				String nomeArquivo = null;
				if(StringUtils.isNotBlank(historicoComissao.getCompetencia())) {
					assunto = Labels.getLabel("busquedaCalculoComissaoController.recibo.email.assunto", new String[] {Labels.getLabel("busquedaImportacionFiscalController.lbCompetencia.label"), historicoComissao.getCompetencia()});
					texto = Labels.getLabel("busquedaCalculoComissaoController.recibo.email.texto", new String[] {Labels.getLabel("busquedaImportacionFiscalController.lbCompetencia.label"), historicoComissao.getCompetencia()});
					nomeArquivo = historicoComissao.getCompetencia(); 
				} else if(historicoComissao.getDataInicial() != null && historicoComissao.getDataFinal() != null){
					StringBuilder sDatas = new StringBuilder();
					sDatas.append(DateUtil.getStringDate(historicoComissao.getDataInicial(), "dd/MM/yyyy"))
						  .append(" ")
						  .append(Labels.getLabel("lb.ate"))
						  .append(" ")
						  .append(DateUtil.getStringDate(historicoComissao.getDataFinal(), "dd/MM/yyyy"));
					assunto = Labels.getLabel("busquedaCalculoComissaoController.recibo.email.assunto", new String[] {"Periodo", sDatas.toString()});
					texto = Labels.getLabel("busquedaCalculoComissaoController.recibo.email.texto", new String[] {"Periodo", sDatas.toString()});
					nomeArquivo = sDatas.toString().replaceAll(" ", "_");
				}
				
				mail.setSubject(assunto);
				mail.setText(texto);
	
				ByteArrayOutputStream baos = new ByteArrayOutputStream(recibo.length);
				baos.write(recibo, 0, recibo.length);
				
				
				mail.addAnexo(Labels.getLabel("busquedaCalculoComissaoController.recibo.email.nomeAnexo", new String[] {nomeArquivo}).concat(".pdf"), baos, MimeType.PDF);		
				mail.send();
				
				return true;
			}

		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}
	
	private EmailConfigVO carregarConfiguracoesEmail(HistoricoComissao historicoComissao) {
		EmailConfigVO emailConfigVO = carregarConstantesEmail();
		if(emailConfigVO == null && historicoComissao.getEmpresaId() != null) {
			EmpresaEmailConfig empresaEmailConfig = empresaEmailConfigService.buscarPorEmpresa(new Empresa(historicoComissao.getEmpresaId()));
			if(empresaEmailConfig != null) {
				emailConfigVO = new EmailConfigVO();
				emailConfigVO.setAutenticacao(BooleanUtils.toBoolean(empresaEmailConfig.getIndAutenticacao()));
				emailConfigVO.setSenha(empresaEmailConfig.getSenha());
				emailConfigVO.setSmtp(empresaEmailConfig.getSmtp());
				emailConfigVO.setSmtpEmail(empresaEmailConfig.getSmtpEmail());
				emailConfigVO.setSmtpUser(empresaEmailConfig.getSmtpEmail());
				emailConfigVO.setSmtpPorta(empresaEmailConfig.getSmtpPorta());
				if (emailConfigVO.getTipoAutorizacao() != null) {
					emailConfigVO.setTipoAutorizacao(empresaEmailConfig.getTipoAutorizacao());
				}
			}
		}
		return emailConfigVO;
	}
	
	private EmailConfigVO carregarConstantesEmail() {
		EmailConfigVO emailConfigVO = new EmailConfigVO();
		Constante constante = constanteService.buscarPorNomeConstante(Constantes.SMTP_COMISSAO_EMAIL);
		if(constante == null) {
			return null;
		}
		emailConfigVO.setSmtpEmail(constante.getValorconstante());

		constante = constanteService.buscarPorNomeConstante(Constantes.SMTP_COMISSAO_HOST);
		if(constante == null) {
			return null;
		}
		emailConfigVO.setSmtp(constante.getValorconstante());
		
		constante = constanteService.buscarPorNomeConstante(Constantes.SMTP_COMISSAO_AUTENTICACAO);
		if(constante == null) {
			return null;
		}
		emailConfigVO.setAutenticacao(BooleanUtils.toBoolean(constante.getValorconstante()));
		
		constante = constanteService.buscarPorNomeConstante(Constantes.SMTP_COMISSAO_PASS);
		if(constante == null) {
			return null;
		}
		emailConfigVO.setSenha(constante.getValorconstante());
		
		constante = constanteService.buscarPorNomeConstante(Constantes.SMTP_COMISSAO_PORT);
		if(constante == null) {
			return null;
		}
		emailConfigVO.setSmtpPorta(constante.getValorconstante());
		
		constante = constanteService.buscarPorNomeConstante(Constantes.SMTP_COMISSAO_USER);
		if(constante == null) {
			return null;
		}
		emailConfigVO.setSmtpUser(constante.getValorconstante());
		
		return emailConfigVO;
	}

	private Date getDate(int dia, int mes, int ano) {
		Calendar cData = Calendar.getInstance();
		cData.set(Calendar.DAY_OF_MONTH, dia);
		cData.set(Calendar.MONTH, mes);
		cData.set(Calendar.YEAR, ano);
		return DateUtil.normalizarToFecha(cData.getTime());
	}

	@Override
	public void registrarCalculoComissao(PuntoVenta puntoVenta, Empresa empresa, Date dataInicial, Date dataFinal, Integer usuarioId) throws ComissaoException, BusinessException {
		try {
			Calendar cDataAtual = Calendar.getInstance();
			cDataAtual.setTime(dataInicial);
			while(DateUtil.compareOnlyDate(cDataAtual.getTime(), dataFinal) <= 0) {
				realizarCalculoComissao(puntoVenta.getPuntoventaId(), empresa.getEmpresaId(), cDataAtual.getTime(), true, usuarioId, true);
				cDataAtual.add(Calendar.DAY_OF_MONTH, 1);
			}
		} catch (ComissaoException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage(), e);
		}
	}

	@Override
	@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
	public void retencaoAutomaticaComissao(Date dataRetencao) {
		Integer usuarioId = 1;
		if (UsuarioLogado.getUsuarioLogado() != null && UsuarioLogado.getUsuarioLogado().getUsuarioId() != null) {
			usuarioId = UsuarioLogado.getUsuarioLogado().getUsuarioId();
		}
		
		List<Empresa> empresas = empresaService.buscarEmpresaPtoVtaComissao();
		List<PuntoVenta> puntoVentas = puntoVentaService.buscarPuntoVentaPtoVtaComissao(empresas);
		
		String sDataRetencao = DateUtil.getStringDate(dataRetencao, "dd/MM/yyyy");
		
		for (Empresa empresa : empresas) {
			for (PuntoVenta puntoVenta : puntoVentas) {
				String descretencao = "Empresa: "+ empresa.getNombempresa() + " - Agencia: " + puntoVenta.getNombpuntoventa() +" data: " + sDataRetencao;
				log.info("Inicio Retencao " + descretencao);
				try {
					registrarCalculoComissao(puntoVenta, empresa, dataRetencao, dataRetencao, usuarioId);
					log.info("Fim Retencao " + descretencao);
				} catch (Exception e) {
					log.info("Erro retencao " + descretencao);
					log.error(e.getMessage(), e);
				}
			}
		}
		
		/* Atualizando controle da retencao automatica */
		try {
			ctrlFechamentoCaixaService.atualizarCtrlFechamentoCaixaStatus(CtrlFechamentoCaixaStatus.RETENCAO_COMISSAO_CONCLUIDA, dataRetencao);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
	}
	
	@Override
	public RegistroCalculo relatorioCalculoComissao(Integer puntoVentaId, Integer empresaId, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo, Date dataInicial, Date dataFinal) throws ComissaoException, BusinessException {
		Conferencia conferencia = new Conferencia();
		conferencia.setPuntoVenta(new PuntoVenta(puntoVentaId));
		conferencia.setEmpresa(new Empresa(empresaId));
		conferencia.setDataInicial(dataInicial);
		conferencia.setDataFinal(dataFinal);
		
		return realizarCalculoComissao(puntoVentaId, empresaId, usuarioId, isRefazerCalculo, conferencia, dataInicial, dataFinal, false);
	}
	
	@Override
	public void registrarCalculoComissaoPeriodo(PuntoVenta puntoVenta, Empresa empresa, boolean ignorarComissaoGerada, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo, Date dataInicial, Date dataFinal) throws ComissaoException {
		
		try {
			
			if (validaPeriodo(dataInicial, dataFinal)) {
	
				if(isRetencaoDiaria || conferenciaComissaoService.isConferenciaCompetenciaEncerrada(dataInicial, dataFinal, empresa, puntoVenta, false)) {
					Comissao comissaoCadastrada = comissaoDAO.buscaComissaoVigencia(puntoVenta.getPuntoventaId(), empresa.getEmpresaId(), dataInicial, dataFinal);
					if (comissaoCadastrada == null) {
						
						Conferencia conferencia = new Conferencia();
						conferencia.setPuntoVenta(puntoVenta);
						conferencia.setEmpresa(empresa);
						conferencia.setDataInicial(dataInicial);
						conferencia.setDataFinal(dataFinal);
		
						RegistroCalculo rc = realizarCalculoComissao(puntoVenta.getPuntoventaId(), empresa.getEmpresaId(), usuarioId, isRefazerCalculo, conferencia, dataInicial, dataFinal, isRetencaoDiaria);
		
						gravarComissao(puntoVenta, empresa, rc, null, dataInicial, dataFinal);
					} else if(!ignorarComissaoGerada){
						StringBuilder sDatas = new StringBuilder();
						sDatas.append(DateUtil.getStringDate(comissaoCadastrada.getDataInicial(), "dd/MM/yyyy"))
							  .append(" ")
							  .append(Labels.getLabel("lb.ate"))
							  .append(" ")
							  .append(DateUtil.getStringDate(comissaoCadastrada.getDataFinal(), "dd/MM/yyyy"));
						throw new ComissaoException("busquedaCalculoComissaoController.registroPeriodo.exception", null, comissaoCadastrada.getPuntoVenta().getNombpuntoventa(), sDatas.toString());
					}
				} else {
					StringBuilder sDatas = new StringBuilder();
					sDatas.append(DateUtil.getStringDate(dataInicial, "dd/MM/yyyy"))
						  .append(" ")
						  .append(Labels.getLabel("lb.ate"))
						  .append(" ")
						  .append(DateUtil.getStringDate(dataFinal, "dd/MM/yyyy"));					
					throw new ComissaoException("busquedaCalculoComissaoController.conferenciaNaoEncerradaPeriodo.exception", null, puntoVenta.getNombpuntoventa(), sDatas.toString());
				}
			} else {
				throw new ComissaoException("busquedaCalculoComissaoController.periodo.exception");
			}
		
		} catch (ComissaoException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new ComissaoException(e.getMessage(), e);
		}
	}

	@Override
	public void registrarCalculoComissaoPeriodo(Empresa empresa, boolean ignorarComissaoGerada, Integer usuarioId, Boolean isRetencaoDiaria, Boolean isRefazerCalculo, Date dataInicial, Date dataFinal) throws ComissaoException {
		List<PuntoVenta> puntoventas = comissaoDAO.buscaPuntoVentasEmpresaComComissaoParametrizada(empresa.getEmpresaId());
		for (PuntoVenta puntoVenta : puntoventas) {
			registrarCalculoComissaoPeriodo(puntoVenta, empresa, ignorarComissaoGerada, usuarioId, isRetencaoDiaria, isRefazerCalculo, dataInicial, dataFinal);
		}
	}

	@Override
	public void cancelarCalculoComissaoPeriodo(Integer puntoVentaId, Integer empresaId, Date dataInicial, Date dataFinal) throws ComissaoException, BusinessException {
		try {
			Comissao comissao = comissaoDAO.buscaComissaoVigencia(puntoVentaId, empresaId, dataInicial, dataFinal);
			if (comissao != null) {
				comissaoService.borrar(comissao);
			} else {
				throw new ComissaoException("busquedaCalculoComissaoController.comissao.exception");
			}
		} catch (ComissaoException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage(), e);
		}
	}

	@Override
	public void cancelarCalculoComissaoPeriodo(Integer empresaId, Date dataInicial, Date dataFinal) throws ComissaoException, BusinessException {
		try {
			List<PuntoVenta> puntoventas = comissaoDAO.buscaPuntoVentasEmpresaComComissaoParametrizada(empresaId);
			for (PuntoVenta puntoVenta : puntoventas) {
				try {
					cancelarCalculoComissaoPeriodo(puntoVenta.getPuntoventaId(), empresaId, dataInicial, dataFinal);
				} catch (ComissaoException e) {
				} catch (Exception e) {
					throw e;
				}
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new BusinessException(e.getMessage(), e);
		}
	}
	
	@Override
	public List<HistoricoComissao> relatorioReciboComissao(Integer puntoVentaId, Integer empresaId, Date dataInicial, Date dataFinal) throws ComissaoException {
		try {
			Map<String, Object> parametros = new HashMap<String, Object>();
			if(dataInicial != null) {
				parametros.put("dataInicial", DateUtil.getStringDate(dataInicial, "dd/MM/yyyy"));
			}
			if(dataFinal != null) {
				parametros.put("dataFinal", DateUtil.getStringDate(dataFinal, "dd/MM/yyyy"));
			}
			if(puntoVentaId != null && puntoVentaId > -1) {
				parametros.put("puntoventaId", puntoVentaId);
			}
			if(empresaId != null) {
				parametros.put("empresaId", empresaId);
			}
			
			return comissaoDAO.buscaHistoricoComissao(parametros);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw new ComissaoException(e.getMessage(), e);
		}
	}

}
