public ActionResult SalvarParecer(DadoPrincipalAprovacao dadPri, DefinicoesClienteAprovacao defCli, string Txtpar, string StatusParecer, string chkEncerra, string vlrLimAnalise, string cpgAnalise, string fpgAnalise)
        {
            using (ParecerSolicitacaoBLL parecerSolicitacaoBLL = new ParecerSolicitacaoBLL())
            {
                PerfilUsuarioBLL perfilBLL = new PerfilUsuarioBLL();
                ConfiguracaoWorkflowBLL configBLL = new ConfiguracaoWorkflowBLL();
                HistoricoSolicitacaoBLL historicoBLL = new HistoricoSolicitacaoBLL();

                ParecerSolicitacao p = Session["Parecer"] as ParecerSolicitacao;
                Solicitacao s = Session["Solicitacao"] as Solicitacao;

                var historico = new HistoricoSolicitacao();

                var usuario = Session["ConexaoSapiens"] as UsuarioSapiens;
                List<PerfilUsuario> perfisUsuarioLogado = null;

                if (usuario != null)
                {
                    perfisUsuarioLogado = perfilBLL.ObterGruposPorCodUsuario(usuario.Codusu);
                }

                // se algum dos perfis do usuário logado contém o perfil aprovador, pode salvar parecer.
                var queryPodeSalvarParecer = from meuPerfil in perfisUsuarioLogado
                                             where meuPerfil.CodPerfilUsuario == p.Codperusu
                                             select meuPerfil;

                var podeSalvar = queryPodeSalvarParecer.Count() > 0 ? true : false;

                // Se o usuário logado não tiver o perfil de aprovação, não pode salvar o parecer
                if (!podeSalvar)
                {
                    return Json(new { msg = "O perfil atual não tem permissão para aprovar este parecer." }, JsonRequestBehavior.DenyGet);
                }

                switch (StatusParecer)
                {
                    case "AP":
                        p.Codsitpar = Convert.ToDecimal(SituacaoParecer.Aprovada);
                        break;

                    case "RP":
                        p.Codsitpar = Convert.ToDecimal(SituacaoParecer.Reprovada);
                        p.Solicitacao.Situacao = "REPROVADA";
                        historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoParecer.Reprovada);
                        historico.DatFinalizacao = DateTime.Now;

                        break;
                }

                #region atualiza o parecer atual com os dados que estão na tela.

                SalvarDadoPrincipal(dadPri);

                defCli.VlrLimite = vlrLimAnalise;
                defCli.CodCondicaoPagamento = cpgAnalise;
                defCli.CodFormaDePagamento = fpgAnalise;

                SalvarDefinicoes(defCli);

                #endregion

                // usando o SignalR para implementar atualização geral em tempo real.
                // (atualiza os grids de todos os usuários logados , sem necessidade do F5)
                var context = GlobalHost.ConnectionManager.GetHubContext<StatusHub>();

                //o parecer persistido ( pode gravar, atualizar, até excluir pelo BLL);
                var parecer = parecerSolicitacaoBLL.ObterPorCodigo(p.CodParecer);

                parecer.Codsitpar = p.Codsitpar; // O Novo parecer inicia como Aguardando Aprovação.
                parecer.Codusuapr = usuario.Codusu;
                parecer.Datpar = DateTime.Now;
                parecer.Solicitacao = p.Solicitacao;
                parecer.Txtpar = Txtpar;

                try
                {
                    if (!String.IsNullOrEmpty(Txtpar))
                    {
                        // se entrar aqui , está APROVADA e OK para Gravar.
                        if (parecer.Codsitpar == Convert.ToDecimal(SituacaoParecer.Aprovada))
                        {
                            // verificar na configuração de alçada se tem próximo nível e qual é esse nível.
                            // 21/08/2015 - verificar se o parecer que está sendo aprovado é o último necessário

                            // se o usuário aprovador corresponde ao nivel máximo, ou se está marcado para encerrar o parecer, pode enviar...
                            var prontaParaIntegrar = (((parecer.Codperusu - 2) == s.nivelMaximo) || chkEncerra == "S");
                            //(s.PareceresSolicitacao.Count - 1) == s.nivelMaximo || chkEncerra == "S"
                            if (prontaParaIntegrar)
                            {
                                try
                                {
                                    // muda status para Aguardando integração
                                    parecer.Codsitpar = Convert.ToDecimal(SituacaoParecer.AguardandoIntegracao);
                                    parecer.Solicitacao.CodSituacaoAtual = Convert.ToInt32(SituacaoSolicitacao.AguardandoIntegracao);
                                    parecerSolicitacaoBLL.Atualizar(parecer);

                                    s.CodSituacaoAtual = Convert.ToInt32(SituacaoSolicitacao.AguardandoIntegracao);

                                    Thread t = new Thread(_ =>
                                    {
                                        ServiceReferenceTeste.srvSicadSoapClient clienteTesteIntegracao = new ServiceReferenceTeste.srvSicadSoapClient();
                                        clienteTesteIntegracao.IntegrarDadosCliente(p.Solicitacao.Codigo);
                                    });

                                    t.Start();

                                    historico.DatEncaminhamento = DateTime.Now;
                                    historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoSolicitacao.AguardandoIntegracao);
                                    historico.Solicitacao = s;
                                    if (chkEncerra == "S")
                                    {
                                        Txtpar += " ( Encerramento do workflow antecipado por " + usuario.Nomusu + " )";
                                    }
                                    historico.TxtHistorico = Txtpar;

                                    historicoBLL.Salvar(historico);
                                }
                                catch (Exception ex)
                                {
                                    // TODO: Retirar depois de validar a execução do webservice ( vai ficar aguardando Integração se for finalmente aprovado )
                                    parecer.Codsitpar = Convert.ToDecimal(SituacaoParecer.AguardandoAprovacao);
                                    parecerSolicitacaoBLL.Atualizar(parecer);

                                    throw ex;
                                }
                            }
                            else
                            {

                                int codPerfilAprovadorAtual = Convert.ToInt32(parecer.Codperusu);

                                // se não encerra, cria um novo parecer ...
                                var novoParecer = new ParecerSolicitacao();

                                novoParecer.Solicitacao = p.Solicitacao;

                                novoParecer.Codsitpar = Convert.ToDecimal(SituacaoParecer.AguardandoAprovacao);

                                novoParecer.Codhistsol = historico.CodHistoricoSolicitacao; // pegar o codhist OK
                                //novoParecer.Codperusu = ++p.Codperusu; // o perfil do analista de crédito. -> se o usuário não tiver perfil, avisar na tela.

                                int codPerfilProximoAprovador = 0;

                                switch (codPerfilAprovadorAtual)
                                {
                                    case 2: codPerfilProximoAprovador = 3; break;
                                    case 3: codPerfilProximoAprovador = 4; break;
                                    case 4: codPerfilProximoAprovador = 5; break;

                                    //case 5: return Json("", JsonRequestBehavior.DenyGet);

                                }

                                novoParecer.Codperusu = (decimal)codPerfilProximoAprovador;
                                //novoParecer.Codusuapr = s.CodUsuarioSolicitacao; // obter o codigo do usuario da aprovacao. OK
                                novoParecer.Codusuapr = usuario.Codusu;

                                // necessário definir o código como 0 para instruir o NHibernate que este é um novo objeto.
                                dadPri.CodigoDadoPrincipalAprovacao = 0;
                                dadPri.Parecer = parecer;

                                // salvar todos os dados do parecer anterior no novo parecer, e incluir as alterações feitas na tela.
                                novoParecer.DadosPrincipaisAprovacao.Add(dadPri);

                                defCli.CodDefinicoesClienteAprovacao = 0;
                                defCli.Parecer = parecer;
                                novoParecer.DefinicoesAprovacao.Add(defCli);

                                foreach (var ca in p.CaracteristicasAprovacao)
                                {
                                    ca.CodCaracteristicaClienteAprovacao = 0;
                                    novoParecer.CaracteristicasAprovacao.Add(ca);
                                }

                                foreach (var ec in p.EnderecosCobrancaAprovacao)
                                {
                                    ec.CodEnderecoCobrancaClienteApr = 0;
                                    novoParecer.EnderecosCobrancaAprovacao.Add(ec);
                                }

                                foreach (var ee in p.EnderecosEntregaAprovacao)
                                {
                                    ee.CodEnderecoEntregaClienteApr = 0;
                                    novoParecer.EnderecosEntregaAprovacao.Add(ee);
                                }

                                foreach (var r in p.ReferenciasAprovacao)
                                {
                                    r.CodReferenciaApr = 0;
                                    novoParecer.ReferenciasAprovacao.Add(r);
                                }

                                foreach (var c in p.ContatosAprovacao)
                                {
                                    c.CodContatoAprovacao = 0;
                                    novoParecer.ContatosAprovacao.Add(c);
                                }

                                foreach (var soc in p.SociosAprovacao)
                                {
                                    soc.CodSocioEmpresaAprovacao = 0;
                                    novoParecer.SociosAprovacao.Add(soc);
                                }

                                foreach (var doc in p.DocumentosAnexadosAprovacao)
                                {
                                    doc.CodDocumentoAnexadoApr = 0;
                                    novoParecer.DocumentosAnexadosAprovacao.Add(doc);
                                }

                                // EX: se estiver R$ 5.000,00 vai ficar 5000, se for nulo vai virar string vazia
                                novoParecer.DefinicoesAprovacao.Last().VlrLimite = String.IsNullOrEmpty(novoParecer.DefinicoesAprovacao.Last().VlrLimite) ? "" : Regex.Replace(novoParecer.DefinicoesAprovacao.Last().VlrLimite, @"(\s+)|(\\+)|(\.+)|(/+)|(\-+)|(\,+)|(R+)|(\$+)", "");
                                novoParecer.DefinicoesAprovacao.Last().VlrLimite = novoParecer.DefinicoesAprovacao.Last().VlrLimite != "" ? novoParecer.DefinicoesAprovacao.Last().VlrLimite.Substring(0, novoParecer.DefinicoesAprovacao.Last().VlrLimite.Length - 2) : "";

                                // EX: se estiver R$ 5.000,00 vai ficar 5000, se for nulo vai virar string vazia
                                novoParecer.DefinicoesAprovacao.Last().VlrDescontoFinanceiro = String.IsNullOrEmpty(novoParecer.DefinicoesAprovacao.Last().VlrDescontoFinanceiro) ? "" : Regex.Replace(novoParecer.DefinicoesAprovacao.Last().VlrDescontoFinanceiro, @"(\s+)|(\\+)|(\.+)|(/+)|(\-+)|(\,+)|(R+)|(\$+)", ""); // .Substring(0, novoParecer.DefinicoesAprovacao.Last().VlrDescontoFinanceiro.Length - 2) estava assim pois inicialmente esse campo foi entendido como monetário, mas é um valor percentual,como em '33%' ou '02%'

                                // salva o novo parecer e os objetos associados.
                                parecerSolicitacaoBLL.Salvar(novoParecer);

                                // atualiza o parecer existente para aprovado
                                parecerSolicitacaoBLL.Atualizar(parecer);

                                historico.Solicitacao = p.Solicitacao;
                                historico.TxtHistorico = p.Txtpar;
                                historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoSolicitacao.AguardandoAprovacao);
                                historicoBLL.Salvar(historico);
                            } // fim do "se não encerra"

                        } // fim do "se aprova"
                        else // se não aprova.
                        {
                            historico.DatFinalizacao = DateTime.Now;
                            historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoSolicitacao.Reprovada);
                            p.Solicitacao.CodSituacaoAtual = Convert.ToInt32(SituacaoSolicitacao.Reprovada);
                            s.CodSituacaoAtual = Convert.ToInt32(SituacaoSolicitacao.Reprovada);
                            historico.Solicitacao = p.Solicitacao;
                            historico.TxtHistorico = Txtpar; // MOTIVO DA REPROVAÇÃO.
                            historicoBLL.SalvarOuAtualizar(historico);

                            //TODO: atualizar o código da situação da solicitação.
                            new SolicitacaoBLL().AtualizarSituacao(s.Codigo, Convert.ToInt32(SituacaoSolicitacao.Reprovada));

                            parecerSolicitacaoBLL.Atualizar(parecer);

                            context.Clients.All.AtualizarGrid();
                            return Json(new { msg = "Parecer Atualizado." }, JsonRequestBehavior.DenyGet);

                        } // fim do "se não aprova"

                        context.Clients.All.AtualizarGrid();
                        return Json(new { msg = "Parecer Atualizado." }, JsonRequestBehavior.DenyGet);
                    }
                    else
                    {
                        throw new Exception("Não foi possível obter o texto do parecer.");
                    }
                } // Fim do try

                catch (Exception ex)
                {
                    historico.Solicitacao = p.Solicitacao;
                    historico.CodSituacaoIntegracaoSolicitacao = Convert.ToInt32(SituacaoIntegracaoSolicitacao.Erro);
                    historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoSolicitacao.AguardandoAprovacao);
                    historico.TxtHistorico = ex.Message;
                    historico.DatFinalizacao = DateTime.Now;
                    historicoBLL.Salvar(historico);

                    return Json(new { erro = "Não foi possível salvar o parecer. Detalhes : " + ex.Message }, JsonRequestBehavior.DenyGet);
                }
            }
        }
        //sem suporte nativo no 2010, instalar o ASync CTP e testar futuramente...
        //      public async Task DoWork()
        //      {
        //          int[] ids = new[] { 1, 2, 3, 4, 5 };
        //          await Task.WhenAll(ids.Select(i => DoSomething(1, i, blogClient)));
        //      }
        /// <summary>
        /// Aprova várias solicitações usando paralelismo (uso de vários núcleos da CPU disponível)
        /// </summary>
        /// <param name="solicitacoes">uma lista dos códigos das solicitações a aprovar, passados como uma string.</param>
        /// <returns></returns>
        public ActionResult AprovarVarias(string solicitacoes)
        {
            try
            {
                //Autentica
                if (Session["ConexaoSapiens"] == null)
                {
                    return RedirectToAction("Login", "Home");
                }

                //Autoriza
                if (!AutorizaUsuario(ControlAccessConfig.ListaAnalise))
                {
                    return View("Erro", null, "Módulo não autorizado para este usuário. ");
                }
                // verificar se é usuário master
                var perfilBLL = new PerfilUsuarioBLL();

                var usuario = (UsuarioSapiens)Session["ConexaoSapiens"];

                usuario.PerfisUsuario = perfilBLL.ObterGruposPorCodUsuario(usuario.Codusu);

                var queryMaster = from perfil in usuario.PerfisUsuario
                                  where perfil.CodPerfilUsuario == 8
                                  select perfil;

                var isUsuarioMaster = queryMaster.ToList().Count > 0;

                if (isUsuarioMaster)
                {
                    // array [1,2,3,4] veio na request como uma string 1,2,3,4, separar e criar um array de inteiros.
                    var codigos = solicitacoes.Split(',').Select(x => Int32.Parse(x)).ToArray();

                    List<int> aprovados = new List<int>();

                    using (ParecerSolicitacaoBLL parecerBLL = new ParecerSolicitacaoBLL())
                    {

                        var historicoBLL = new HistoricoSolicitacaoBLL();

                        foreach (var c in codigos)
                        {
                            // aprovar várias...
                            // pegar o último parecer de cada solicitação.

                            Thread t = new Thread(_ =>
                            {
                                ServiceReferenceTeste.srvSicadSoapClient clienteTesteIntegracao = new ServiceReferenceTeste.srvSicadSoapClient();
                                clienteTesteIntegracao.IntegrarDadosCliente(c);
                            });

                            t.Start();

                            aprovados.Add(c);

                            //var parecer = solBLL.ObterPorCodigo(c).PareceresSolicitacao.Last();

                            // parecer.Codsitpar = Convert.ToDecimal(SituacaoParecer.AguardandoIntegracao);
                            // parecerBLL.Atualizar(parecer);
                            var historico = new HistoricoSolicitacao();
                            historico.DatEncaminhamento = DateTime.Now;
                            historico.CodSituacaoIntegracaoSolicitacao = Convert.ToInt32(SituacaoIntegracaoSolicitacao.Integrado);
                            historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoSolicitacao.Integrada);
                            var s = new SolicitacaoBLL().ObterPorCodigo(c);
                            historico.Solicitacao = s;

                            historicoBLL.Salvar(historico);
                        }
                    }
                    // atualizar o grid na tela..
                    return Json(new { aprovados = aprovados }, JsonRequestBehavior.DenyGet);
                }
                else
                {
                    return Json(new { erro = "A Função \"Aprovar Selecionados\" não está disponível para o usuário atual. " }, JsonRequestBehavior.DenyGet);
                }
            }
            catch (Exception ex)
            {
                return Json(new { erro = ex.Message }, JsonRequestBehavior.DenyGet);
            }
        }
        public ActionResult Reintegrar(int codigo)
        {
            try
            {
                //Autentica
                if (Session["ConexaoSapiens"] == null)
                {
                    return RedirectToAction("Login", "Home");
                }

                //Autoriza
                if (!AutorizaUsuario(ControlAccessConfig.ListaAnalise))
                {
                    return View("Erro", null, "Módulo não autorizado para este usuário. ");
                }
                // verificar se é usuário master
                var perfilBLL = new PerfilUsuarioBLL();

                var usuario = (UsuarioSapiens)Session["ConexaoSapiens"];

                usuario.PerfisUsuario = perfilBLL.ObterGruposPorCodUsuario(usuario.Codusu);

                var queryTi = from perfil in usuario.PerfisUsuario
                              where perfil.CodPerfilUsuario == 1
                              select perfil;

                var ehUsuarioTI = queryTi.ToList().Count > 0;

                if (ehUsuarioTI)
                {
                    using (ParecerSolicitacaoBLL parecerBLL = new ParecerSolicitacaoBLL())
                    {

                        var historicoBLL = new HistoricoSolicitacaoBLL();

                        Thread t = new Thread(_ =>
                        {
                            ServiceReferenceTeste.srvSicadSoapClient clienteTesteIntegracao = new ServiceReferenceTeste.srvSicadSoapClient();
                            clienteTesteIntegracao.IntegrarDadosCliente(codigo);
                        });

                        t.Start();

                        // pegar o último parecer da solicitação.

                        // var parecer = solBLL.ObterPorCodigo(c).PareceresSolicitacao.Last();

                        // parecer.Codsitpar = Convert.ToDecimal(SituacaoParecer.AguardandoIntegracao);
                        // parecerBLL.Atualizar(parecer);

                        var historico = new HistoricoSolicitacao();
                        historico.DatEncaminhamento = DateTime.Now;
                        historico.CodSituacaoIntegracaoSolicitacao = Convert.ToInt32(SituacaoIntegracaoSolicitacao.Pendente);
                        historico.CodSituacaoSolicitacao = Convert.ToInt32(SituacaoSolicitacao.Aprovada);
                        var s = new SolicitacaoBLL().ObterPorCodigo(codigo);
                        historico.Solicitacao = s;
                        historico.TxtHistorico = "Nova tentativa de reintegração.";

                        historicoBLL.Salvar(historico);
                    } // fim do using

                    // atualizar o grid na tela..
                    return Json(new { msg = "Integração iniciada..." + codigo }, JsonRequestBehavior.AllowGet);
                }
                else
                {
                    return Json(new { erro = "A Função \"Reintegrar\" não está disponível para o usuário atual. " }, JsonRequestBehavior.AllowGet);
                }
            }
            catch (Exception ex)
            {
                return Json(new { erro = ex.Message }, JsonRequestBehavior.DenyGet);
            }
        }