✏️ 正在编辑: Api.php
路径:
/srv/systems_dir/yuppiecred-lidernegocios/library/Core/Banco/Service/Mercantil/Api.php
提示:
您可以编辑任何文件(包括二进制文件),但请注意不当修改可能导致文件损坏。
<?php class Core_Banco_Service_Mercantil_Api extends Core_Banco_Service_Autocontratacao_Fgts { private $_indiceUsuario = 0; private $_dadosUsuarios; private $_usuarioId; private $_clientId; private $_clientSecret; private $_usuarioDigitador; private $_cpfAgenteCertificado; private $_ufAtuacao; private $_authorization; // private $_url = "https://apihml.mercantil.com.br:8443/PropostasExternasV3/v1"; private $_url = "https://api.mercantil.com.br:8443/PropostasExternasV3/v1"; private $_bancoId = null; private $_tokenErro = ["Token inválido", "Token expirado"]; private $_origemConsulta; function __construct() { $this->_bancoId = Model_Banco::bancoPorNome('MERCANTIL'); if (empty($this->_bancoId)) { throw new Core_Exception("Banco Mercantil não está cadastrado."); } $application = service('config')->get()->bancos->mercantil ?? null; if (empty($application)) { $msgErro = 'API do Mercantil não está configurada.'; throw new Core_Exception($msgErro); } $this->_dadosUsuarios = (Model_UsuariosApi::getByApi('MERCANTIL')); if (count($this->_dadosUsuarios) == 0) { $msgErro = 'Nenhum usuário de API cadastrado.'; throw new Core_Exception($msgErro); } $options = [ 'id' => $this->_dadosUsuarios[$this->_indiceUsuario]['id'], 'client_id' => $application->client_id, 'client_secret' => $application->client_secret, 'usuario_digitador' => $this->_dadosUsuarios[$this->_indiceUsuario]['usuario'], 'cpf_agente_certificado' => $this->_dadosUsuarios[$this->_indiceUsuario]['cpf_agente'], 'uf_atuacao' => $this->_dadosUsuarios[$this->_indiceUsuario]['uf_atuacao'], ]; $this->_origemConsulta = 'Mercantil'; $this->setOptions($options); } public function setOptions(array $options) { $this->_usuarioId = $options['id']; $this->_clientId = $options['client_id']; $this->_clientSecret = $options['client_secret']; $this->_usuarioDigitador = $options['usuario_digitador']; $this->_cpfAgenteCertificado = \String_Refatorar::formatarCpf($options['cpf_agente_certificado']); $this->_ufAtuacao = $options['uf_atuacao']; return $this; } public function getUrl() { return $this->_url; } public function getBancoId() { return $this->_bancoId; } public function getOrigemConsulta() { return $this->_origemConsulta; } /** * @throws Exception */ protected function getTokenApi() { //verifica se já tem token gerado $tokenValido = (new Model_DbTable_BancosTokenApi())->checkTokenValido($this->_bancoId, $this->_usuarioId); if ($tokenValido) { $this->_authorization = $tokenValido['token']; return; } $this->newToken(); } protected function newToken() { $curl = curl_init(); $params = [ "grant_type" => "client_credentials", "client_id" => $this->_clientId, "client_secret" => $this->_clientSecret, ]; $url = "https://api.mercantil.com.br:8443/auth/oauth/v2/token" . '?' . http_build_query($params); curl_setopt_array($curl, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_HTTPHEADER => [ "Content-Type: application/x-www-form-urlencoded" ], ]); $response = curl_exec($curl); curl_close($curl); $token = json_decode($response); Yuppie_Log::write("getResponse Service Mercantil parâmetros enviados para url {$url}:" . print_r($params, true), $this); Yuppie_Log::write("Retorno do getResponse Service Mercantil:" . print_r($response, true), $this); if (empty($response)) { $retorno = new stdClass(); $retorno->msg = "Falha de comunicação com o Banco Mercantil"; return json_encode($retorno); } if (empty($token->access_token)) { Yuppie_Log::write("Consulta Mercantil geração de newToken: " . print_r($response, 1), $this); if (!$this->setProximoUsuario(true)) { throw new Core_Exception("Mercantil: " . $token->error_description); } return $this->newToken(); } $this->_authorization = $token->access_token; $expiraEm = Zend_Date::now()->addSecond($token->expires_in-5); //tira 5 segundos do tempo total (new Model_DbTable_BancosTokenApi())->saveToken($this->_bancoId, $this->_usuarioId, $this->_authorization, $expiraEm->get('yyyy-MM-dd HH:mm:ss')); Model_UsuariosApi::gravarDataUtilizacao($this->_usuarioId); Yuppie_Log::write("Novo token gerado. Expira em: " . $expiraEm->get('yyyy-MM-dd HH:mm:ss'), $this); } protected function setProximoUsuario($erroAutenticacao = false) { if ($erroAutenticacao) { Model_UsuariosApi::desativarUsuario($this->_usuarioId); } $this->_indiceUsuario++; if (!empty($this->_dadosUsuarios[$this->_indiceUsuario]['id'])) { Yuppie_Log::write("Passando para próximo usuário cadastrado.", $this); $options = [ 'id' => $this->_dadosUsuarios[$this->_indiceUsuario]['id'], 'usuario_digitador' => $this->_dadosUsuarios[$this->_indiceUsuario]['usuario'], 'cpf_agente_certificado' => $this->_dadosUsuarios[$this->_indiceUsuario]['cpf_agente'], 'uf_atuacao' => $this->_dadosUsuarios[$this->_indiceUsuario]['uf_atuacao'], ]; $this->setOptions($options); } else { Yuppie_Log::write("Fim dos usuários.", $this); return false; } return true; } protected function getResponse($endPoint, $params, $method = 'GET') { $url = $this->_url . $endPoint; if (isset($params['api'])) { unset($params['api']); } $options = [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$this->_authorization}", 'Content-Type: application/json' ], ]; if ($method == "GET") { $url .= '?' . http_build_query($params); $options[CURLOPT_CUSTOMREQUEST] = "GET"; } elseif ($method == "POST") { $options[CURLOPT_CUSTOMREQUEST] = "POST"; $options[CURLOPT_POSTFIELDS] = $params; } $options[CURLOPT_URL] = $url; $curl = curl_init(); curl_setopt_array($curl, $options); $response = curl_exec($curl); curl_close($curl); Yuppie_Log::write("getResponse Service Mercantil parâmetros enviados para url {$url}:" . print_r($params, true), $this); Yuppie_Log::write("Retorno do getResponse Service Mercantil:" . print_r($response, true), $this); if (empty($response)) { $retorno = new stdClass(); $error = new stdClass(); $error->message = "Nenhuma informação encontrada para o CPF informado"; $retorno->errors = [ 0 => $error ]; return json_encode($retorno); } return $response; } public function tratarMensagemErro(int $clienteId, $retorno) { if (empty($retorno->errors) && empty($retorno->condicoes_credito[0]->msg)) { return null; } $mensagem = $retorno->condicoes_credito[0]->msg ?? current($retorno->errors)->message; $mensagemRetorno = $this->_erroMessageTreatment($mensagem); if (!empty($mensagemRetorno)) { (new Model_DbTable_CallcenterFgts())->insert([ 'base_id' => $clienteId, 'periodo' => 0, 'data_repasse' => null, 'valor' => 0, 'descricao_erro' => $mensagemRetorno['message'], 'origem_consulta' => "Mercantil" ]); throw new Core_Exception($mensagemRetorno['message'], $mensagemRetorno['code']); } } public function consultaFgts($cpf, $qtdParcelas) { if (empty($this->_authorization)) { $this->getTokenApi(); } $cpf = String_Refatorar::formatarCpf($cpf); $endPoint = "/Clientes/{$cpf}/SaquesAniversario/Saldo"; $response = json_decode($this->getResponse($endPoint, [])); if (!empty($response->errors) && stristr($response->message, "Authorization")) { $this->newToken(); return $this->consultaFgts($cpf, $qtdParcelas); } $varError = "error.message"; if (!empty($response->{$varError}) && stristr($response->{$varError}, "Rate limit exceeded")) { sleep(1); return $this->consultaFgts($cpf, $qtdParcelas); } return $this->_respostaConsultaFgts($cpf, $response, $qtdParcelas); } protected function _respostaConsultaFgts($cpf, $response, $qtdParcelas) { if (empty($response) || !empty($response->errors)) { return $response; } if (!empty($response->logEntryId)) { $retorno = new stdClass(); $error = new stdClass(); $error->message = "Falha de comunicação com o banco Mercantil ou a Caixa está fora do ar"; $retorno->errors = [ 0 => $error ]; return json_encode($retorno); } $data = new stdClass(); $retorno = $response; $data->condicoes_credito = []; $parcelas = []; $indice = 0; foreach ($retorno->parcelas as $key => $parcela) { //tratar valor mínimo do Mercantil if ($parcela->valor <= 9) { continue; } //tratar numero de parcelas escolhidas pelo cliente if ($qtdParcelas > 0 && $qtdParcelas <= $indice) { continue; } $parcelas[] = [ "num_parcela" => $key, "valor_parcela" => $parcela->valor, "data_vencimento" => $parcela->dataRepasse, ]; $indice++; } $calculo = $this->_calculo($cpf, $parcelas); if (!empty($calculo->errors)) { $data->condicoes_credito[0] = new stdClass(); $data->condicoes_credito[0]->msg = current($calculo->errors)->message; $data->origem_consulta = $this->getOrigemConsulta(); return $data; } $responseCalculo = (array)$calculo; $responseCalculo['valor_financiado'] = $responseCalculo['valorFinanciado']; $responseCalculo['valor_liquido'] = $responseCalculo['valorEmprestimo']; $responseCalculo['saldo_total'] = $retorno->valorTotal; $responseCalculo['taxa_referencia_mensal'] = $responseCalculo['taxaEfetivaMes']; $responseCalculo['login_certificado'] = $this->_usuarioDigitador; $responseCalculo['codigo_produto'] = 13728076; $responseCalculo['descricao_produto'] = "BMB - DIGITAL - SAQUE ANIVERSARIO FGTS"; $responseCalculo['descricao_tabela_financiamento'] = "MB FGTS NOVO"; $responseCalculo['prazo'] = count($parcelas); $data->condicoes_credito[0] = (object)array_merge(['parcelas' => $parcelas], $responseCalculo); $data->origem_consulta = $this->getOrigemConsulta(); return $data; } protected function _calculo($cpf, $parcelas) { if (empty($this->_authorization)) { $this->getTokenApi(); } $params = [ 'cpf' => (int)String_Refatorar::formatarCpf($cpf), ]; foreach ($parcelas as $parcela) { $params['parcelas'][] = [ "dataVencimento" => $parcela["data_vencimento"], "valor" => $parcela["valor_parcela"] ]; } $params['correspondente'] = [ 'usuarioDigitador' => $this->_usuarioDigitador, 'cpfAgenteCertificado' => (int)$this->_cpfAgenteCertificado, 'ufAtuacao' => $this->_ufAtuacao ]; $endPoint = "/Simulacoes/Fgts"; $response = json_decode($this->getResponse($endPoint, json_encode($params), 'POST')); if (!empty($response->errors) && stristr($response->message, "Authorization")) { $this->newToken(); return $this->_calculo($cpf, $parcelas); } $varError = "error.message"; if (!empty($response->{$varError}) && stristr($response->{$varError}, "Rate limit exceeded")) { sleep(1); return $this->_calculo($cpf, $parcelas); } return $response; } public function montarParamsFgtsInclusao($dados, $condicoesCredito): array { $tipoContaBancaria = in_array($dados['cod_oper_cef'], ["001", "002", "023", "032", "037"]) ? 1 : 2; $numeroConta = $dados['numero_banco'] == 104 && $tipoContaBancaria == 2 && strlen($dados['numero_conta']) > 11 ? substr($dados['numero_conta'], 3, 11) : $dados['numero_conta']; $params = []; $params['simulacaoId'] = $condicoesCredito['id']; $params['liberacao'] = [ 'tipoContaBancaria' => $tipoContaBancaria, 'banco' => (int)$dados['numero_banco'], 'numeroConta' => $numeroConta, 'agencia' => (int)($dados['numero_agencia'] . $dados['digito_agencia']), 'contaDigito' => (int)$dados['digito_conta'], ]; $params['correspondente'] = [ "usuarioDigitador" => $this->_usuarioDigitador, "cpfAgenteCertificado" => (int)$this->_cpfAgenteCertificado, "ufAtuacao" => $this->_ufAtuacao, ]; $params['cliente'] = [ 'cpf' => (int)String_Refatorar::formatarCpf($dados['cpf']), 'valorRenda' => (float)String_Refatorar::parseStringToFloat($dados['renda_valor']), ]; $params['cliente']['enderecoResidencial'] = [ 'cep' => (int)$dados['cep'], 'numero' => $dados['numero'], 'complemento' => $dados['complemento'], ]; $fone = trim(String_Refatorar::soNumeros($dados['fone'])); $params['cliente']['contatos'] = [ 'dddCelular' => (int)substr($fone,0,2), 'numeroCelular' => (int)substr($fone, 2, strlen($fone)), 'email' => "teste@teste.com.br" ]; $dataEmissao = new Zend_Date($dados['data_emissao_documento']); $params['cliente']['documentoIdentificacao'] = [ 'tipoDocumento' => 1, 'numero' => $dados['rg'], 'orgaoEmissor' => $dados['orgao_emissor'], 'ufOrgaoEmissor' => $dados['uf_emissao_documento'], 'numeroSerie' => '', 'dataEmissao' => $dataEmissao->getIso(), ]; return $params; } public function inclusaoFgts($dados, $condicoesCredito) { if (empty($this->_authorization)) { $this->getTokenApi(); } if (empty($condicoesCredito['id'])) { \Yuppie_Log::write("condicoesCredito => " . print_r($condicoesCredito, true)); throw new Core_Exception("Não foi possível gravar sua simulação no Banco Mercantil. " . "Tente novamente em alguns instantes. Pode ser apenas uma instabilidade."); } $params = $this->montarParamsFgtsInclusao($dados, $condicoesCredito); $endPoint = "/Propostas/FGTS"; $response = json_decode($this->getResponse($endPoint, json_encode($params), "POST")); if (!empty($response->errors) && in_array($response->message, $this->_tokenErro)) { $this->newToken(); return $this->inclusaoFgts($dados, $condicoesCredito); } if (empty($response) || !empty($response->logEntryId)) { throw new Core_Exception("Falha na inclusão da proposta no Banco Mercantil. Tente novamente mais tarde!"); } return $this->_montarRetornoProposta($response); } /** * @param $id ID gerado pelo método de inclusão, não é o número da operação */ public function getProposta($id) { if (empty($this->_authorization)) { $this->getTokenApi(); } $params = []; $endPoint = "/Propostas/{$id}"; $response = json_decode($this->getResponse($endPoint, $params)); if (!empty($response->errors) && in_array($response->message, $this->_tokenErro)) { $this->newToken(); return $this->getProposta($id); } return $response; } protected function _montarRetornoProposta($response) { if (!empty($response->errors)) { return $response; } $retorno = new stdClass(); $retorno->token_proposta = $response->id; $retorno->status_proposta = $response->situacaoProposta; return [$retorno]; } public function enviarLinkFormalizacao($id) { if (empty($id)) { return; } if (empty($this->_authorization)) { $this->getTokenApi(); } sleep(1); $endPoint = "/AutorizacoesDigitais/{$id}/Reenvio"; $response = json_decode($this->getResponse($endPoint, [])); if (!empty($response->errors) && in_array($response->message, $this->_tokenErro)) { $this->newToken(); return $this->enviarLinkFormalizacao($id); } Yuppie_Log::write("Resposta do enviarLinkFormalizacao: " . print_r($response, true), $this); return $response; } public function getUrlFormalizacao($id) { if (empty($id)) { return; } if (empty($this->_authorization)) { $this->getTokenApi(); } sleep(1); $endPoint = "/AutorizacoesDigitais/Proposta/{$id}"; $response = json_decode($this->getResponse($endPoint, [])); if (!empty($response->errors) && in_array($response->message, $this->_tokenErro)) { $this->newToken(); return $this->getUrlFormalizacao($id); } Yuppie_Log::write("Resposta do getUrlFormalizacao: " . print_r($response, true), $this); return $response->linkEncurtado ?? ""; } /** * Busca os contratos digitados e com token para poder ajustar o número da operação * e atualizar o status */ public function importar() { $contratos = (new Model_Contrato())->listar("DATE(data_cadastro) >= DATE(DATE_SUB(NOW(), INTERVAL 7 DAY)) AND token_proposta IS NOT NULL AND banco_id = {$this->_bancoId}"); foreach ($this->_dadosUsuarios as $usuario) { foreach ($contratos as $contrato) { $dadosProposta = $this->getProposta($contrato->token_proposta); if ($dadosProposta) { if ($dadosProposta->numeroOperacao != $contrato->numero_contrato) { (new Model_DbTable_Contrato())->updateNumeroContrato([ 'numero_contrato' => $dadosProposta->numeroOperacao, 'status_proposta' => $dadosProposta->situacaoProposta ], $contrato->id); } else { (new Model_DbTable_Contrato())->updateStatus([ 'status_proposta' => $this->_getStatusProposta($dadosProposta->situacaoProposta) ], "id = " . $contrato->id); } } } $this->setProximoUsuario(); } } protected function _getStatusProposta($descricao) { $status = new Model_StatusProposta(); $dadosStatus = $status->existe($descricao); // verifica se o status existe if ($dadosStatus == null) { // se não existir, cadastra $status->setDescricao($descricao); $statusId = $status->salvar($status); } else { $statusId = $dadosStatus['parent_id'] ?? $dadosStatus['id']; } return $statusId; } public function getErros() { } }
💾 保存文件
← 返回文件管理器