Artigo original: https://www.freecodecamp.org/news/making-an-awesome-inventory-management-application-in-php-and-mysql-from-start-to-finish-90bc5996680a/

Escrito por: Richard

Você não precisa de software corporativo inchado para rastrear seu estoque com eficiência. Este tutorial ajudará você a desenvolver sua própria aplicação de rastreamento de estoque personalizada para que você possa tomar decisões de inventário inteligentes com base em dados de estoque precisos e oportunos.

Requisitos do sistema

Nosso sistema de estoque requer a licença comercial padrão do phpGrid e do phpChart. Ele precisa de alguns recursos avançados de ambos os componentes.

  • PHP 5.6+(PHP 7.x é agora altamente recomendado!)
  • MySQL / MariaDB
  • phpGrid Lite (subgrid) -ou- phpGrid Enterprise (Master detail, Grouping)
  • phpChart (para relatórios)

O que é um sistema de gerenciamento de estoque

Também conhecido como sistema de gerenciamento de inventário, esse sistema tem vários componentes críticos. Em sua essência, o controle de estoque funciona rastreando as duas principais funções de um armazém: recebimento (entrada) e expedição (saída). Outras atividades, como a movimentação ou a realocação de estoque, também ocorrem. As matérias-primas são decrementadas e os produtos acabados são incrementados.

Projeto de banco de dados do sistema de estoque

Normalmente, um sistema de estoque tem quatro elementos básicos: produtos, compras, pedidos e fornecedores. Cada elemento deve ser rastreado com base em sua localização, SKU (sigla de Stock Keeping Unit – unidade de manutenção de estoque, em português) e quantidade. O estoque atual (os produtos disponíveis) é atualizado rastreando as remessas recebidas e os pedidos enviados. Os alertas de pedidos podem ser configurados para serem acionados quando os níveis de estoque ficarem abaixo dos níveis mínimos definidos pelo cliente.

ZH5FJWHyUxVNeNFNMqOKPwde7lqBS5Lwvtkp

Configurando o banco de dados do gerenciador de estoque

Baixe o script de SQL InventoryManager.sql do repositório do GitHub deste tutorial e execute o script usando uma ferramenta de MySQL, como o MySQL Workbench. Isso criará um banco de dados chamado InventoryManager, bem como as tabelas necessárias para este tutorial.

Uma nota sobre o ZenBase

O sistema de gerenciamento de estoque é um dos muitos modelos de aplicações disponíveis no ZenBase (construído sobre o phpGrid) para qualquer pessoa – com ou sem habilidades em programação – usar e personalizar para suas próprias necessidades.

Configurar phpGrid

Vamos continuar.

Usaremos um componente de datagrid (em português, grade de dados) do phpGrid para lidar com todas as operações CRUD (Criar, Remover, Atualizar e Excluir) do banco de dados interno.

Não se esqueça de baixar uma cópia do phpGrid antes de continuar.

Para instalar o phpGrid, siga estes passos:

  1. Descompacte o arquivo de download do phpGrid.
  2. Carregue a pasta phpGrid para a pasta do phpGrid.
  3. Conclua a instalação configurando o arquivo conf.php.

Antes de começarmos, devemos incluir as seguintes informações no arquivo conf.php de configuração do phpGrid.

define('PHPGRID_DB_HOSTNAME', 'localhost'); //  nome do host
define('PHPGRID_DB_USERNAME', 'root'); // nome de usuário do banco de dados
define('PHPGRID_DB_PASSWORD', ''); // senha do banco de dados
define('PHPGRID_DB_NAME', 'InventoryManager'); // nome do banco de dados do gerenciador de estoque
define('PHPGRID_DB_TYPE', 'mysql'); // tipo de banco de dados
define('PHPGRID_DB_CHARSET','utf8'); // sempre 'utf8' no MySQL

Criando a interface de usuário (UI)

Nosso sistema de inventário é composto por quatro páginas (nomes em inglês, seguidos pela respectiva tradução):

  • Current Inventory (Estoque atual)
  • Incoming Purchases (Compras recebidas)
  • Outgoing Orders (Encomendas a enviar)
  • Reports (Relatórios)
5AWVXClN4dV5xDNjuSOuNyHn2iJWDJ3Xu4PL

O arquivo de inclusão do menu é armazenado em uma pasta inc com o nome  de menu.php. O código para o menu é simples. Por uma questão de foco, não entraremos em grandes detalhes. Sinta-se à vontade para olhar o código dentro da pasta inc.

Também adicionamos um item de menu chamado Reports.

nL2WOBl0IY3-KmkHLxyWenxsQ5CmYZcKTC-k

Páginas

Usaremos o mesmo modelo de página que usamos para os tutoriais de CRM e gerenciamento de projetos.

Current Inventory (Estoque atual)

AVz5Mdch-aEydKuRqCNgKCUz24E7XCreeaIM

Vamos começar com a página do estoque atual, Current Inventory.

As compras recebidas aumentam o estoque, enquanto os pedidos de saída o diminuem. De uma perspectiva mestre-detalhe, o Current Inventory não tem uma, mas duas grades de dados (datagrids, em inglês) de detalhes – Purchases (compras recebidas) e Orders (pedidos de saída).

Assim, a página Current Inventory é composta por uma grade mestre (o estoque atual) e duas grades de detalhes (Incoming Purchases e Outgoing Orders). Podemos apresentar facilmente esses relacionamentos usando o recurso  do phpGrid de uma grade de dados mestre com várias grades de dados de detalhes.

phpGrid Lite Professional e Enterprise

Os recursos de agrupamento e detalhes mestre requerem a versão Professional ou Enterprise do phpGrid. Se você está na versão gratuita Lite, ainda pode usar o subgrid no lugar dos detalhes mestre, apesar de o subgrid ser menos avançado. As versões Professional ou Enterprise são altamente recomendadas.

Se você já leu o tutorial Building a Donation Manager from Scratch (em inglês), não terá problemas em seguir o código abaixo.

Observe o uso da função set_col_format() (em inglês) para formatar os números inteiros.

$dgProd = new C_DataGrid('SELECT * FROM products', 'id', 'products');
$dgProd->set_col_hidden('id', false);
$dgProd->enable_autowidth(true)->set_dimension('auto', '200px')->set_pagesize(100);

$dgProd->set_col_title('ProductName', 'Name');
$dgProd->set_col_title('PartNumber', 'Part Number');
$dgProd->set_col_title('ProductLabel', 'Label');
$dgProd->set_col_title('StartingInventory', 'Starting Inventory');
$dgProd->set_col_title('InventoryReceived', 'Inventory Received');
$dgProd->set_col_title('InventoryShipped', 'Inventory Shipped');
$dgProd->set_col_title('InventoryOnHand', 'Inventory On Hand');
$dgProd->set_col_title('MinimumRequired', 'Minimum Required');

$dgProd->set_col_format('StartingInventory', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('InventoryReceived', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('InventoryShipped', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('InventoryOnHand', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('MinimumRequired', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->enable_edit('FORM');

Isso é tudo para a grade de dados de Current Inventory. Aqui está a aparência até agora:

z4aLzzcqepAfvKzy8SgY-hpYfAkRjh6NAbDE

Agora, vamos fazer algumas alterações para melhorar nossa grade de dados de produtos, Products.

Em primeiro lugar, adicionaremos uma formatação condicional: sempre que o estoque disponível, InventoryOnHand, for definido como zero ou um valor negativo, ele será exibido usando uma cor de fundo diferente. Usaremos a função set_conditional_format() para esse propósito.

 $dgProd->set_conditional_format(
    'InventoryOnHand', 'CELL',
        array("condition"=>"lt",
          "value"=>"1",
          "css"=> array("color"=>"red","background-color"=>"#DCDCDC")));

O código acima adiciona uma condição de exibição para que, sempre que o campo InventoryOnHand tiver um valor menor que (lt) um, a cor do texto mude para red e a cor de fundo para cinza escuro (#DCDCDC).

Em segundo lugar, sempre que InventoryOnHand for menor que o valor mostrado em MinimumRequired, gostaríamos de alertar o usuário com uma cor de fundo proeminente, como ouro. Para comparar valores entre dois campos, devemos mudar para Javascript porque a função set_conditional_format() só funciona com um único campo.

O código abaixo usa um laço for para iterar em cada linha na grade de dados Products. Ele compara o inventoryOnHand com o minimumRequired e, quando a condição for atendida, usará a função setCell para alterar a cor do plano de fundo.

$onGridLoadComplete = <<<ONGRIDLOADCOMPLETE
function(status, rowid)
{
    var ids = jQuery("#products").jqGrid('getDataIDs');
    for (var i = 0; i < ids.length; i++)
    {
        var rowId = ids[i];
        var rowData = jQuery('#products').jqGrid ('getRowData', rowId);

        var inventoryOnHand = $("#products").jqGrid("getCell", rowId, "InventoryOnHand");
        var minimumRequired = $("#products").jqGrid("getCell", rowId, "MinimumRequired");

        // compare two dates and set custom display in another field "status"
        console.log(inventoryOnHand + " | " + minimumRequired);
        if(parseInt(inventoryOnHand) < parseInt(minimumRequired)){

            $("#products").jqGrid("setCell", rowId, "PartNumber", '', {'background-color':'gold'});

        }
    }

}
ONGRIDLOADCOMPLETE;
$dgProd->add_event("jqGridLoadComplete", $onGridLoadComplete);

Você pode aprender mais sobre como comparar vários valores de células no site de suporte do phpGrid (em inglês).

Em seguida, na mesma página, precisamos ver as compras recebidas (Incoming) e os pedidos de saída (Outgoing) para um produto específico.

Grade de detalhes de compras (Incoming)

// Grade de detalhes de compras
$dgPur = new C_DataGrid('SELECT id, PurchaseDate, ProductId, NumberReceived, SupplierId FROM purchases', 'id', 'purchases');
$dgPur->set_col_hidden('id', false)->set_caption('Incoming Purchases');
$dgPur->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
$dgPur->set_col_edittype('SupplierId', 'select', "select id, supplier from suppliers");
$dgPur->set_dimension('800px');

Grade de detalhes de pedidos (Outgoing)

// Grade de detalhes dos pedidos
$dgOrd = new C_DataGrid('SELECT id, OrderDate, ProductId, NumberShipped, First, Last FROM orders', 'id', 'orders');
$dgOrd->set_sortname('OrderDate', 'DESC')->set_caption('Outgoing Orders');
$dgOrd->set_col_hidden('id', false);
$dgOrd->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
$dgOrd->set_dimension('800px');

As duas grades de detalhes usam a mesma chave estrangeira ProductId para vincular à grade de dados mestre (Products).

$dgProd->set_masterdetail($dgPur, 'ProductId', 'id');
$dgProd->set_masterdetail($dgOrd, 'ProductId', 'id');

Finalmente, nosso código completo para gerenciar a página Current Inventory é:

$dgProd = new C_DataGrid('SELECT * FROM products', 'id', 'products');
$dgProd->set_col_hidden('id', false);
$dgProd->enable_autowidth(true)->set_dimension('auto', '200px')->set_pagesize(100);

$dgProd->set_col_title('ProductName', 'Name');
$dgProd->set_col_title('PartNumber', 'Part Number');
$dgProd->set_col_title('ProductLabel', 'Label');
$dgProd->set_col_title('StartingInventory', 'Starting Inventory');
$dgProd->set_col_title('InventoryReceived', 'Inventory Received');
$dgProd->set_col_title('InventoryShipped', 'Inventory Shipped');
$dgProd->set_col_title('InventoryOnHand', 'Inventory On Hand');
$dgProd->set_col_title('MinimumRequired', 'Minimum Required');

$dgProd->set_col_format('StartingInventory', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('InventoryReceived', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('InventoryShipped', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('InventoryOnHand', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));
$dgProd->set_col_format('MinimumRequired', 'integer', array('thousandsSeparator'=>',', 'defaultValue'=>'0'));

$dgProd->set_conditional_format('InventoryOnHand', 'CELL', array("condition"=>"lt",
                                                  "value"=>"1",
                                                  "css"=> array("color"=>"red","background-color"=>"#DCDCDC")));

$onGridLoadComplete = <<<ONGRIDLOADCOMPLETE
function(status, rowid)
{
    var ids = jQuery("#products").jqGrid('getDataIDs');
    for (var i = 0; i < ids.length; i++)
    {
        var rowId = ids[i];
        var rowData = jQuery('#products').jqGrid ('getRowData', rowId);

        var inventoryOnHand = $("#products").jqGrid("getCell", rowId, "InventoryOnHand");
        var minimumRequired = $("#products").jqGrid("getCell", rowId, "MinimumRequired");

        // compare two dates and set custom display in another field "status"
        console.log(inventoryOnHand + " | " + minimumRequired);
        if(parseInt(inventoryOnHand) < parseInt(minimumRequired)){

            $("#products").jqGrid("setCell", rowId, "PartNumber", '', {'background-color':'gold'});

        }
    }

}
ONGRIDLOADCOMPLETE;

$dgProd->add_event("jqGridLoadComplete", $onGridLoadComplete);
$dgProd->enable_edit('FORM');

// Purchases detail grid
$dgPur = new C_DataGrid('SELECT id, PurchaseDate, ProductId, NumberReceived, SupplierId FROM purchases', 'id', 'purchases');
$dgPur->set_col_hidden('id', false)->set_caption('Incoming Purchases');
$dgPur->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
$dgPur->set_col_edittype('SupplierId', 'select', "select id, supplier from suppliers");
$dgPur->set_dimension('800px');

// Orders detail grid
$dgOrd = new C_DataGrid('SELECT id, OrderDate, ProductId, NumberShipped, First, Last FROM orders', 'id', 'orders');
$dgOrd->set_sortname('OrderDate', 'DESC')->set_caption('Outgoing Orders');
$dgOrd->set_col_hidden('id', false);
$dgOrd->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
$dgOrd->set_dimension('800px');

$dgProd->set_masterdetail($dgPur, 'ProductId', 'id');
$dgProd->set_masterdetail($dgOrd, 'ProductId', 'id');
$dgProd->display();

Aqui, vemos uma captura de tela da página de estoque:

Spe5wb7oEkaVAikkKBEJrPzQExFzFj70EZTf

Compras recebidas (Incoming Purchases)

luyVRlrvSLQ10tITWdwYUHJ4A5flLdxEtuaZ

A próxima página é a de compras recebidas, ou Incoming Purchases. É similar à grade de detalhes de compras, Purchase Detail Grid, que nós vimos ao configurar a página de estoque atual, Current Inventory. Agrupamos as compras por ProductId e exibimos a soma em NumberReceived. Quaisquer compras recebidas vão aumentar o estoque.

$dgPur -> set_group_properties('ProductId', false, true, true, false);
$dgPur -> set_group_summary('NumberReceived','sum');
Observação: o recurso de agrupamento está disponível apenas no phpGrid em suas versões Professional e Enterprise. Para filtrar sem o agrupamento, use a pesquisa por integração.

O código completo:

$dgPur = new C_DataGrid('SELECT id, PurchaseDate, ProductId, NumberReceived, SupplierId FROM purchases', 'id', 'purchases');
$dgPur->set_col_hidden('id', false);

$dgPur->set_col_title('PurchaseDate', 'Date of Purchase');
$dgPur->set_col_title('ProductId', 'Product');
$dgPur->set_col_title('NumberReceived', 'Number Received');
$dgPur->set_col_title('SupplierId', 'Supplier');

$dgPur->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");
$dgPur->set_col_edittype('SupplierId', 'select', "select id, supplier from suppliers");

// $dgPur->enable_edit('FORM');
$dgPur->set_pagesize(100);

$dgPur->set_col_width('PurchaseDate', '50px');
$dgPur->set_col_width('NumberReceived', '35px');

$dgPur -> set_group_properties('ProductId', false, true, true, false);
$dgPur -> set_group_summary('NumberReceived','sum');

$dgPur->enable_autowidth(true);
$dgPur->display();

Aqui está uma captura de tela de nossa página Incoming Purchases com o agrupamento habilitado:

8sDg-Tnhm0s1ZH5td-xdCWokJ3oO3ulAzf-T

Pedidos enviados (Outgoing Orders)

9ymBPuuoXXvfEoCntXG-WPBxpUqIiGOpUACw

A próxima página é a de pedidos enviados, Outgoing Orders. É semelhante à grade de detalhes dos pedidos, Orders Detail Grid, da página do estoque atual, Current Inventory. Aqui, apresentaremos uma função avançada chamada set_grid_method().

$dgOrd = new C_DataGrid('SELECT id, OrderDate, ProductId, NumberShipped, First, Last FROM orders', 'id', 'orders');
$dgOrd->set_sortname('OrderDate', 'DESC');
$dgOrd->set_col_hidden('id', false);

$dgOrd->set_col_title('OrderDate', 'Order Date');
$dgOrd->set_col_title('ProductId', 'Product');
$dgOrd->set_col_title('NumberShipped', 'Number Shipped');

$dgOrd->set_col_edittype('ProductId', 'select', "select id, ProductLabel from products");

// $dgOrd->enable_edit('FORM');
$dgOrd->set_pagesize(100);

$dgOrd->set_col_width('OrderDate', '30px');
$dgOrd->set_col_width('NumberShipped', '35px');
$dgOrd->set_col_width('First', '20px');
$dgOrd->set_col_width('Last', '20px');

$dgOrd->set_grid_method('setGroupHeaders', array(
                                array('useColSpanStyle'=>true),
                                'groupHeaders'=>array(
                                        array('startColumnName'=>'First',
                                              'numberOfColumns'=>2,
                                              'titleText'=>'Customer Name') )));

$dgOrd->enable_autowidth(true);
$dgOrd->display();

Resumo

Este tutorial cria um sistema de estoque, simples e extensível em pouco menos de 50 linhas de código. O estilo progressivo desses tutoriais também ajuda o leitor a ficar, no fim das contas, mais familiarizado e tranquilo com o phpGrid ao apresentar um número limitado de recursos novos do phpGrid em cada um.

O que vem a seguir

Esse é o final do código necessário para criar as grades de dados necessárias para o tutorial. Porém, ainda não terminamos. Ainda temos mais uma página que precisamos criar — a página dos relatórios, ou Reports. Trataremos dela em instantes.

Qual é a finalidade de um sistema de estoque sem algum tipo de relatório? Nesta seção, você aprenderá a usar o phpChart — que se integra de modo perfeito com o phpGrid — para criar relatórios que sejam visualmente agradáveis e úteis para sua aplicação de gerenciamento de estoque.

Esta será a aparência da página ao concluirmos:

rLTmQ3BPx8zS1nbHXhPPaTDHB81SDxBrWqDE

Antes de iniciarmos, precisaremos instalar o phpChart. É recomendado que você obtenha a versão completa do phpChart, pois a versão gratuita (phpChart Lite) dá suporte apenas aos gráficos de linhas.

Configuração do phpChart

É importante que tenhamos o phpGrid e o phpChart em pastas separadas. Abaixo, vemos a hierarquia de pastas recomendada.

www
+-- Donation_Manager
|   |-- phpGrid
|   |   +-- conf.php
|   |-- phpChart
|   |   +-- conf.php
|   +-- ...

Design do relatório

Colocaremos o gráfico de pizza próximo à grade de resumo do estoque. A grade de dados fornece os dados em série para que o gráfico de pizza seja produzido.

oBEgm5-eYi2TXN1Ay5YQ-wgwGZveIgLFZpAp

Integração do phpGrid e do phpChart

Primeiro, inclua chamadas aos dois arquivos conf.php no início do código.

require_once("phpGrid/conf.php");
require_once("phpChart/conf.php");

Abaixo, vemos o código completo para a criação de nosso gráfico de pizza:

$pc = new C_PhpChartX(array(array(null)), 'PieChart');
$pc->set_title(array('text'=>'Current Inventory Summary'));
$pc->set_series_default(array( 'shadow'=> false,
    'renderer'=> 'plugin::PieRenderer',
    'rendererOptions'=> array(
      'showDataLabels' => true,
      'highlightMouseOver' => true,
      'startAngle'=> 180,
      'sliceMargin'=> 4,
      'showDataLabels'=> true )
  ));
$pc->set_legend(array('show'=>true,'location'=> 'w'));
// remove background
$pc->set_grid(array(
    'background'=>'white',
    'borderWidth'=>0,
    'borderColor'=>'#000000',
    'shadow'=>false));
$pc->add_custom_js("
        $('#PieChart').bind('jqplotDataHighlight',
            function (ev, seriesIndex, pointIndex, data) {
               $('#label_info').text(data);      
            }
        );
    ");
$pc->draw(660,400);

Vamos ver o passo a passo do código.

A primeira linha é o construtor. Passamos array(null) como os dados em série, pois não queremos que os dados sejam exibidos no gráfico de pizza inicialmente. Os dados do estoque usados para fazer o gráfico ainda não estão disponíveis quando ele é inicializado pela primeira vez. Os dados serão recebidos da grade de dados mais tarde, em formato JSON.

Damos ao nosso gráfico um nome exclusivo, PieChart.

$pc = new C_PhpChartX(array(array(null)), 'PieChart');

Em seguida, damos a ele um título. Nada muito complicado.

$pc->set_title(array('text'=>'Current Inventory Summary'));

Ao termos o título, chamamos a função set_series_default para definir o renderer para PieRenderer. Diferente de um gráfico de barras, um gráfico de pizza não tem um eixo Y.

Também podemos definir a propriedade rendererOptions. Não entraremos em detalhes em cada uma das opções aqui, mas você poderá encontrar mais informações sobre elas na documentação on-line.

$pc->set_series_default(array( 'shadow'=> false,
    'renderer'=> 'plugin::PieRenderer',
    'rendererOptions'=> array(
      'highlightMouseOver' => true,
      'startAngle'=> 180,
      'sliceMargin'=> 4,
      'showDataLabels'=> true )
  ));

Também queremos dar uma legenda ao gráfico. O comando set_legend abaixo mostra a legenda a oeste (o que sabemos em função do w) ou à esquerda do gráfico de pizza.

$pc->set_legend(array('show'=>true,'location'=> 'w'));

Também removeremos a borda e o segundo plano.

$pc->set_grid(array(
    'background'=>'white',
    'borderWidth'=>0,
    'borderColor'=>'#000000',
    'shadow'=>false));

Por fim, criaremos nosso gráfico dando a ele uma altura (height) e uma largura (width) em pixels.

$pc->draw(660,400);

No entanto, se você executar o código agora, não verá o gráfico, pois os dados usados para rendererizá-lo ainda não estão disponíveis.

Grade de dados do resumo do estoque (Inventory Summary Datagrid)

Aqui, usaremos a mesma grade de dados de estoque que usamos na página Products. Apenas adicionaremos uma questão — um manipulador de eventos.

No phpGrid, podemos adicionar um manipulador de eventos com a função add_event(). add_event() vincula um manipulador de eventos, que é, essencialmente, uma função do JavaScript, a um evento específico do phpGrid. Uma lista de eventos possíveis pode ser encontrada aqui.

Como devemos aguardar até que a grade de dados termine de carregar antes que ela possa enviar os dados para criar o gráfico, usaremos o evento jqGridLoadComplete.

Introdução ao phpGrid — o evento jqGridLoadComplete

O evento jqGridLoadComplete é o último evento que ocorre quando todo o corpo da grade de dados terminou de carregar. Observe que o corpo da grade será recarregado se o usuário alterar a ordem de classificação de uma coluna ou se definir um filtro.

Enviando dados com o Javascript

A seguir vemos o manipulador de eventos em Javascript para jqGridLoadComplete.

<span class="hljs-function">function(status, rowid)
{</span>
    var dataX = [];
    var dataY = [];

    d1 = $('#products').jqGrid('getCol', 'ProductLabel', false);
    d2 = $('#products').jqGrid('getCol', 'InventoryReceived', false);

    npoints = d1.length;
    for(var i=0; i < npoints; i++){
        dataX[i] = [i+1, d1[i]];
        dataY[i] = [i+1, parseInt(d2[i])];
    }

    var pieData = [];
    for(var j=0; j < dataX.length; j++)
    {
        pieData.push([dataX[j][1], dataY[j][1]]);
    }
    console.log(pieData);
    _PieChart.series[0].data = pieData;
    _PieChart.replot({resetAxes:true});
}

O código completo:

$dgProd = new C_DataGrid('SELECT id, ProductLabel, InventoryReceived FROM products', 'id', 'products');
$dgProd->set_col_hidden('id', false);
$dgProd->set_dimension('auto', 'auto')->set_pagesize(100);
$onGridLoadComplete = <<<ONGRIDLOADCOMPLETE
function(status, rowid)
{
    var dataX = [];
    var dataY = [];

    d1 = $('#products').jqGrid('getCol', 'ProductLabel', false);
    d2 = $('#products').jqGrid('getCol', 'InventoryReceived', false);
    d3 = $('#products').jqGrid('getCol', 'InventoryShipped', false);
    d4 = $('#products').jqGrid('getCol', 'InventoryOnHand', false);


    npoints = d1.length;
    for(var i=0; i < npoints; i++){
        dataX[i] = [i+1, d1[i]];
        dataY[i] = [i+1, parseInt(d2[i])];
    }

    var pieData = [];
    for(var j=0; j < dataX.length; j++)
    {
        pieData.push([dataX[j][1], dataY[j][1]]);
    }
    console.log(pieData);
    _PieChart.series[0].data = pieData;
    _PieChart.replot({resetAxes:true});
}
ONGRIDLOADCOMPLETE;
$dgProd->add_event("jqGridLoadComplete", $onGridLoadComplete);
$dgProd->display();

Aí está. Você acaba de criar seu primeiro sistema de gerenciamento de estoque do zero usando o PHP e o MySQL!

É novo na programação? Sem problemas!

Se você é novo na programação e ainda não se sente confortável com ela, confira o ZenBase, que foi criado sobre o phpGrid. O sistema de gerenciamento de estoque é apenas um dos vários templates de aplicação disponíveis no ZenBase para quem quiser — com ou sem habilidade em programação — para usar e personalizar às suas próprias necessidades.

Demonstração on-line

A seguir: adicionar um leitor de código de barras

Adicione um leitor de código de barras ao nosso sistema de gerenciamento de estoque (texto em inglês)

VqWE2ltTZhdjoJld8PcEnfrTL4g645hyQJTv

Faça o download do código-fonte no GitHub

Problema comum:

Fatal error: Uncaught Error: Class ‘phpGrid\C_DataGrid’ not found

Como resolver:
Se estiver usando a versão Lite gratuita, você pode comentar a primeira linha de código

// use phpGrid\C_DataGrid;

— OU —

Adicionar um símbolo de namespace global — backslash/barra invertida (\) única — ANTES do construtor

$dg = new \C_DataGrid("SELECT * FROM orders", "orderNumber", "orders");

É possível que você se interesse também pelos tutoriais a seguir (textos em inglês):

Obrigado pela leitura! Se gostou deste artigo, compartilhe-0 para que mais pessoas possam ter acesso a ele.