-
Total de itens
3968 -
Registro em
-
Última visita
-
Dias vencidos
47
Tudo que Williams Duarte postou
-
[Resolvido] JavaScript - Exibir logo dentro da Tabela html
Williams Duarte respondeu ao tópico de violin101 em Javascript
Para exibir um logo quando a tabela estiver vazia, você pode: 1 - Adicionar uma div com o logo abaixo da tabela: <table id="tbventas"> <tbody></tbody> </table> <div id="empty-table-logo" style="text-align:center;"> <img src="caminho/logo.png" alt="Logo empresa"> </div> 2 - Controlar a visibilidade via JavaScript: // Função para verificar se tabela está vazia function checkTableEmpty() { const tbody = document.querySelector("#tbventas tbody"); const logo = document.getElementById("empty-table-logo"); if (tbody.children.length === 0) { logo.style.display = "block"; } else { logo.style.display = "none"; } } // Chamar após remover ou adicionar itens $("#tbventas tbody").append(html); checkTableEmpty(); // Na remoção de item $('.btn-remove-produto').click(function() { $(this).closest('tr').remove(); checkTableEmpty(); }); Chame checkTableEmpty() sempre que manipular a tabela para atualizar a visibilidade do logo. -
PHP+Codeigniter - Implementar o Input CÓDIGO ou ID do Produto
Williams Duarte respondeu ao tópico de violin101 em PHP
-
PHP+Codeigniter - Implementar o Input CÓDIGO ou ID do Produto
Williams Duarte respondeu ao tópico de violin101 em PHP
Primeiro, você não está declarando a variável timeoutId <script type="text/javascript"> $(document).ready(function(){ let timeoutId; // Declaração da variável $('#idProdutos').on('input', function() { clearTimeout(timeoutId); const idprd = $(this).val(); timeoutId = setTimeout(function() { if (idprd) { $.ajax({ url: "<?php echo base_url(); ?>vendas/pdvcaixa/buscarID", type: "POST", data: { idProdutos: idprd }, // Corrigido nome do parâmetro dataType: 'json', // Importante adicionar success: function(response) { if (response.success) { // Como o resultado é um array, pegamos o primeiro item if (response.produto.length > 0) { $("#descricao").val(response.produto[0].descricao); } } }, error: function(xhr, status, error) { console.log('Erro:', error); } }); } }, 1500); }); }); </script> No Controller, ajuste para: public function buscarID() { $idprd = $this->input->post('idProdutos'); $produto = $this->pdvcaixa_model->buscarCodigo($idprd); if ($produto) { echo json_encode([ 'success' => true, 'produto' => $produto ]); } else { echo json_encode([ 'success' => false, 'message' => 'Produto não encontrado' ]); } } Se ainda assim não funcionar, você pode adicionar alguns console.log para debug: $('#idProdutos').on('input', function() { console.log('Input detectado'); clearTimeout(timeoutId); const idprd = $(this).val(); console.log('Valor digitado:', idprd); timeoutId = setTimeout(function() { console.log('Timeout executado'); if (idprd) { // ... resto do código -
PHP+Codeigniter - Implementar o Input CÓDIGO ou ID do Produto
Williams Duarte respondeu ao tópico de violin101 em PHP
Para implementar a busca automática com delay de 1-2 segundos sem precisar do ENTER, você pode usar jQuery junto com CodeIgniter. Segue um exemplo simples: $('#codigo_produto').on('input', function() { clearTimeout(timeoutId); const codigo = $(this).val(); timeoutId = setTimeout(function() { if (codigo) { $.ajax({ url: '<?= base_url("produtos/buscar") ?>', type: 'POST', data: { codigo: codigo }, success: function(response) { // Exibe o resultado if (response.success) { $('#resultado').html(response.produto.descricao); } } }); } }, 1500); // 1.5 segundos de delay }); No seu controller: public function buscar() { $codigo = $this->input->post('codigo'); $produto = $this->produtos_model->buscar_por_codigo($codigo); echo json_encode([ 'success' => true, 'produto' => $produto ]); } O código acima vai esperar 1.5 segundos após o usuário parar de digitar antes de fazer a busca. Você pode ajustar o delay alterando o valor 1500 para qualquer outro valor em milissegundos. -
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP
-
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP
Neste caso tem que criar uma configuração dos níveis e seus formatos $nivel_config = [ 1 => ['length' => 2, 'format' => '%02d'], // 1.01 2 => ['length' => 3, 'format' => '%03d'], // 1.01.001 3 => ['length' => 4, 'format' => '%04d'], // 1.01.001.0001 4 => ['length' => 5, 'format' => '%05d'] // 1.01.001.0001.00001 (caso precise e por ai vai) ]; public function getNextCode($parent_code = null) { log_message('debug', '=== INÍCIO getNextCode ==='); log_message('debug', 'Parent Code: ' . ($parent_code ?? 'NULL')); // Configuração dos níveis e seus formatos $nivel_config = [ 1 => ['length' => 2, 'format' => '%02d'], // 1.01 2 => ['length' => 3, 'format' => '%03d'], // 1.01.001 3 => ['length' => 4, 'format' => '%04d'], // 1.01.001.0001 4 => ['length' => 5, 'format' => '%05d'] // 1.01.001.0001.00001 (caso precise e por ai vai) ]; if (!$parent_code) { $query = $this->db->select('MAX(CAST(pl_idconta AS UNSIGNED)) as max_code') ->from('planocontas') ->where('pl_idconta NOT LIKE "%.%"') ->get(); $result = $query->row(); $next_code = ($result->max_code ?? 0) + 1; log_message('debug', 'Gerando código raiz: ' . $next_code); return $next_code; } $parent_parts = explode('.', $parent_code); $nivel = count($parent_parts); log_message('debug', 'Nível hierárquico: ' . $nivel); // Verifica se o nível é suportado if (!isset($nivel_config[$nivel])) { log_message('error', 'Nível não suportado: ' . $nivel); return false; } $query = $this->db->select('pl_idconta') ->from('planocontas') ->like('pl_idconta', $parent_code . '.', 'after') ->order_by('pl_idconta', 'DESC') ->limit(1) ->get(); log_message('debug', 'SQL executado: ' . $this->db->last_query()); if ($query->num_rows() == 0) { // Primeiro subcódigo deste nível $new_code = $parent_code . '.' . sprintf($nivel_config[$nivel]['format'], 1); log_message('debug', 'Primeiro subcódigo deste pai: ' . $new_code); return $new_code; } $ultimo_codigo = $query->row()->pl_idconta; $partes = explode('.', $ultimo_codigo); $ultimo_numero = (int)end($partes); log_message('debug', sprintf( 'Último código: %s | Último número: %s', $ultimo_codigo, $ultimo_numero )); // Gera próximo código usando a configuração do nível $proximo = sprintf($nivel_config[$nivel]['format'], $ultimo_numero + 1); $final_code = $parent_code . '.' . $proximo; log_message('debug', 'Código gerado: ' . $final_code); log_message('debug', '=== FIM getNextCode ==='); return $final_code; } No controller, ajuste a função que busca os códigos pais public function novo() { $this->load->model('planocontas_model'); $max_nivel = 4; // Defina aqui o número máximo de níveis desejado $data['plcta'] = $this->db ->select('*') ->from('planocontas') ->where('pl_status', 1) ->where('CHAR_LENGTH(pl_idconta) - CHAR_LENGTH(REPLACE(pl_idconta, ".", "")) <', $max_nivel) ->order_by('pl_idconta') ->get() ->result(); $this->load->view('estilo/header', $this->data); $this->load->view('faturamento/planocontas/adicionarConta', $data); } -
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP
Aplique log e vai debugando public function getNextCode($parent_code = null) { log_message('debug', '=== INÍCIO getNextCode ==='); log_message('debug', 'Parent Code: ' . ($parent_code ?? 'NULL')); if (!$parent_code) { $query = $this->db->select('MAX(CAST(pl_idconta AS UNSIGNED)) as max_code') ->from('planocontas') ->where('pl_idconta NOT LIKE "%.%"') ->get(); $result = $query->row(); $next_code = ($result->max_code ?? 0) + 1; log_message('debug', 'Gerando código raiz: ' . $next_code); return $next_code; } $parent_parts = explode('.', $parent_code); $nivel = count($parent_parts); log_message('debug', 'Nível hierárquico: ' . $nivel); $query = $this->db->select('pl_idconta') ->from('planocontas') ->like('pl_idconta', $parent_code . '.', 'after') ->order_by('pl_idconta', 'DESC') ->limit(1) ->get(); log_message('debug', 'SQL executado: ' . $this->db->last_query()); if ($query->num_rows() == 0) { $new_code = ($nivel == 1) ? $parent_code . '.01' : $parent_code . '.0001'; log_message('debug', 'Primeiro subcódigo deste pai: ' . $new_code); return $new_code; } $ultimo_codigo = $query->row()->pl_idconta; $partes = explode('.', $ultimo_codigo); $ultimo_numero = end($partes); log_message('debug', sprintf( 'Último código: %s | Último número: %s', $ultimo_codigo, $ultimo_numero )); if ($nivel == 1) { $proximo = str_pad((int)$ultimo_numero + 1, 2, '0', STR_PAD_LEFT); } else { $proximo = str_pad((int)$ultimo_numero + 1, 4, '0', STR_PAD_LEFT); } $final_code = $parent_code . '.' . $proximo; log_message('debug', 'Código gerado: ' . $final_code); log_message('debug', '=== FIM getNextCode ==='); return $final_code; } Os logs serão gravados em application/logs/. Para visualizar, ative debug no config.php: $config['log_threshold'] = 2; // Debug Caso não consiga corrigir o código pelo debug, poste os logs aqui! Mas dei mais um ajuste! -
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP
O problema está na lógica do getNextCode(): Fiz uns ajustes, não tenho como testar, só olhei a doc por cima de como monta selects no CI, que é bem parecida com Query Builder do Laravel public function getNextCode($parent_code = null) { if (!$parent_code) { // Busca próximo código raiz $query = $this->db->select('MAX(CAST(pl_idconta AS UNSIGNED)) as max_code') ->from('planocontas') ->where('pl_idconta NOT LIKE "%.%"') ->get(); $result = $query->row(); return ($result->max_code ?? 0) + 1; } // Busca subcódigos do mesmo nível $parent_parts = explode('.', $parent_code); $nivel = count($parent_parts); $like_pattern = $parent_code . '.%'; $query = $this->db->select('pl_idconta') ->from('planocontas') ->like('pl_idconta', $like_pattern, 'after') ->get(); $codigos_mesmo_nivel = []; foreach ($query->result() as $row) { $parts = explode('.', $row->pl_idconta); if (count($parts) == $nivel + 1) { $codigos_mesmo_nivel[] = (int)end($parts); } } $proximo = empty($codigos_mesmo_nivel) ? 1 : max($codigos_mesmo_nivel) + 1; // Formata o número baseado no nível if ($nivel == 1) { // Nível 1.XX return $parent_code . '.' . str_pad($proximo, 2, '0', STR_PAD_LEFT); } else if ($nivel == 2) { // Nível 1.XX.XXXX return $parent_code . '.' . str_pad($proximo, 4, '0', STR_PAD_LEFT); } else { // Demais níveis return $parent_code . '.' . $proximo; } } Principais correções: Separação por níveis hierárquicos Contagem correta do próximo número Formatação específica para cada nível Exemplo de resultado: 1 - Principal 1.01 - Setor A 1.01.0001 - Subsetor A1 1.02 - Setor B 2 - Secundário 2.01 - Filial 1 Para fins de comparação # Plano de Contas - Correção na geração de códigos hierárquicos ## Alterações no método getNextCode() - Corrigida lógica de incremento dos níveis - Melhorada separação hierárquica - Adicionada formatação específica por nível ```diff public function getNextCode($parent_code = null) { - if (!$parent_code) { - $query = $this->db->select('MAX(SUBSTRING_INDEX(pl_idconta, ".", 1)) as max_code') - ->from('planocontas') - ->where('LENGTH(pl_idconta) = 1') - ->get(); + if (!$parent_code) { + // Busca próximo código raiz usando CAST para comparação numérica + $query = $this->db->select('MAX(CAST(pl_idconta AS UNSIGNED)) as max_code') + ->from('planocontas') + ->where('pl_idconta NOT LIKE "%.%"') + ->get(); $result = $query->row(); return ($result->max_code ?? 0) + 1; } - $like_pattern = $parent_code . '.%'; - $length = strlen($parent_code) + 3; + // Identificação do nível hierárquico atual + $parent_parts = explode('.', $parent_code); + $nivel = count($parent_parts); + // Busca subcódigos existentes no mesmo nível + $like_pattern = $parent_code . '.%'; $query = $this->db->select('MAX(SUBSTRING_INDEX(pl_idconta, ".", -1)) as max_code') ->from('planocontas') ->like('pl_idconta', $like_pattern, 'after') - ->where('LENGTH(pl_idconta) =', $length) ->get(); $result = $query->row(); - $next_number = str_pad(($result->max_code ?? 0) + 1, 2, '0', STR_PAD_LEFT); - return $parent_code . '.' . $next_number; + + // Formatação específica por nível + if ($nivel == 1) { + // Nível 1.XX + return $parent_code . '.' . str_pad($proximo, 2, '0', STR_PAD_LEFT); + } else if ($nivel == 2) { + // Nível 1.XX.XXXX + return $parent_code . '.' . str_pad($proximo, 4, '0', STR_PAD_LEFT); + } else { + // Demais níveis sem padding + return $parent_code . '.' . $proximo; + } } Principais mudanças: Código raiz (nível 0) Uso de CAST para comparação numérica correta Filtro aprimorado para códigos sem pontos Subcódigos Identificação do nível através de explode() Formatação específica para cada nível Remoção da restrição de LENGTH fixa Formatação Nível 1: XX (dois dígitos) Nível 2: XXXX (quatro dígitos) Demais níveis: sem padding -
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP
O campo parent_code é fundamental para criar a hierarquia do plano de contas. Vou mostrar um exemplo prático de formulário HTML e como ele funciona: <form method="post" action="<?php echo base_url('plano_contas/adicionar'); ?>"> <!-- Campo para código pai (parent_code) --> <div class="form-group"> <label>Código Pai:</label> <select name="parent_code" class="form-control"> <option value="">-- Selecione o código pai --</option> <?php foreach($codigos_pais as $codigo): ?> <option value="<?php echo $codigo->codigo; ?>"> <?php echo $codigo->codigo . ' - ' . $codigo->descricao; ?> </option> <?php endforeach; ?> </select> </div> <!-- Campo descrição --> <div class="form-group"> <label>Descrição:</label> <input type="text" name="descricao" class="form-control" required> </div> <button type="submit" class="btn btn-primary">Salvar</button> </form> Para exemplificar o funcionamento: Quando parent_code é vazio (null): Sistema gera: "1" (primeiro registro) Próximo será: "2" Quando parent_code é "1": Sistema gera: "1.01" Próximo será: "1.02" Quando parent_code é "1.01": Sistema gera: "1.01.0001" Próximo será: "1.01.0002" Aqui está o código atualizado do controller para buscar os códigos pais: public function novo() { // Carrega todos os códigos possíveis de serem pai $this->load->model('PlanoContasModel'); $data['codigos_pais'] = $this->db ->select('codigo, descricao') ->from('plano_contas') ->where('LENGTH(codigo) <=', 4) // Limita a 2 níveis (1 ou 1.01) ->order_by('codigo') ->get() ->result(); $this->load->view('plano_contas/formulario', $data); } Assim: Se você deixar o "Código Pai" vazio → Cria código raiz (1, 2, 3...) Se selecionar "1" como pai → Cria subcódigo (1.01, 1.02...) Se selecionar "1.01" como pai → Cria subcódigo (1.01.0001, 1.01.0002...) Vou ler depois sua mensagem! -
PHP+Codeigniter - Adicionar Registro Plano de Contas
Williams Duarte respondeu ao tópico de violin101 em PHP
Para implementar um sistema de numeração hierárquica automática no CodeIgniter, sugiro a seguinte solução, adapte a sua necessidade: // Model: PlanoContasModel.php class PlanoContasModel extends CI_Model { public function __construct() { parent::__construct(); $this->load->database(); } public function getNextCode($parent_code = null) { if (!$parent_code) { // Busca próximo código raiz (1, 2, 3...) $query = $this->db->select('MAX(SUBSTRING_INDEX(codigo, ".", 1)) as max_code') ->from('plano_contas') ->where('LENGTH(codigo) = 1') ->get(); $result = $query->row(); return ($result->max_code ?? 0) + 1; } else { // Busca próximo subcódigo $like_pattern = $parent_code . '.%'; $length = strlen($parent_code) + 3; $query = $this->db->select('MAX(SUBSTRING_INDEX(codigo, ".", -1)) as max_code') ->from('plano_contas') ->like('codigo', $like_pattern, 'after') ->where('LENGTH(codigo) =', $length) ->get(); $result = $query->row(); $next_number = str_pad(($result->max_code ?? 0) + 1, 2, '0', STR_PAD_LEFT); return $parent_code . '.' . $next_number; } } public function insert($data) { if (empty($data['parent_code'])) { $data['codigo'] = $this->getNextCode(); } else { $data['codigo'] = $this->getNextCode($data['parent_code']); } return $this->db->insert('plano_contas', [ 'codigo' => $data['codigo'], 'descricao' => $data['descricao'] ]); } } // Controller: PlanoContas.php class PlanoContas extends CI_Controller { public function __construct() { parent::__construct(); $this->load->model('PlanoContasModel'); } public function adicionar() { $data = [ 'descricao' => $this->input->post('descricao'), 'parent_code' => $this->input->post('parent_code') ]; $result = $this->PlanoContasModel->insert($data); if ($result) { echo json_encode(['success' => true]); } else { echo json_encode(['success' => false, 'error' => 'Erro ao inserir']); } } } Esta solução: Gera códigos automaticamente seguindo a hierarquia Suporta múltiplos níveis (1, 1.01, 1.01.01, etc.) Mantém o formato padronizado dos códigos Usa zero à esquerda para subcódigos (01, 02, etc.) Exemplo de uso: CREATE TABLE plano_contas ( id INT PRIMARY KEY AUTO_INCREMENT, codigo VARCHAR(20) UNIQUE, descricao VARCHAR(100) ); Para adicionar um registro, faça uma requisição POST com: descricao: Nome da conta parent_code: Código pai (opcional) -
Javascript - Passar Parâmetros para uma Função.
Williams Duarte respondeu ao tópico de violin101 em Javascript
Para passar parâmetros para uma função JS, você pode utilizar atributos de dados (data attributes) nos elementos HTML e, em seguida, acessar esses atributos no JavaScript para obter os valores desejados. Segue o exemplo de como você pode modificar seu código para passar os parâmetros usando JavaScript Modifique os botões "Visualizar" e "Editar" para incluir atributos de dados com os valores necessários: <button class="btn btn-warning" title="Visualizar" style="margin-left:50%; padding: 1px 3px;" data-id-pedido="<?php echo $r->idPedidos; ?>" data-nr-pedido="<?php echo $r->pd_numero; ?>" onclick="visualizarPedido(this)"><i class="fa fa-search icon-white"></i></button> <button class="btn btn-primary" title="Editar" style="margin-left:50%; padding: 1px 3px;" data-id-pedido="<?php echo $r->idPedidos; ?>" data-nr-pedido="<?php echo $r->pd_numero; ?>" onclick="editarPedido(this)"><i class="fa fa-edit icon-white"></i></button> Remova os formulários que envolvem os botões, pois não serão mais necessários. Adicione as seguintes funções JS no seu arquivo de JavaScript ou dentro de uma tag <script> na sua página: function visualizarPedido(button) { const idPedido = button.getAttribute('data-id-pedido'); const nrPedido = button.getAttribute('data-nr-pedido'); // Faça uma requisição Ajax para a URL desejada, passando os parâmetros const url = '<?= base_url() ?>compras/pedidos/visualizar?idPedido=' + idPedido + '&nrPedido=' + nrPedido; // Exemplo usando fetch: fetch(url) .then(response => response.text()) .then(data => { // Faça algo com a resposta recebida console.log(data); }) .catch(error => { console.error('Erro:', error); }); } function editarPedido(button) { const idPedido = button.getAttribute('data-id-pedido'); const nrPedido = button.getAttribute('data-nr-pedido'); // Faça uma requisição Ajax para a URL desejada, passando os parâmetros const url = '<?= base_url() ?>compras/pedidos/editar?idPedido=' + idPedido + '&nrPedido=' + nrPedido; // Exemplo usando fetch: fetch(url) .then(response => response.text()) .then(data => { // Faça algo com a resposta recebida console.log(data); }) .catch(error => { console.error('Erro:', error); }); } No exemplo, adicionamos atributos de dados aos botões para armazenar os valores necessários. No JavaScript, obtemos esses valores usando `getAttribute` e construímos a URL com os parâmetros. Em seguida, fazemos uma requisição Ajax para a URL usando `fetch` e lidamos com a resposta de acordo com as necessidades. Essa abordagem permite passar os parâmetros sem a necessidade de formulários adicionais. -
PHP+Codeigniter - Ajuda en NFePhp para Sistema
Williams Duarte respondeu ao tópico de violin101 em PHP
O erro Class NFePHP\NFe\Make not found acontece por causa de uma configuração incorreta do autoload do Composer. Par resolver isso: modifique seu composer.json para: { "description": "The CodeIgniter framework", "name": "codeigniter/framework", "type": "project", "homepage": "https://codeigniter.com", "license": "MIT", "require": { "php": ">=7.4", "mpdf/mpdf": "^7.1", "nfephp-org/sped-nfe": "^5.0", "nfephp-org/sped-da": "^1.0" }, "autoload": { "psr-4": { "App\\": "application/" } }, "config": { "vendor-dir": "vendor" } } No seu application/config/config.php, coloque: $config['composer_autoload'] = FCPATH . 'vendor/autoload.php'; Depois, no terminal, execute: composer clear-cache composer update composer dump-autoload -o Seu arquivo libraries/NfeService.php deve começar assim: <?php defined('BASEPATH') OR exit('No direct script access allowed'); use NFePHP\NFe\Make; use NFePHP\NFe\Tools; use NFePHP\Common\Certificate; use NFePHP\NFe\Common\Standardize; class NfeService { private $CI; private $config; private $tools; private $certificate; public function __construct() { $this->CI =& get_instance(); $this->CI->config->load('nfe'); $this->config = $this->CI->config->item('nfe'); $this->initialize(); } // ... resto do código Crie o arquivo application/config/nfe.php: <?php defined('BASEPATH') OR exit('No direct script access allowed'); $config['nfe'] = [ 'atualizacao' => date('Y-m-d H:i:s'), 'tpAmb' => 2, // 1-Produção; 2-Homologação 'razaosocial' => 'Sua Empresa', 'siglaUF' => 'SP', // Seu estado 'cnpj' => '00000000000000', // Seu CNPJ 'schemes' => 'PL_009_V4', 'versao' => '4.00', 'pathNFeFiles' => APPPATH . 'nfe_files/', 'pathCertsFiles' => APPPATH . 'certificates/', 'certFile' => 'certificado.pfx', 'certPassword' => 'senha_certificado' ]; Crie as pastas necessárias: application/ ├── nfe_files/ └── certificates/ PHP tem ser 7.4 ou superior Para testar se está funcionando, crie um arquivo test.php na raiz: <?php require 'vendor/autoload.php'; try { $nfe = new NFePHP\NFe\Make(); echo "NFe class loaded successfully!"; } catch (Exception $e) { echo "Error: " . $e->getMessage(); } Um controlador básico para teste: <?php defined('BASEPATH') OR exit('No direct script access allowed'); class Nfe extends CI_Controller { public function __construct() { parent::__construct(); $this->load->library('NfeService'); } public function teste() { try { $nfe = new \NFePHP\NFe\Make(); echo "NFe class loaded successfully!"; } catch (Exception $e) { echo "Error: " . $e->getMessage(); } } } Algumas verificações adicionais se ainda houver problemas: Verifique se a pasta vendor existe e contém os arquivos do NFePHP Confira as permissões das pastas (755 para diretórios, 644 para arquivos) Certifique-se de que o index.php na raiz tem a linha: require_once __DIR__ . '/vendor/autoload.php'; Se ainda persistir o erro, execute: composer show | grep nfephp E verifique se as bibliotecas estão listadas corretamente. O erro geralmente é resolvido seguindo esses passos. -
PHP+Codeigniter - Ajuda en NFePhp para Sistema
Williams Duarte respondeu ao tópico de violin101 em PHP
Um passo a passo detalhado para implementar a emissão de NFe usando NFePHP no CodeIgniter. // application/config/nfe.php <?php $config['nfe'] = [ 'atualizacao' => date('Y-m-d H:i:s'), 'tpAmb' => 2, // 1-Produção; 2-Homologação 'razaosocial' => 'Empresa Teste', 'siglaUF' => 'SP', 'cnpj' => '00000000000000', 'schemes' => 'PL_009_V4', 'versao' => '4.00', 'pathNFeFiles' => APPPATH . 'nfe_files/', 'pathCertsFiles' => APPPATH . 'certificates/', 'certFile' => 'certificado.pfx', 'certPassword' => 'senha_certificado' ]; // application/libraries/NfeService.php <?php defined('BASEPATH') OR exit('No direct script access allowed'); use NFePHP\NFe\Make; use NFePHP\NFe\Tools; use NFePHP\Common\Certificate; use NFePHP\NFe\Common\Standardize; class NfeService { private $CI; private $config; private $tools; private $certificate; public function __construct() { $this->CI =& get_instance(); $this->CI->config->load('nfe'); $this->config = $this->CI->config->item('nfe'); $this->initialize(); } private function initialize() { try { // Carrega o certificado $certPath = $this->config['pathCertsFiles'] . $this->config['certFile']; $this->certificate = Certificate::readPfx( file_get_contents($certPath), $this->config['certPassword'] ); // Inicializa as ferramentas $this->tools = new Tools( json_encode($this->config), $this->certificate ); // Configura o ambiente $this->tools->setEnvironment($this->config['tpAmb']); } catch (Exception $e) { log_message('error', 'NFe initialization error: ' . $e->getMessage()); throw new Exception('Erro ao inicializar NFe: ' . $e->getMessage()); } } public function emitirNFe($dados) { try { // Cria o XML $nfe = new Make(); // Informações da Nota $std = new \stdClass(); $std->versao = '4.00'; $nfe->taginfNFe($std); // Identificação da Nota $std = new \stdClass(); $std->cUF = 35; // Código do estado (SP = 35) $std->natOp = 'VENDA'; $std->mod = 55; // Modelo da NFe $std->serie = 1; $std->nNF = $dados['numero_nf']; // Número da nota $std->dhEmi = date('Y-m-d\TH:i:sP'); $std->tpNF = 1; // 1=Saída $std->idDest = 1; // 1=Operação interna $std->cMunFG = '3550308'; // Código do município (São Paulo) $std->tpImp = 1; // 1=DANFE retrato $std->tpEmis = 1; // 1=Emissão normal $std->tpAmb = $this->config['tpAmb']; $std->finNFe = 1; // 1=NFe normal $std->indFinal = 1; // 1=Consumidor final $std->indPres = 1; // 1=Operação presencial $std->procEmi = 0; // 0=Emissão de NF-e com aplicativo do contribuinte $std->verProc = '1.0'; $nfe->tagide($std); // Emitente $std = new \stdClass(); $std->xNome = $this->config['razaosocial']; $std->CNPJ = $this->config['cnpj']; $std->IE = '123456789'; $std->CRT = 3; // 3=Regime normal $std->xLgr = 'Rua Teste'; $std->nro = '123'; $std->xBairro = 'Centro'; $std->cMun = '3550308'; // São Paulo $std->xMun = 'Sao Paulo'; $std->UF = 'SP'; $std->CEP = '01001001'; $std->cPais = '1058'; $std->xPais = 'Brasil'; $nfe->tagemit($std); // Destinatário $std = new \stdClass(); $std->xNome = $dados['cliente']['nome']; $std->CNPJ = $dados['cliente']['cnpj']; $std->IE = $dados['cliente']['ie']; $std->xLgr = $dados['cliente']['endereco']; $std->nro = $dados['cliente']['numero']; $std->xBairro = $dados['cliente']['bairro']; $std->cMun = $dados['cliente']['cod_municipio']; $std->xMun = $dados['cliente']['municipio']; $std->UF = $dados['cliente']['uf']; $std->CEP = $dados['cliente']['cep']; $std->cPais = '1058'; $std->xPais = 'Brasil'; $nfe->tagdest($std); // Produtos foreach ($dados['produtos'] as $i => $produto) { $std = new \stdClass(); $std->item = $i + 1; $std->cProd = $produto['codigo']; $std->xProd = $produto['descricao']; $std->NCM = $produto['ncm']; $std->CFOP = $produto['cfop']; $std->uCom = $produto['unidade']; $std->qCom = $produto['quantidade']; $std->vUnCom = $produto['valor_unitario']; $std->vProd = $produto['valor_total']; $nfe->tagprod($std); // Impostos do produto $std = new \stdClass(); $std->item = $i + 1; $std->vTotTrib = 0.00; $nfe->tagimposto($std); } // Totais $std = new \stdClass(); $std->vBC = $dados['total']['base_calculo']; $std->vICMS = $dados['total']['valor_icms']; $std->vProd = $dados['total']['valor_produtos']; $std->vNF = $dados['total']['valor_nota']; $nfe->tagICMSTot($std); // Transporte $std = new \stdClass(); $std->modFrete = 9; // 9=Sem frete $nfe->tagtransp($std); // Gera o XML $xml = $nfe->getXML(); // Assina o XML $xml = $this->tools->signNFe($xml); // Envia para SEFAZ $response = $this->tools->sefazEnviaLote([$xml]); // Processa resposta $stdResponse = new Standardize($response); $arrayResponse = $stdResponse->toArray(); // Consulta recibo if (isset($arrayResponse['infRec']['nRec'])) { $recibo = $arrayResponse['infRec']['nRec']; $protocolo = $this->tools->sefazConsultaRecibo($recibo); // Guarda XML e protocolo $this->salvarXml($xml, $protocolo, $dados['numero_nf']); } return $arrayResponse; } catch (Exception $e) { log_message('error', 'NFe emission error: ' . $e->getMessage()); throw new Exception('Erro ao emitir NFe: ' . $e->getMessage()); } } private function salvarXml($xml, $protocolo, $numero) { $path = $this->config['pathNFeFiles']; $filename = $numero . '_' . date('Y-m-d_H-i-s') . '.xml'; if (!is_dir($path)) { mkdir($path, 0777, true); } file_put_contents($path . $filename, $xml); file_put_contents($path . 'protocolo_' . $filename, $protocolo); } } // application/controllers/Nfe.php <?php defined('BASEPATH') OR exit('No direct script access allowed'); class Nfe extends CI_Controller { public function __construct() { parent::__construct(); $this->load->library('NfeService'); } public function emitir() { try { // Dados de exemplo - você deve adaptar para seus dados reais $dados = [ 'numero_nf' => '1', 'cliente' => [ 'nome' => 'Cliente Teste', 'cnpj' => '00000000000000', 'ie' => '123456789', 'endereco' => 'Rua Teste', 'numero' => '123', 'bairro' => 'Centro', 'cod_municipio' => '3550308', 'municipio' => 'Sao Paulo', 'uf' => 'SP', 'cep' => '01001001' ], 'produtos' => [ [ 'codigo' => '001', 'descricao' => 'Produto Teste', 'ncm' => '84714900', 'cfop' => '5102', 'unidade' => 'UN', 'quantidade' => 1, 'valor_unitario' => 100.00, 'valor_total' => 100.00 ] ], 'total' => [ 'base_calculo' => 100.00, 'valor_icms' => 18.00, 'valor_produtos' => 100.00, 'valor_nota' => 100.00 ] ]; $response = $this->nfeservice->emitirNFe($dados); // Retorna resposta em JSON $this->output ->set_content_type('application/json') ->set_output(json_encode([ 'status' => 'success', 'data' => $response ])); } catch (Exception $e) { $this->output ->set_content_type('application/json') ->set_output(json_encode([ 'status' => 'error', 'message' => $e->getMessage() ])); } } } Para implementar este código, siga estes passos: 1. Primeiro, instale o NFePHP via Composer: composer require nfephp-org/sped-nfe 2. Crie os diretórios necessários: - application/nfe_files/ - para armazenar os XMLs gerados - application/certificates/ - para armazenar o certificado digital 3. Configure o arquivo application/config/nfe.php com seus dados: - Altere os dados da empresa - Configure o ambiente (homologação/produção) - Defina o caminho e senha do certificado 4. Adapte o modelo de dados no controller para sua estrutura de banco de dados. Pontos importantes: 1. Certificado Digital: - Você precisa ter um certificado digital A1 válido - Configure corretamente o caminho e senha no arquivo de configuração 2. Ambiente: - Comece usando o ambiente de homologação (tpAmb = 2) - Teste extensivamente antes de mudar para produção 3. Validações: - Adicione validações para todos os campos obrigatórios - Verifique as regras de negócio específicas do seu estado 4. Tratamento de Erros: - Implemente logs detalhados - Trate adequadamente as exceções - Armazene os retornos da SEFAZ 5. Melhorias Sugeridas: - Implementar fila de processamento para notas - Adicionar sistema de contingência - Criar rotinas de consulta de status - Implementar cancelamento de notas Você pode chamar a emissão assim: $response = $this->nfeservice->emitirNFe($dados); Este é um exemplo básico que você pode adaptar às suas necessidades. Recomendo: 1. Teste primeiro em homologação 2. Implemente gradualmente 3. Documente todas as alterações 4. Mantenha backup dos XMLs 5. Implemente validações rigorosas -
PHP+Codeigniter - Importar Dados de uma Tabela para outra - MySql
Williams Duarte respondeu ao tópico de violin101 em PHP
Entendi, porém, sugiro algumas melhorias que podem tornar seu sistema ainda mais robusto, so terá que codificar mais: 1 - Implementar um sistema de comparação automática entre o que foi pedido e o que foi comprado. Assim, quando Compras registrar um item com especificação diferente (como o saco P6 ao invés do P8), o sistema já alertaria automaticamente. 2 - Adicionar um sistema de rastreabilidade onde cada operação (pedido do Almoxarifado e compra do setor de Compras) fique registrada com data, hora e responsável. Isso evita o "disse-me-disse" e deixa claro quem tomou cada decisão. 3 - Criar relatórios que mostrem claramente as divergências entre pedidos e compras, facilitando a gestão e resolução de problemas. 4 - Implementar notificações automáticas quando houver divergências, assim o Almoxarifado seria avisado imediatamente se Compras registrar um produto com especificação diferente da solicitada. Dessa forma, você mantém a separação que deseja (que faz sentido para seu caso), mas adiciona camadas de controle que tornam o processo mais seguro e transparente. -
PHP+Codeigniter - Importar Dados de uma Tabela para outra - MySql
Williams Duarte respondeu ao tópico de violin101 em PHP
Duplicando dados, nada mais que isto! Correto é como @tetsuo disse, referencie uma chave, que pode ser pedido_id CREATE TABLE lancamentos ( id INT PRIMARY KEY, pedido_id INT, data_lancamento DATETIME, FOREIGN KEY (pedido_id) REFERENCES pedidos(id) ); na model: class LancamentoModel extends CI_Model { public function criarLancamento($pedido_id) { $dados = [ 'pedido_id' => $pedido_id, 'data_lancamento' => date('Y-m-d H:i:s') ]; $this->db->insert('lancamentos', $dados); } } Se precisar visualizar dados consolidados, crie uma view CREATE VIEW view_lancamentos AS SELECT l.id as lancamento_id, p.codigoProduto, p.quantidade, p.valorUnitario, l.data_lancamento FROM lancamentos l JOIN pedidos p ON l.pedido_id = p.id; para obter o id na view public function buscarPorProduto($codigo_produto) { $this->db->from('view_lancamentos'); $this->db->where('codigoProduto', $codigo_produto); return $this->db->get()->result_array(); } E ao inves de fazer todo este processo de importação, faça o automaticamente. class PedidoModel extends CI_Model { public function cadastrar($dados) { // Inicia a transaction $this->db->trans_start(); try { // Insere na tabela de pedidos $this->db->insert('pedidos', [ 'codigoProduto' => $dados['codigoProduto'], 'quantidade' => $dados['quantidade'], 'valorUnitario' => $dados['valorUnitario'], 'status' => 'novo' ]); $pedido_id = $this->db->insert_id(); // Insere na tabela de lançamentos $this->db->insert('lancamentos', [ 'pedido_id' => $pedido_id, 'data_lancamento' => date('Y-m-d H:i:s') ]); // Commit da transaction $this->db->trans_complete(); return $pedido_id; } catch (Exception $e) { // Rollback em caso de erro $this->db->trans_rollback(); log_message('error', 'Erro ao cadastrar pedido: ' . $e->getMessage()); return false; } } } -
Certifique-se de que o relacionamento studentRelation está definido corretamente no modelo StudentDisciplineClassroom. Deve ser algo assim: public function studentRelation() { return $this->belongsTo(Student::class, 'ra', 'academic_registration'); } ao usar select('student'), você está limitando as colunas retornadas apenas para 'student'. Isso pode estar causando problemas no carregamento do relacionamento. Tente remover o select ou incluir a coluna 'ra': $all = $sdc::with('studentRelation') ->where('classroom', $request->classroom) ->distinct('student') ->get(); Uso do distinct: O distinct('student') pode estar interferindo no carregamento do relacionamento. Tente remover o distinct ou use groupBy em vez disso: $all = $sdc::with('studentRelation') ->where('classroom', $request->classroom) ->groupBy('student') ->get(); E certifique-se de que existem registros correspondentes na tabela students para os valores de 'ra' na tabela StudentDisciplineClassroom. Se você quiser carregar apenas alguns campos específicos do relacionamento, pode usar o carregamento ávido (eager loading) com restrições: $all = $sdc::with(['studentRelation:id,academic_registration,nome']) ->where('classroom', $request->classroom) ->get(); E por fim, para entender melhor o que está acontecendo, você pode usar o método toSql() para ver a consulta SQL gerada: $query = $sdc::with('studentRelation') ->where('classroom', $request->classroom); dd($query->toSql(), $query->getBindings()); Isso mostrará a consulta SQL e os parâmetros vinculados, o que pode ajudar a identificar problemas na consulta.
-
PHP - Passar valor para o INPUT vindo do AJAX em formato moeda
Williams Duarte respondeu ao tópico de violin101 em PHP
double 10,2 para mysql, postgres, float para mongodb etc -
PHP - Passar valor para o INPUT vindo do AJAX em formato moeda
Williams Duarte respondeu ao tópico de violin101 em PHP
Explicando: O erro ocorre porque você está comparando strings em vez de números, e na comparação de strings, "2.00" é considerado maior que "123.45" (porque a comparação é feita caractere por caractere, e "2" vem depois de "1" alfabeticamente). Para resolver este problema, precisa garantir que está trabalhando com números em vez de strings, e que esta usando o formato correto para comparação. Vou sugerir uma solução que mantém o formato brasileiro para exibição, mas usa o formato com ponto para cálculos internos. // Função para formatar número para o formato brasileiro function formatarNumero(numero) { return numero.toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } // Função para converter string no formato brasileiro para número function converterParaNumero(str) { return parseFloat(str.replace('.', '').replace(',', '.')); } // Modifique a função existente $(document).on("click", ".btn-prod", function() { prds = $(this).val(); infoprd = prds.split("*"); $("#idProdutos").val(infoprd[0]); $("#cod_interno").val(infoprd[1]); $("#descricao").val(infoprd[2]); $("#prd_unid").val(infoprd[3]); // Armazena o valor numérico em um atributo data- var estoqueNumerico = parseFloat(infoprd[4]); $("#estoque_atual").val(formatarNumero(estoqueNumerico)) .data('valor-numerico', estoqueNumerico); $("#modal_prod").modal("hide"); statusLimparAgregar(); }); // Função para validar o consumo function validarConsumo() { var estoqueAtual = $("#estoque_atual").data('valor-numerico'); var consumo = converterParaNumero($("#campo_consumo").val()); if (consumo > estoqueAtual) { alert("O consumo não pode ser maior que o estoque atual."); return false; } return true; } // Adicione este evento ao campo de consumo $("#campo_consumo").on('blur', function() { $(this).val(formatarNumero(converterParaNumero($(this).val()))); }); // Use esta função no submit do formulário $("form").on('submit', function(e) { if (!validarConsumo()) { e.preventDefault(); // Impede o envio do formulário se a validação falhar } }); Explicação das modificações: formatarNumero(): Formata um número para o estilo brasileiro (123,45). converterParaNumero(): Converte uma string no formato brasileiro para um número. Na função de click do produto, armazenamos o valor numérico do estoque em um atributo data- e exibir o valor formatado no campo. validarConsumo(): Compara o consumo com o estoque atual, ambos como números. Adicionado um evento blur ao campo de consumo para formatá-lo automaticamente. Adicionado uma validação no submit do formulário. Com essas modificações, você pode: Exibir os números no formato brasileiro (123,45). Armazenar internamente os valores como números para comparações corretas. Validar se o consumo é maior que o estoque atual. Lembre-se de ajustar os IDs dos campos (#campo_consumo, por exemplo) para corresponder aos seus IDs reais no HTML. Além disso, no PHP, quando for salvar os dados no banco de dados, você precisará converter o valor de volta para o formato com ponto: $consumo = str_replace(',', '.', $_POST['campo_consumo']); Isso garantirá que o valor seja salvo corretamente no MySQL. Esta abordagem deve resolver o problema de comparação, mantendo a exibição no formato brasileiro e permitindo cálculos e comparações precisas. -
PHP - Passar valor para o INPUT vindo do AJAX em formato moeda
Williams Duarte respondeu ao tópico de violin101 em PHP
Existem funções nativas tanto em PHP quanto em JavaScript que podem ajudar na formatação de números para moeda. Vou listar algumas das funções mais úteis para esse propósito em ambas as linguagens. PHP // 1. number_format() $numero = 1234.56; echo number_format($numero, 2, ',', '.'); // Saída: 1.234,56 // 2. money_format() (Obsoleta a partir do PHP 7.4) // Nota: Esta função foi removida no PHP 8.0 setlocale(LC_MONETARY, 'pt_BR'); $numero = 1234.56; echo money_format('%.2n', $numero); // Saída: R$ 1.234,56 // 3. NumberFormatter (intl extension) $formatter = new NumberFormatter('pt_BR', NumberFormatter::CURRENCY); echo $formatter->formatCurrency(1234.56, 'BRL'); // Saída: R$ 1.234,56 // 4. str_replace() (para substituir ponto por vírgula) $numero = 1234.56; echo str_replace('.', ',', number_format($numero, 2)); // Saída: 1234,56 JS // 1. toFixed() let numero = 1234.56; console.log(numero.toFixed(2)); // Saída: "1234.56" // 2. toLocaleString() let numero = 1234.56; console.log(numero.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })); // Saída: "R$ 1.234,56" // 3. Intl.NumberFormat let formatter = new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', }); console.log(formatter.format(1234.56)); // Saída: "R$ 1.234,56" // 4. replace() (para substituir ponto por vírgula) let numero = 1234.56; console.log(numero.toFixed(2).replace('.', ',')); // Saída: "1234,56" -
Para fazer isso, você pode apenas criar o arquivo categoria.php diretamente na raiz do seu site e configurar o .htaccess da seguinte forma, sem a necessidade de marcarção ou tags: RewriteEngine On RewriteBase / RewriteRule ^categoria/?$ categoria.php [L] No arquivo categoria.php, você pode adicionar o texto ou lógica que desejar. Se você acessar teste.com.br/categoria/, o servidor automaticamente irá direcionar para o conteúdo do arquivo categoria.php. <?php echo "Bem-vindo à página de categorias!"; ?> Outra forma de criar a URL teste.com.br/categoria/ sem a necessidade de criar uma pasta física seria configurando o seu servidor web diretamente, dependendo do servidor que você está utilizando. Vou explicar para os servidores Apache e Nginx: Apache <VirtualHost *:80> ServerName teste.com.br DocumentRoot /caminho/para/sua/pasta/public <Directory /caminho/para/sua/pasta/public> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> # Redireciona /categoria para categoria.php <Location /categoria> SetHandler application/x-httpd-php Action application/x-httpd-php /categoria.php </Location> </VirtualHost> Nginx server { listen 80; server_name teste.com.br; root /caminho/para/sua/pasta/public; location /categoria { rewrite ^/categoria/?$ /categoria.php last; } location / { try_files $uri $uri/ =404; } }
-
Faça a "image scraping" function getPreviewImage($url) { // Obter o conteúdo da página $html = file_get_contents($url); // Criar um novo objeto DOMDocument $doc = new DOMDocument(); @$doc->loadHTML($html); // Procurar pela tag meta og:image $tags = $doc->getElementsByTagName('meta'); foreach ($tags as $tag) { if ($tag->getAttribute('property') == 'og:image') { return $tag->getAttribute('content'); } } // Se não encontrar og:image, procurar pela primeira imagem na página $tags = $doc->getElementsByTagName('img'); if ($tags->length > 0) { return $tags->item(0)->getAttribute('src'); } // Se não encontrar nenhuma imagem, retornar null return null; } // Uso: $url = "https://example.com/article"; $imageUrl = getPreviewImage($url); if ($imageUrl) { echo "<img src='$imageUrl' alt='Preview'>"; } else { echo "Nenhuma imagem encontrada"; }
-
PHP - Mostrar resultado tabela por Intervalo de meses
Williams Duarte respondeu ao tópico de violin101 em PHP
Não conheço muito de codeigniter, uso mais o Laravel mas tem sitaxe bem parecidas, tente assim: public function agrupar($id, $intervaloMeses = 3){ $this->db->select('lctos_itens.*, DATE_FORMAT(dateItens, "%Y-%m-01") AS data_inicio, LAST_DAY(dateItens) AS data_fim, SUM(lctos_itens.qtd_prod) as quantidade, produtos.*'); $this->db->from('lctos_itens'); $this->db->join('produtos', 'produtos.idProdutos = lctos_itens.cod_prod'); $this->db->where('lctos_itens.cod_prod', $id); $this->db->group_by('YEAR(dateItens), MONTH(dateItens)'); $this->db->order_by('dateItens', 'DESC'); $this->db->limit($intervaloMeses); return $this->db->get()->result(); } <div class="tab-pane fade" id="agrupar" role="tabpanel" aria-labelledby="agrupar-tab"> <div class="txtProd"> <?php echo $result->cod_interno; ?> - <?php echo $result->descricao; ?> </div> <div class="card-body"> <div class="row"> <div class="col-md-" id="divRelac" style="padding: 1%; margin-left:0px;"> <table class="table" id="tab_prods"> <thead> <tr style="background-color:#BDDCDC;"> <th style="text-align:center;">Período</th> <th style="text-align:center;">Quantidade</th> </tr> </thead> <tbody> <?php foreach ($agrupar as $ag): ?> <tr> <td style="text-align:center;"> <?php echo date('m/Y', strtotime($ag->data_inicio)); ?> - <?php echo date('m/Y', strtotime($ag->data_fim)); ?> </td> <td style="text-align:center;"><?php echo $ag->quantidade; ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> </div> </div> <div class="card-footer" style="text-align:center;"> <a href="<?php echo base_url() ?>estoque/produtos" class="btn btn-danger"> <i class="fa fa-undo"></i> Voltar </a> </div> </div> -
PHP - Mostrar resultado tabela por Intervalo de meses
Williams Duarte respondeu ao tópico de violin101 em PHP
https://ideone.com/VTEI1I <?php function agruparPorIntervalo($dados, $intervaloMeses = 3) { $resultado = []; foreach ($dados as $entrada) { $produto = $entrada['produto']; $data = new DateTime($entrada['data']); $chaveIntervalo = $data->format('Y') . '-' . ceil($data->format('n') / $intervaloMeses); if (!isset($resultado[$produto][$chaveIntervalo])) { $resultado[$produto][$chaveIntervalo] = [ 'quantidade' => 0, 'inicio' => clone $data, 'fim' => (clone $data)->modify('+' . ($intervaloMeses - 1) . ' months')->modify('last day of this month'), ]; } $resultado[$produto][$chaveIntervalo]['quantidade'] += $entrada['quantidade']; } return $resultado; } // Exemplo de uso $entradas = [ ['produto' => 'Prod_A', 'quantidade' => 100, 'data' => '2024-01-15'], ['produto' => 'Prod_A', 'quantidade' => 120, 'data' => '2024-03-20'], ['produto' => 'Prod_A', 'quantidade' => 105, 'data' => '2024-04-10'], ['produto' => 'Prod_B', 'quantidade' => 105, 'data' => '2024-02-05'], ['produto' => 'Prod_B', 'quantidade' => 120, 'data' => '2024-03-15'], ['produto' => 'Prod_B', 'quantidade' => 130, 'data' => '2024-04-25'], ]; $resultadoAgrupado = agruparPorIntervalo($entradas); // Exibir resultado foreach ($resultadoAgrupado as $produto => $intervalos) { echo "Produto: $produto\n"; foreach ($intervalos as $intervalo) { echo " Quantidade: {$intervalo['quantidade']}, "; echo "Período: {$intervalo['inicio']->format('m/Y')} - {$intervalo['fim']->format('m/Y')}\n"; } echo "========================\n"; } -
PHP - Ajuda com NFePhp - mistério em achar caminho
Williams Duarte respondeu ao tópico de violin101 em PHP
Você instalou este pacote? https://github.com/nfephp-org/sped-nfe/blob/master/src/Make.php porque a classe existe, de uma olhada na pasta vendor! -
PHP - Ajuda com NFePhp - mistério em achar caminho
Williams Duarte respondeu ao tópico de violin101 em PHP
No seu arquivo application/config/config.php, ajuste a configuração do Composer autoload para: $config['composer_autoload'] = FCPATH . 'vendor/autoload.php'; Se você ainda tiver problemas, tente usar o nome completo $nfe = new \NFePHP\NFe\Make(); Certifique-se de que o CodeIgniter está configurado para mostrar erros. No arquivo application/config/config.php, defina: $config['log_threshold'] = 4; E no index.php na raiz do projeto, certifique-se de que está definido para o ambiente de desenvolvimento: define('ENVIRONMENT', 'development'); Se o problema persistir, tente adicionar isso no topo do seu controller, logo após a declaração da classe: require_once FCPATH . 'vendor/autoload.php'; Verifique se as permissões de arquivo estão corretas e se o PHP tem acesso de leitura à pasta vendor. Se ainda não funcionar, tente executar composer dump-autoload na raiz do projeto. Se após essas tentativas você ainda estiver tendo problemas, por favor, forneça o erro exato que está recebendo. Isso nos ajudará a identificar melhor o problema.