Neste artigo será realizado um embasamento teórico e prático sobre as tecnologias utilizadas no front-end, neste caso Bootstrap e jQuery, permitindo que o leitor se adapte a situações de âmbito real, através da construção de um PDV (portal) Web completo, em conjunto com as tecnologias PHP para o back-end da aplicação, e MySQL para lidar com o salvamento das informações no banco dados.

Exploraremos ao máximo os recursos de ambos os frameworks com exemplos os mais próximos da realidade possível, tratando de focar sempre na integração entre todas as referidas tecnologias.

Como criar um site com Bootstrap e jQuery

É sabido que o desenvolvimento web envolto pelas “n” tecnologias, frameworks e ferramentas acarreta uma necessidade de atualização deveras constante. Seja em projetos pequenos ou de grande porte, o desenvolvedor front-end na maioria dos casos deve ter um conhecimento bem aprofundado em tecnologias como HTML5, CSS3, JavaScript e Web Services, por exemplo, além de saber como utilizar frameworks como Bootstrap, jQuery, jQueryUI, dentre outros, levando em consideração que tais frameworks estão em constante atualização, desta forma o desenvolvedor tem que saber a diferença entre as versões já em uso e buscar se atualizar para as próximas, seja uma versão beta ou apenas notas sobre as novidades das que virão em um arquivo README qualquer.

Outro ponto importante é saber o que usar em um projeto e qual versão de determinado framework será inserido no mesmo, pois em se tratando de mobilidade existe a preocupação de tornar o website responsivo, ou seja, permitir que o layout de seu site se adeque ao tamanho da tela do dispositivo em que o usuário esteja usando, seja um smartphone, tablet ou mesmo um PC.

Logo, é importante saber, antes de adotar um framework para um projeto, se o mesmo trata os recursos da responsividade, o que pode ser observado juntamente à documentação do framework. Veja na Figura 1 o portal da DevMedia proporcionando a responsividade de layout para diferentes dispositivos de seus usuários e assinantes MVP.

Portal
DevMedia com layout responsivo
Figura 1. Portal DevMedia com layout responsivo.

Bootstrap

O Bootstrap, ou Twitter Bootstrap, é um dos frameworks open source para front-end mais conhecidos e usados em projetos web em todo o mundo, conquista essa devida principalmente à sua produtividade. Ele foi lançado em 2011 e ganhou popularidade pela facilidade de uso para criar interfaces robustas para a web e por ser de fácil manutenção.

O Bootstrap foi idealizado e criado por membros da equipe de desenvolvedores do Twitter, especificamente encabeçando o projeto Mark Otto e Jacob Thornton.

Cansados de utilizar várias bibliotecas em projetos internos que acarretaram em várias inconsistências e inúmeras horas de manutenção, eles resolveram então criar um framework que fornecesse um kit de ferramentas para projetos web de forma fácil e produtiva, garantindo assim um padrão nos projetos web de interface com elementos HTML bem estruturados e tipograficamente elegantes e agradáveis, ou seja, em conjunto com os elementos HTML e estrutura DOM são aplicados vários estilos CSS e até mesmo recursos em JavaScript.

No Bootstrap temos uma série de classes CSS que podemos utilizar facilmente com elementos divs e outros elementos da HTML. Além disso, o Bootstrap também pode ser considerado uma coleção de ferramentas que integra componentes do jQuery, facilitando, desta forma, o uso das classes CSS do Bootstrap em tags HTML para melhor organizar a estrutura do site, melhorar visualmente os componentes da página, usar recursos de responsividade e JavaScript em conjunto com CSS para criar efeitos elegantes e antenados com a web 2.0.

Tudo isso é apenas parte do Bootstrap, mais adiante veremos sua estrutura e como utilizar seus componentes em um projeto web.

A equipe do Twitter abraçou o mundo mobile no Bootstrap, desta forma a partir da versão 2 já existiam várias funcionalidades do Bootstrap para o projeto de Web Design Responsivo. Veja na Figura 2 o website do Bootstrap onde é possível realizar o download do framework.

website oficial do Bootstrap
Figura 2. website oficial do Bootstrap.

O website do projeto contempla desde um tour pelos componentes e bibliotecas do framework, até templates prontos, tutoriais e o blog oficial. Um destaque especial vai para a opção “Customize” que apresenta vários componentes reutilizáveis ​​construídos para fornecer iconografia, menus suspensos com dropdowns, botões agrupados, navegação, mensagens de alertas, grupos de inputs, paginação, badges, barras de progresso, painéis dentre outros componentes prontos para aplicar em contextos diversos de um projeto web.

Caso você prefira ter o primeiro contato com o Bootstrap no idioma português, poderá visitar a página de tradução do Bootstrap feita pela Globo.com (seção Links). Só atenha-se ao fato da versão ser uma anterior à que usaremos neste artigo, mas será o suficiente para lidar com as implementações que faremos.

Criando um projeto com Bootstrap

Os templates do Bootstrap são uma mão na roda quando se trata de iniciar uma aplicação do zero e quando não temos nenhum modelo pronto de design em mente. Até mesmo os web designers que começam o desenvolvimento de um site usam o estilo padrão fornecido pelo Bootstrap para ter uma ideia mais rápida e prática de como o mesmo irá se comportar.

No menu Expo do site oficial do framework, o leitor poderá encontrar links para sites prontos que fizeram uso do Bootstrap em suas construções. Em alguns deles é possível inclusive o reuso do estilo e estrutura usados.

Um fator importante na construção de um projeto front-end é criar uma espécie de mapa com a quantidade de páginas do seu website juntamente com a estrutura de layouts e elementos que irão compor o mesmo, pois a partir deste ponto você saberá se pode aproveitar um template pronto do Bootstrap ou se vai precisar criar seu próprio modelo, definindo a quantidade de containers bem como o sistema de grids a utilizar. A seguir veja os passos para iniciar um novo projeto com o Bootstrap.

Bootstrap CDN

Conforme apresentado na Figura 2 você pode facilmente realizar o download da última versão do Bootstrap via site, porém existe outra forma de utilizar o mesmo em um projeto sem precisar ter os arquivos do framework fisicamente no servidor de hospedagem. Para isso, seria necessário fazer uso do Bootstrap CDN que é uma forma de referência aos arquivos do projeto através do MaxCDN (Max Content Delivery Network), um provedor de conteúdo via rede muito usado. Veja na Listagem 1 como realizar este procedimento em seu projeto.

Listagem 1. Referências CDN para o projeto com Bootstrap.


  01  <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Bootstrap CDN</title>
  07  
  08      <!-- Bootstrap links CDN-->
  09      <link rel= "stylesheet" href= "https://maxcdn.Bootstrapcdn.com/Bootstrap/3.3.2/css/Bootstrap.min.css" > 
  10      <link rel= "stylesheet" href= "https://maxcdn.Bootstrapcdn.com/Bootstrap/3.3.2/css/Bootstrap-theme.min.css" > 
  11    </head>
  12    <body>
  13      <h1>Bootstrap CDN!</h1>
  14      
  15     <!-- Dependência jQuery-->
  16      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
  17     <script src= "https://maxcdn.Bootstrapcdn.com/Bootstrap/3.3.2/js/Bootstrap.min.js" ></script>
  18    </body>
  19  </html>

Vejamos alguns detalhes importantes presentes na listagem:

· Linha 1: Perceba a presença da tag DOCTYPE, que indica que esta página deve ser renderizada pelo browser seguindo os padrões da HTML5. Isso é importante pois o Bootstrap irá trabalhar com elementos dessa versão da HTML em específico.

· Linha 5: Aqui foi definido na tag meta o viewport, que, conforme documentação do Bootstrap, é necessário para tornar o layout do projeto responsivo.

· Linhas 9 e 10: Foi informado o CDN para a versão minificada dos arquivos CSS do Bootstrap através do MaxCDN.

· Linha 16: Nesta linha temos uma referência à versão minificada da biblioteca JS do jQuery que é uma dependência do Bootstrap.

· Linha 17: Referência CDN à biblioteca JS minificada do Bootstrap.

A utilização do CDN tem várias vantagens, como o download dos arquivos CSS e JS do Bootstrap que não serão realizados pelo seu servidor de hospedagem, auxiliando na diminuição do consumo de banda quando seu website for visualizado por uma quantidade relativamente alta de usuários.

Uma desvantagem seria o fato de que se em algum momento você ficar sem internet no ambiente de desenvolvimento, não seria possível fazer os testes com o Bootstrap.

Configurando o Bootstrap

O primeiro passo é realizar o download do Bootstrap conforme link de download presente na seção Links. A versão que usaremos é a v3.3.2, ou seja, a versão mais recente no momento da escrita deste artigo. Após clicado no link para download, você será redirecionado para outra página que possibilita a escolha das seguintes opções conforme Figura 3, a saber:

· Bootstrap: A primeira opção possibilita realizar o download dos arquivos CSS e JavaScript compilados e minificados, ou seja, uma forma enxuta de usar o Bootstrap, uma vez que isso também ajudaria muito a reduzir o tráfico de dados via browser cliente e a sua aplicação hospedada em produção.

Isso é possível graças à remoção dos espaços em branco e quebras de linha, o que torna o mesmo bem pequeno. É importante salientar que não serão incluídos quaisquer arquivos com documentação para consulta. Esta é a opção que usaremos no projeto deste artigo.

· Source code: Se o leitor preferir entender como foi estruturado e arquitetado o projeto a nível de código fonte, pode escolher esta opção para download, pois aqui você terá os arquivos de fontes e documentação do projeto juntos, porém é necessário um compilador para usar o projeto final.

Neste caso, a equipe do Twitter usa o Grunt.js, um executor de tarefas automatizadas que gera builds através do código de projetos prontos, e cujo link para download você pode encontrar na seção Links deste artigo ou no próprio site do Bootstrap.

· Sass: Aqui você pode baixar o Twitter Bootstrap convertido de Less para Sass e pronto, já pode usá-lo, inclusive com pré-compiladores em Rails, Compass e projetos Sass-only.

Opções
de download do Bootstrap
Figura 3. Opções de download do Bootstrap.

Sass x Less

Ambos os frameworks podem ser entendidos como uma nova forma de escrever código em CSS, ou seja, com o uso de pré-processadores e frameworks de folhas de estilo para dar mais produtividade no desenvolvimento do código CSS principalmente no que diz respeito a repetição de uma mesma ação diversas vezes. Também pode ser feito o uso de variáveis em valores, propriedades e seletores, uma vez que você irá escrever arquivos com a extensão .sass e o mesmo será compilado para .css, para que você possa subir para o servidor.

Depois de realizar o download do Bootstrap e descompactá-lo, você terá uma estrutura de diretórios conforme a apresentada na Figura 4.

Perceba que existe uma pasta chamada “css” para armazenar os arquivos de CSS com os nomes Bootstrap e Bootstrap-theme com estilo pré-definido para os componentes e temas, respectivamente, porém existem algumas diferenças entre eles: Bootstrap.css e Bootstrap-theme.css são arquivos css simples, Bootstrap.min.css e Bootstrap-theme.min.css são os arquivos CSS minificados, com tamanho reduzido, e os arquivos Bootstrap.css.map e Bootstrap-theme.css.map são usados em pré-processadores e editores Less; outra pasta chamada “js” para arquivos JavaScript e outra chamada “fonts” que armazena algumas fontes utilizadas pelo Bootstrap por padrão.

Estrutura
de arquivos do Bootstrap
Figura 4. Estrutura de arquivos do Bootstrap.

Bootstrap Containers

Para iniciar o uso do Bootstrap na prática você deverá criar um diretório para salvar as páginas HTML e os recursos necessários para o website. Chamaremos a pasta de “www_Bootstrap” e dentro da mesma devem ser extraídos os arquivos do Bootstrap contidos no zip baixado anteriormente.

Feito isso, deve ser criado um novo arquivo HTML na raiz do projeto conforme apresentado na Listagem 2 com o nome de Home.html. Veja na Figura 5 a hierarquia de diretórios que você obedecer, em detrimento da pasta www do WampServer.

Nós usaremos o aplicativo WampServer para hospedar o website em ambiente de desenvolvimento e também pelo fato de que iremos precisar do mesmo para interpretar os códigos PHP que serão usados na segunda parte deste artigo. O WampServer é um pacote tudo em um, ou seja, você instala e junto vem o PHP, o servidor Apache, o PHPAdmin, o banco de dados MySQL, dentre outros aplicativos.

Estrutura
de diretórios dentro do WampServer
Figura 5. Estrutura de diretórios dentro do WampServer.

Listagem 2. Código HTML referente à página Home com uso de containers.


  01  <!DOCTYPE html>
  02    <html lang="pt-BR">
  03      <head>
  04        <meta charset="utf-8">   
  05        <meta name="viewport" content="width=device-width, initial-scale=1">
  06        <title>Website com Bootstrap</title>      
  07        <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap.min.css" > 
  08        <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap-theme.min.css" > 
  09      </head>
  10      <body>
  11           <h3>h3 fora da class Container, somente dentro de body.</h3> 
  12                  <div class="container">
  13                  <h3>h3 dentro da class Container.</h3>
  14                  </div>       
  15           <div class="jumbotron">
  16                  <h3>h3 dentro class Jumbotron.</h3>            
  17                  </div>       
  18           <div class="container">    
  19                  <div class="jumbotron">
  20                         <h3>h3 dentro class Jumbotron, e Jumbotron dentro de Container.</h3>
  21                  </div>
  22                  </div>       
  23             <div class="container-fluid">   
  24                  <div class="jumbotron">
  25                         <h3>h3 dentro class Jumbotron, e Jumbotron dentro de Container-fluid.</h3>
  26                  </div>
  27                  </div>       
  28           <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
  29           <script src= "Bootstrap-3.3.2-dist/js/Bootstrap.min.js" ></script>
  30      </body>
  31  </html>

Já em relação ao conteúdo da listagem, temos algumas configurações novas a quem ainda não conhece o framework, a saber:

· Linhas 7 e 8: Referências aos arquivos CSS do Bootstrap.

· Linha 11: Foi inserido um elemento h3 para que se possa ter uma noção de como fica um elemento HTML solto dentro do body sem uso de um container.

· Linhas 12 à 14: É definida uma div onde é atribuída a propriedade class (a classe CSS container) e dentro da mesma é inserido outro h3 para realizar uma comparação no layout em relação à linha 11.

· Linhas 15 à 17: Aqui é definida uma div com o uso da classe jumbotron interna ao framework. Veja que ela diferente da classe container pois nela algumas propriedades do CSS como padding e background-color tem valores distintos, possibilitando a cor cinza no fundo e toda a largura da tela. Por fim, dentro desta mesma div foi colocado outro h3 para uso futuro.

· Linhas 18 à 22: Temos a presença de uma div de classe jumbotron dentro de outra div de classe container, e um h3 para mostrar o resultado e o efeito em relação às margens, então dessa forma você pode facilmente agrupar um container dentro de outro para obter o resultado esperado.

· Linhas 23 à 27: Nestas linhas foi utilizado outro container, neste caso o container-fluid e dentro do mesmo uma jumbotron e uma h3. Veja a diferença em relação ao agrupamento das linhas 18 à 22.

· Linhas 28 e 29: Aqui nós inserimos as referências aos arquivos JavaScript do Bootstrap e jQuery. Perceba que estas foram feitas apenas no final do documento em vez de dentro da tag head, isso porque com a referência ao final do documento obtemos uma melhor performance de carregamento dos elementos HTML. Além disso, como o browser já deve ter renderizado toda a página a essa altura, podemos acessar qualquer elemento HTML já carregado via JavaScript.

Quando se utiliza dos recursos do Bootstrap em um website é de extrema importância usar containers para agrupar conjuntos de elementos HTML, ou seja, através da tag div da HTML você pode definir na propriedade “class” o que foi apontado na classe de estilos CSS do Bootstrap para servir de containers de elementos. Veja a seguir algumas classes que podem ser utilizadas neste sentido:

· Container: A classe container do Bootstrap funciona como uma forma de recipiente para os elementos HTML do seu layout, tendo sua importância na estruturação do documento e se comportando de acordo com o tipo de dispositivo que está renderizando a página através do uso das Media Queries do CSS, que definem a largura da tela. Conforme o trecho de código da Listagem 3 (retirado do arquivo Bootstrap.css), pode ser vista parte da formação CSS pertencente à classe container.

· Container-fluid: A classe container-fluid pode ser considerada uma extensão de container para layouts fluidos, onde o próprio código é reorganizado por si só.

Listagem 3. Techo de código retirado do arquivo Bootstrap.css que repesenta a classe container.


  1564  .container {
  1565    padding-right: 15px;
  1566    padding-left: 15px;
  1567    margin-right: auto;
  1568    margin-left: auto;
  1569  }
  1570  @media (min-width: 768px) {
  1571    .container {
  1572      width: 750px;
  1573    }
  1574  }
  1575  @media (min-width: 992px) {
  1576    .container {
  1577      width: 970px;
  1578    }
  1579  }
  1580  @media (min-width: 1200px) {
  1581    .container {
  1582      width: 1170px;
  1583    }
  1584  }

Media Queries

As Media Queries são um recurso utilizado para identificar características do dispositivo que está sendo utilizado para renderizar as páginas HTML. Dessa forma, através do uso de Media Types podemos obter informações como a resolução do dispositivo, por exemplo, e em cima disso fazer com que o layout se comporte de acordo com o tamanho da tela, aplicando código CSS conforme a necessidade. Esta tecnologia proporciona parte dos recursos que precisamos para impor o responsive web design.

Nas Figuras 6 e 7 é exibido o resultado das execuções da referida listagem em um navegador de PC e dispositivo móvel, respectivamente.

Resultado
da execução visualizado pelo navegador em um PC
Figura 6. Resultado da execução visualizado pelo navegador em um PC.

Resultado
da execução visualizado em um dispositivo móvel
Figura 7. Resultado da execução visualizado em um dispositivo móvel.

Sistema de Grids do Bootstrap

O novo sistema de grids do Bootstrap 3 teve mudanças significativas em relação à versão 2, principalmente pelo upgrade que tivemos com foco no desenvolvimento de websites responsivos, isto é, o Bootstrap agora idealiza o foco no desenvolvimento mobile primeiro para depois focar na adaptação para dispositivos com maior resolução.

O sistema de grids nada mais é que um recurso do Bootstrap para que você possa construir seu layout, uma forma de organizar os elementos HTML dentro de linhas e colunas. Antigamente eram usadas tabelas para a construção de layouts, porém com a padronização da Web e da estrutura de documentos HTML, elas hoje são usadas apenas para exibir conteúdo tabular.

Para entender o sistema de grids do Bootstrap você precisa pensar na janela de um browser como sendo uma estrutura de tabela, linhas e colunas (como no Excel, por exemplo), sendo possível adicionar várias linhas uma abaixo da outra e que cada linha possa ser dividida em uma ou várias colunas. Todavia, o Bootstrap trabalha com um total de 12 colunas por linha, caso você adicione mais que isso a linha sofrerá uma quebra para a próxima logo abaixo quebrando o padrão do seu layout. No fim, veremos que existem 4 classes CSS no Bootstrap responsáveis por dividir as colunas de uma linha observando o tipo de dispositivo através das media queries. Vejamos a seguir os passos para isso:

1. Primeiramente você precisa criar um container usando uma div com as classes container ou container-fluid que vimos para armazenar seu layout.

2. Com o container já criado, você pode ir inserindo a quantidade de linhas que o seu layout necessita, ou pode optar por ir criando uma linha de cada vez para ir acompanhando o resultado no browser. Para criar uma linha basta criar uma div e definir para esta a classe CSS row do Bootstrap, e dentro da linha dela dividir as colunas num total de 12.

3. Agora só precisa dividir as colunas pertencentes à linha criada no passo anterior. Para isso é importante imaginar dimensões invisíveis que você acha que caberão no seu modelo. A conta é mais ou menos assim: imagine uma linha dividia em 12 pedaços na horizontal, então se você deseja criar um menu à esquerda e outro à direita, deverá dividir esses pedaços por 3 (o que chamamos de mescla), o que dará um total de 6 partes restantes para criar a área central do layout. Para fazer isso, precisamos usar umas das seguintes classes específicas do Bootstrap:

a. .col-xs-: Esta classe deve ser utilizada quando se deseja personalizar as divisões de uma linha para dispositivos com resolução muito pequena (xs – extra small, ou super pequena) ou menor que 750px.

b. .col-sm-: Usando esta classe você dividirá as colunas de uma linha para dispositivos pequenos (sm - small), com resolução entre 750px e 970px.

c. .col-md-: Essa classe terá efeito em dispositivos médios (md - medium) com resolução entre 970 e 1170px.

d. .col-lg-: Nesta, o resultado será apenas para resoluções acima de 1170px. Por exemplo: para dividir uma linha em duas partes usamos <div class=”col-lg-4”>4 partes</div> e <div class=”col-lg-8”>8 partes</div>, somando as 12 colunas em duas divisões com 4 e 8 partes mescladas. Perceba que após o hífen no final do nome da classe de divisão de coluna é onde você deve informar a quantidade de partes (ou colunas) que esta divisão vai ocupar na linha, uma espécie de mescla como é efeito em colunas do Excel, por exemplo.

Para uma melhor compreensão de quando cada classe para divisão de colunas deve ser utilizada, veja o conteúdo da tabela presente na Figura 8.

Classe
CSS do Bootstrap para divisão de colunas por resolução e dispositivo
Figura 8. Classe CSS do Bootstrap para divisão de colunas por resolução e dispositivo.

Para fixar os conceitos acerca do sistema de grids do Bootstrap vamos criar um layout utilizando uma grid que se comporte diferente de acordo com a resolução do dispositivo em que esteja sendo visualizada a página HTML, desta forma poderemos notar a diferença nas divisões de colunas usando as classes col-md e col-sm conforme apresentado nas Figuras 9, 10 e 11. Veja na Listagem 4 o código que exemplifica o layout em questão.

Listagem 4. Exemplo de layout utilizando o sistema de grids do Bootstrap.


  01  <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Sistema de grids</title>      
  07      <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap.min.css" > 
  08      <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap-theme.min.css" >
  09      <style rel="stylesheet" type="text/css">
  10       .estilo1{ background-color: lightgreen; border: 1px solid;} </style>
  11    </head>
  12    <body>
  13        <div class="container">
  14            <div class="row">
  15                <div class="col-md-2 col-sm-6 estilo1">LOGO </div>
  16                <div class="col-md-10 col-sm-6 estilo1">MENU</div>
  17            </div>
  18            <div class="row">
  19                <div class="col-md-6 col-sm-4 estilo1">SLIDESHOW <br><br><br></div>                
  20                <div class="col-md-6 col-sm-8 estilo1">BANNER <br><br><br></div>
  21            </div>
  22            <div class="row">
  23                <div class="col-md-3 col-sm-4 estilo1">ESQUEDA <br><br><br><br><br></div>                
  24                <div class="col-md-6 col-sm-6 estilo1">CENTRAL <br><br><br><br><br></div>                
  25                <div class="col-md-3 col-sm-2 estilo1">DIREITA <br><br><br><br><br></div>                
  26            </div>
  27            <div class="row">
  28                <div class="col-md-12 estilo1">RODAPÉ</div>                
  29            </div>
  30        </div>        
  31    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
  32     <script src= "Bootstrap-3.3.2-dist/js/Bootstrap.min.js" ></script>
  33    </body>
  34  </html>

A listagem retrata o layout fluido simples, porém com alguns detalhes que merecem destaque, a saber:

· Linhas 9 à 10: Definimos a classe estilo1 com propriedades simples para alterar a cor de fundo e borda.

· Linha 13: Criamos um container, pois precisaremos dele para estipular as propriedades responsivas citadas.

· Linhas 14, 18, 22 e 27: Perceba que foram criadas várias divs e utilizada a classe row do Bootstrap várias vezes, pois estes elementos representam linhas no layout. Veja ainda que todas estão dentro do container e é dentro dele que você pode criar divs usando a classe row para assim dividir as colunas.

· Linhas 15 e 16: Como estas linhas estão contidas dentro de uma row, criamos duas divs para representar a divisão das colunas, neste caso em duas partes: na primeira div foram definidas na propriedade class as classes com os valores col-md-2, col-sm-6 que representam o formato e quantidade de colunas destinadas a ocupar duas e seis colunas, respectivamente; e estilo1 que na realidade faz parte da divisão da mesma linha, o que muda é a quantidade de colunas utilizadas na visualização dos menus. Para entender melhor como irá se comportar a linha veja que na Figura 9 a logo assume menos colunas que o menu, já na Figura 10 tanto a logo quanto o menu tem a mesma quantidade de colunas.

· Linhas 19 e 20: Perceba que estas linhas seguem o mesmo raciocínio utilizado nas linhas 15 e 16, o que muda agora é o fato de ser uma nova linha para separar o slideshow e banner, a quantidade de colunas em ambos muda para cada tipo de dispositivo.

· Linhas 23 a 25: Aqui o interessante é que uma linha foi dividida em três divs, possibilitando ter dois painéis, um à esquerda e outro à direita, os dois com o mesmo tamanho. Por fim, temos a área central com uma div definindo col-md-6, col-sm-6 e estilo1 na propriedade class.

· Linhas 28: Para finalizar este exemplo de layout, nesta linha foi definido o rodapé com apenas uma div setando o valor na class col-md-12 e estilo1, ou seja, esta divisão ocupa toda a largura da tela com 12 colunas.

Visualização
em dispositivo acima de 1170px
Figura 9. Visualização em dispositivo acima de 1170px.
Visualização
em dispositivo entre 750px e 970px
Figura 10. Visualização em dispositivo entre 750px e 970px.

É interessante notar que a tela da Figura 11 não tem um comportamento especifico, pois não foi defino nada para a classe col-xs-. Sendo assim, temos apenas o comportamento do layout fluido do Bootstrap que coloca uma divisão abaixo da outra para obter uma melhor visualização do layout em dispositivos menores.

Visualização
em dispositivo menor que 750px
Figura 11. Visualização em dispositivo menor que 750px.

Tipografia do Bootstrap

A tipografia no Bootstrap é tudo que está relacionado com elementos textuais de um website, ou seja, títulos, textos, parágrafos, listas dentro de listas, etc. O Bootstrap por padrão já zera o CSS colocado pelos browsers no HTML, assim ele aplica outra formatação a elementos como as tags <body> e <p> que recebem outro tamanho de fonte e margem. Isso já ocorre quando são realizadas as referências ao arquivo CSS do Bootstrap, porém os ganhos não param por aí: existem várias classes CSS que podem ser utilizadas juntamente com elementos HTML para formar textos e obter uma melhor visibilidade e legibilidade. Na Listagem 5 serão apresentados vários elementos presentes na tipografia do Bootstrap.

Listagem 5. Exemplos de uso da tipografia com classe CSS do Bootstrap e elementos HTML.


  01 <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Tipografia Bootstrap</title>      
  07      <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap.min.css" > 
  08      <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap-theme.min.css" > 
  09    </head>
  10    <body>
  11        <div class="container">
  12            <h1>Título com h1 <small>Texto secundário.</small></h1>
  13            <h2>Título com h2 <small>Texto secundário.</small></h2>
  14            <h3>Título com h3 <small>Texto secundário.</small></h3>
  15            <h4>Título com h4 <small>Texto secundário.</small></h4>
  16            <h5>Título com h5 <small>Texto secundário.</small></h5>
  17            <h6>Título com h6 <small>Texto secundário.</small></h6>            
  18            <p class="lead">Aqui temos um parágrafo com texto destacado com uso da classe <mark>"lead e elemento mark"</mark>.</p>            
  19            <p> Excluindo parte de um texto: <del>Este texto foi excluído usando o elemento "del".</de></p>            
  20            <p> Incluindo texto: <ins>Este texto foi incluído com uso do "ins".</ins></p>            
  21            <p class="text-left">Texto alinhado a esquerda com uso da classe "text-left".</p>            
  22            <p class="text-center">Texto alinhado ao centro com uso da classe "text-center"</p>
  23            <p class="text-right">Texto alinhado a direita com uso da classe "text-right"</p>
  24            <p class="text-justify">Texto justificado com uso da classe text-justify.</p>            
  25            <p class="text-nowrap">Usando a classe text-nowrap</p>
  26            <p class="text-lowercase">Texto em caixa baixa com uso da classe text-lowercase.</p>
  27            <p class="text-uppercase">Texto em caixa alta com uso da classe text-uppercase.</p>
  28            <p class="text-capitalize">Texto com primeiras letras em maiúsculo com classe text-capitalize.</p>
  29       </div>        
  30    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
  31     <script src= "Bootstrap-3.3.2-dist/js/Bootstrap.min.js" ></script>
  32    </body>
  33  </html>

Sobre a listagem, podemos defini-la da seguinte forma:

  • Linhas 12 à 17: Aqui temos a definição de títulos fazendo uso dos diferentes tamanhos de texto com h1 ao h6, perceba ainda que está sendo utilizada a tag <small> em cada um dos seis títulos para exibir um texto secundário um pouco menor que o título principal.
  • Linha 18: Esta linha apresenta um parágrafo utilizando a classe lead do Bootstrap para dar um destaque a mais neste texto; você poderia fazer uso da classe lead para exibir um “Leia mais”, por exemplo. Perceba também que foi usado o elemento <mark> para destacar parte do texto deixando a cor de fundo em amarelo.
  • Linha 19: Quando for necessário excluir parte do texto de um parágrafo, você pode fazer uso da tag <del>, desta forma o texto fica em forma de taxado.
  • Linha 20: Esta linha é o inverso da linha 19, ou seja, você irá usar tag <ins> quando desejar inserir algo a mais em um texto. Veja o resultado deste exemplo na Figura 12, o texto fica sublinhado, porém o ins não serve apenas para colocar um sublinhado num texto, mas também é usado em mecanismos de busca para destacar esta inclusão.
  • Linhas 21 à 25: Aqui as classes CSS text-left, text-justify, text-center, text-right e text-nowrap são utilizadas em parágrafos para centralizar o texto em diferentes posições.
  • Linhas 26 à 28: Caso precise deixar um texto por completo em caixa alta, baixa ou apenas com as primeiras letras em maiúsculo você pode usar as classes text-uppercase, text-lowercase e text-capitalize, respectivamente.
Resultado
execução do exemplo sobre tipografia Bootstrap
Figura 12. Resultado execução do exemplo sobre tipografia Bootstrap.

Configurando o jQuery

O jQuery constitui um pequeno arquivo que pode ser facilmente baixado no endereço presente na seção Links deste artigo.

Nesta página é possível baixar as versões 1.x e 2.x do jQuery, assim como utilizar o CDN conforme foi demonstrado com o Bootstrap, ou até mesmo utilizar as referências do servidor do Google também demonstrado no mesmo exemplo. Selecione a versão 2.x com a opção de arquivo não minificado para permitir uma melhor análise da própria biblioteca. Observe que ao clicar no link de download é provável que o código seja exibido direto no browser, desta forma você pode copiar e salvar um arquivo com extensão .js conforme apresentado na Figura 13, que mostra a pasta do projeto jQuery dentro do Bootstrap.

Arquivos
js do jQuery no Bootstrap
Figura 13. Arquivos js do jQuery no Bootstrap

Query na prática

Antes de iniciar a prática com o jQuery é importante saber como utilizá-lo, pois existem formas diferentes de recuperar os elementos HTML e executar as funções JavaScript da biblioteca, dados os diferentes ambientes e frameworks onde o mesmo irá atuar. Podemos optar por duas formas:

1. Usar $(nome_elemento_html): construtor padrão do framework;

2. Usar jQuery(nome_elemento_html): construtor sobrecarregado explicitamente.

Analisemos, portanto, o exemplo apresentado na Listagem 6.

Listagem 6. Exemplo de uso da biblioteca jQuery


  01  <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Exemplo jQuery</title>                 
  07      <script type="text/javascript" src="jquery/jquery-2.1.3.min.js"></script>      
  08        <script type="text/javascript">
  09          $(document).ready(function() { 
  10              alert("Mensagem de alerta fazendo uso da jQuery.");
  11               });
  12        </script>
  13    </head>
  14    <body>                    
  15    </body>
  16  </html>

Vejamos os detalhes presentes nesta codificação:

· Linha 7: Nesta linha é realizada a referência direta à biblioteca do jQuery, ou seja, os arquivos js. Você também pode substituir pela referência ao CDN aqui nesta linha se tiver conexão com a internet.

· Linhas 8 e 12: Temos a definição de um bloco JavaScript dentro do documento HTML, o que não é boa prática. A partir da HTML5 a definição de atributos do tipo type, por exemplo, não é mais obrigatória.

· Linha 9: Aqui é usado o operador $() do jQuery, passando como parâmetro o objeto document (referência da página HTML por completo – DOM - com todos os seus elementos). Depois temos a chamada à função ready, que diz que o script só deve ser executado com determinado trecho de código JavaScript apenas quando o browser tiver renderizado todo o documento HTML (semelhante à função load da tag body). Por último, é criada uma função anônima através do comando function() e, dentro da mesma, a exibição de uma mensagem de alerta simples. Veja o resultado da execução na Figura 14.

Resultado
de execução do comando simples de alerta
Figura 14. Resultado de execução do comando simples de alerta.

Funções de estilo CSS com jQuery

No nosso projeto, faremos uso constante de funções de estilo para impor design aos elementos HTML de forma dinâmica e muitas vezes por intermédio de uma linguagem de programação server side. Ações como aplicar formatação, cor, alteração de margens, dentre outras opções, podem ser realizadas via funções de estilo. Para isso, podemos usar algumas funções do jQuery como css(), addClass(), add(), removeClass() e toggleClass(). A seguir na Listagem 7 é demonstrado como utilizar algumas destas funções.

Listagem 7. Aplicando formatação CSS a elementos com jQuery.


  01  <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Exemplo CSS jQuery</title>                 
  07      <script type="text/javascript" src="jquery/jquery-2.1.3.min.js"></script>
  08      <style rel="stylesheet" type="text/css">
  09        .estilo1{
  10            background-color: lightgreen;
  11            border: 1px solid;
  12        }
  13      </style>
  14        <script type="text/javascript">
  15          $(document).ready(function() { 
  16              $("#btn_alterar").click(function(){
  17              $("#paragrafo_1").css("color","blue")
  18              .addClass("estilo1");
  19              })});
  20        </script>
  21    </head>
  22    <body> 
  23        <p id="paragrafo_1">Estilos CSS com jQuery.</p>
  24        <button id="btn_alterar">Altera cor de fundo.</button>
  25    </body>
  26  </html>

Vejamos alguns detalhes sobre este trecho de código:

· Linhas 8 à 12: Aqui foi inserida a classe estilo1 criada anteriormente no exemplo de uso do Bootstrap. Perceba que este código apenas altera a cor de fundo e aplica uma borda. Além disso, a partir daqui começamos a mesclar ambos os frameworks para ver o poder dos dois juntos.

· Linha 23: Nesta linha é definido um parágrafo e informado o valor “paragrafo_1” para seu atributo id.

· Linha 24: É criado um botão para que possamos capturar o evento click (também via funções jQuery) e em cima disso realizar as formatações.

· Linha 16: Aqui é selecionado o elemento HTML pelo nome informado no atributo id, foi utilizado o # antes do nome e logo após é chamada a função click para monitorar os cliques no botão btn_alterar.

· Linha 17: Nesta linha é selecionado o elemento que se deseja alterar a formatação, neste caso o paragrafo_1, logo em seguida é chamada a função css() e passado como parâmetro o par de chave e valor com as propriedades de estilo que se deseja alterar.

· Linha 18: Aqui temos uso da função addClass(), que aplica ao objeto selecionado todo a formatação presente em uma classe CSS, esta que deve ser passada por parâmetro na mesma função.

O leitor deve ter percebido que as divisões de responsabilidades para cada framework até agora já tomam uma certa forma, onde temos o Bootstrap focando principalmente na estilização e componentização dos elementos HTML, enquanto o jQuery foca em dinamizar todo esse conteúdo, inclusive o próprio CSS. Veja na Figura 15 o resultado da execução dessa listagem, isto é, antes e depois do clique no botão btn_alterar.

Aplicando
estilos CSS com jQuery
Figura 15. Aplicando estilos CSS com jQuery.

Ocultando e exibindo elementos HTML com jQuery

O ocultamento de elementos HTML em páginas web é algo muito útil quando desejamos carregar todo o conteúdo de uma requisição, mas não exibir tudo de uma vez. Isso serve, inclusive, para diminuir o tráfego de dados na rede e aumentar a performance da aplicação para fins de usabilidade, SEO, etc.

Existem duas funções bastante úteis no jQuery para controlar a visibilidade de elementos na janela do browser: hide() para ocultar um elemento e show0 para tornar o mesmo visível. Então, é possível controlar a visibilidade dinamicamente no lado do cliente sem ser preciso enviar uma requisição ao servidor e ter que renderizar novamente a página, poupando tempo e consumo de banda.

Veja na Listagem 8 como é simples ocultar e exibir elementos utilizando a biblioteca jQuery e tenha uma prévia de como faremos isso no nosso projeto com a Figura 16.

Listagem 8. Aplicando funções hide() e show() com jQuery.


  01  <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Exemplo visibilidade com jQuery</title>                 
  07      <script type="text/javascript" src="jquery/jquery-2.1.3.min.js"></script>
  08      <style rel="stylesheet" type="text/css">
  09        .estilo1{
  10            background-color: lightgreen;
  11            border: 1px solid;
  12        }
  13      </style>
  14        <script type="text/javascript">
  15          $(document).ready(function() { 
  16              $("#btn_ocultar").click(function(){
  17                $("#mensagem").hide();
  18                $("#btn_ocultar").hide();
  19                $("#btn_exibir").show();
  20              });
  21              
  22              $("#btn_exibir").click(function(){
  23                $("#mensagem").show();
  24                $("#btn_ocultar").show();
  25                $("#btn_exibir").hide();
  26              });
  27          });
  28        </script>
  29    </head>
  30    <body> 
  31        <p id="mensagem">Cadastro realizado com sucesso.</p>
  32        <button id="btn_ocultar">Ocultar mensagem</button>
  33        <button id="btn_exibir">Exibir mensagem</button>
  34    </body>
  35  </html>

Na listagem, podemos perceber dentre outras coisas:

· Linha 31: Aqui foi inserido um parágrafo exibindo uma mensagem de confirmação de cadastro, este elemento é o que iremos controlar para exibição de uma forma geral.

· Linhas 32 e 33: Foram definidos dois botões, um para exibir a mensagem da linha 31 e outro para ocultar a mesma.

· Linhas 17 à 19: É utilizada a função hide() para ocultar o botão btn_ocultar e o parágrafo “mensagem”, logo após é exibido o botão btn_exibir através do show(). Por fim, nas linhas 23 à 25 é realizado o mesmo processo, porém de forma invertida, ou seja, exibir o botão btn_exibir e a mensagem novamente.

Resultado
da execução das funções
Figura 16. Resultado da execução das funções show() e hide().

HTML dinâmico com jQuery e Bootstrap

O jQuery possibilita gerar elementos HTML dinamicamente e inseri-los em uma página. Para exemplificar, vejamos como realizar este processo fazendo uso também do Bootstrap para criar um pequeno cadastro de clientes que será apresentado apenas quando o usuário clicar no botão cadastrar. Veja na Listagem 9 todo o código necessário para criar este formulário e os comentários sobre o mesmo em seguida.

Listagem 9. Gerando código HTML dinamicamente com jQuery.


  01  <!DOCTYPE html>
  02  <html lang="pt-BR">
  03    <head>
  04      <meta charset="utf-8">   
  05      <meta name="viewport" content="width=device-width, initial-scale=1">
  06      <title>Gerando elementos html com jQuery</title>                 
  07      <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap.min.css" > 
  08      <link rel= "stylesheet" href= "Bootstrap-3.3.2-dist/css/Bootstrap-theme.min.css" >   
  09      <script type="text/javascript" src="jquery/jquery-2.1.3.min.js"></script>
  10      <script type="text/javascript" src= "Bootstrap-3.3.2-dist/js/Bootstrap.min.js" ></script>      
  11
  12      
  13        <script type="text/javascript">
  14          $(document).ready(function() { 
  15              $("#btn_formulaio").click(function(){
  16                  $("form").append("<div class='container'>" + "<div class='jumbotron'>" +
  17                              "<div id='div_nome' class='form-group'></div>" + "</div>" + "</div>");                                    
  18                  
  19                  $("#div_nome").append("<label>::CADASTRO DE CLIENTE::</label></br></br>");                  
  20                  $("#div_nome").append("<label>Nome</label>");
  21                  var inputNome = $("<input />", {id:"inputNome", class:"form-control"});
  22                  $("#div_nome").append(inputNome);
  23                  
  24                  $("#div_nome").append("<label>CPF</label>");
  25                  var inputCPF = $("<input />", {id:"inputCPF", class:"form-control"});
  26                  $("#div_nome").append(inputCPF);
  27                  
  28                  $("#div_nome").append("</br></br><button type='submit' class='btn btn-default'>Cadastrar</button>");
  29              })});
  30        </script>
  31    </head>      
  32    <body>         
  33        <button id="btn_formulaio" class="btn btn-default">Cadastro cliente</button></br></br>        
  34        <form>
  35        </form>        
  36    </body>
  37  </html>

Veja a seguir alguns detalhes importantes a serem citados em relação à listagem:

· Linha 7 a 10: Temos as referências aos arquivos CSS e JS do Bootstrap e da biblioteca jQuery (a ordem não altera os resultados).

· Linhas 13 à 30: É definido o JavaScript que faz uso do jQuery responsável por gerar dinamicamente todo o código HTML.

· Linha 33: Foi criado um botão que será utilizado para disparar o evento de click para gerar o formulário de cadastro de cliente dinamicamente na página.

· Linhas 34 e 35: Nestas linhas temos as tags de abertura e fechamento do formulário HTML que receberá os elementos para o usuário preencher.

· Linha 14: Definição da função ready que aguarda a renderização por completo da página e aguarda o clique do usuário no botão cadastrar.

· Linha 15: Seleção do botão btn_formulaio para recuperar o evento click e em seguida gerar o formulário.

· Linhas 16 e 17: Aqui, a geração dos elementos HTML é iniciada e são chamadas as classes CSS para gerar o formulário com aparência de alguns componentes originais do Bootstrap. Perceba que foi selecionado o form que está dentro do body através do $("form"), em seguida é chamada a função append que recebe como parâmetro um código HTML a ser inserido conforme o elemento selecionado, neste caso o form. Também é interessante observar que foram inseridas três divs usando as seguintes classes do Bootstrap: container, jumbotron e form-group, que serão responsáveis pelo alinhamento.

· Linhas 19 e 20: Aqui também é gerado mais código HTML, neste caso os elementos propriamente ditos do formulário, como a label de título, etc. Veja que foi utilizada a função append e selecionada a div com o id ‘div_nome’ gerada anteriormente, dessa forma podemos notar que embora o JavaScript não tenha sido executado por completo já é possível usar os elementos gerados na instrução anterior através desta função.

· Linha 21: Aqui é gerado um elemento do tipo input, porém foi criada primeiro uma variável inputNome e em seguida gerado o elemento com dois parâmetros: o tipo do elemento e o <input />. Em seguida, finalizamos com as configurações finais do Bootstrap.

· Linha 22: Mesmo processo das linhas 24 à 26, para gerar o elemento de CPF.

· Linha 28: Por fim, é criado o botão de cadastro de fato com as classes btn btn-default de formatação do botão de input do Bootstrap.

Veja na Figura 17 o resultado da execução do código, observando os efeitos de usar ambos os frameworks juntos. Pressione a tecla F12 no seu navegador e observe se algum log de erro JavaScript foi impresso no console de depuração do mesmo.

Tela
de cadastro dinâmica com jQuery e Bootstrap
Figura 17. Tela de cadastro dinâmica com jQuery e Bootstrap.

Esta primeira parte do artigo teve como objetivo realizar uma breve introdução ao Bootstrap e à biblioteca jQuery, mas ainda tem muito a ser explorado sobre os mesmos. Além disso, é de suma importante que você tenha uma boa noção de tecnologias como HTML5, CSS3 e JavaScript para melhor compreensão do artigo e, dessa forma, possa ganhar experiência e produtividade em projetos que focam nas mesmas.

Links

Website Bootstrap
http://getBootstrap.com/

Download Bootstrap
http://getBootstrap.com/getting-started/#download

Compilador Grunt usado no Bootstrap
http://gruntjs.com/

Tradução Bootstrap realizada pela Globo.com
https://getbootstrap.com.br/

Download WampServer
http://www.wampserver.com/en/

Download biblioteca jQuery
http://jquery.com/


PARTE II
Veja abaixo a segunda parte do artigo - Agora as partes I e II foram compiladas em um único artigo. Bons estudos :)


Por que eu devo ler este artigo:Este artigo finaliza a construção do nosso PDV Web para vendas de produtos utilizando os frameworks Bootstrap e jQuery no front-end e o PHP, MySQL e Slim Framework no back-end. Inicialmente, o leitor poderá entender como funcionam todas essas tecnologias em conjunto e atreladas a regras de negócio próximas da realidade de aplicações corporativas. Verá também a maioria das classes e métodos presentes na API dessas plataformas, e como eles podem te ajudar a simplificar o processo de criação de CRUDs e implementações comuns a esse tipo de sistema. Além disso, configurações de requisições assíncronas usando Ajax também serão alvo deste artigo, o que trará um ar mais profissional ao aplicativo final.

Para dar continuidade à construção do PDV será desenvolvido um modelo DER para o banco de dados e a partir deste implementaremos o serviço REST com PHP e o Slim framework. No front-end será criado um layout moderno e responsivo com Bootstrap, onde faremos uso extensivo de JavaScript e jQuery para a implementação das regras de negócio juntamente às requisições assíncronas via Ajax feitas ao servidor remoto para obter acesso aos dados no banco de dados MySQL.

Apesar de estarmos trabalhando essencialmente com os frameworks na camada cliente, será necessária também a utilização de uma infraestrutura de back-end para expor serviços baseados no REST, o que permitirá que os mesmos possam ser consumidos no lado cliente da aplicação, por intermédio, essencialmente, do jQuery e do Ajax. O serviço REST retornará dados no formato JSON, que é um padrão do JavaScript e pode ser manipulado facilmente com jQuery.

O fluxo de execução do nosso PDV Web consiste, basicamente, em um usuário realizar o login no sistema, abrir uma venda, informar o cliente, vender itens que irão compor os dados da venda como um todo e por fim encerrar a venda. Para o desenvolvimento do sistema será criada uma página similar ao um software PAFECF de supermercado, o qual se caracteriza por detalhar os itens vendidos e os totalizar ao final da venda.

DER para o banco de dados MySQL

No desenvolvimento de qualquer sistema é necessário o máximo de documentação possível para que a equipe de desenvolvimento possa construir um software sem ambiguidade. No caso do nosso PDV será desenvolvido um DER para que possamos criar o banco de dados no SGDB MySQL e, a partir do mesmo, nortear a forma como implementaremos todo o back-end e front-end da aplicação.

O DER será composto por cinco tabelas:

· produto, que irá armazenar as informações de todos os produtos a serem vendidos;

· cliente, pois cada venda deverá ser realizada para um cliente em especifico;

· usuario, para que o funcionário caixa possa logar no sistema e termos, automaticamente, um histórico das vendas efetuadas por ele;

· venda_cabecalho, para armazenar informações genéricas sobre as vendas;

· E por fim itens_venda, que irá armazenar os dados dos itens vendidos para o cliente com as respectivas quantidades, preço unitário e subtotal, que, por sua vez, serão úteis quando precisarmos formar um cupom não-fiscal.

Para uma melhor compreensão do DER, analise as tabelas e seus campos presentes na Figura 1.

DER do banco
de dados PDV Web
Figura 1. DER do banco de dados PDV Web.

Vejamos alguns detalhes importantes sobre as tabelas e campos que formam o DER:

· Tabela Usuário: Esta tabela tem como objetivo armazenar todos os usuários que farão uso do sistema. No caso especifico do PDV, serão os caixas que efetuarão login para realizar vendas aos clientes. Esta tabela tem vários campos como id do usuário, nome, login, senha (que será armazenada criptografada no banco), campo ativo para inativar o usuário caso seja necessário e data de cadastro.

· Tabela Cliente: A venda de produtos no PDV só será permitida se for informado um cliente no ato da abertura da venda. Neste caso, esta tabela irá servir para o cadastro de clientes. Os campos desta tabela são auto descritivos e não necessitam de maiores detalhes.

· Tabela Produto: Esta tabela tem como objetivo armazenar todos os produtos que poderão ser vendidos pela empresa. O campo id_produto irá armazenar o código identificador do produto (que será autogerado); o campo nome serve para informar a marca do produto e será apresentado na página no ato da venda; o campo descricao irá guardar um detalhamento maior sobre o produto; o campo imagem irá salvar a foto do produto na página; dentre outros.

· Tabela Venda Cabeçalho: Esta tabela irá armazenar os dados das vendas realizadas, neste caso o código da venda, código do usuário caixa, código do cliente que realizou a compra, quantidade de itens vendidos, valor total da venda, status da venda (que pode ser finalizada, cancelada, em andamento e outros), e por fim a data e hora que ocorreu a venda.

· Tabela Itens Venda: Esta tabela tem como objetivo gravar os dados de cada item vendido, este que representa um produto em especifico. Nesta tabela será armazenada a sequência de itens vendidos, valor unitário, subtotal e status do item vendido.

Banco de dados MySQL

Para armazenar todos os dados iremos utilizar o SGDB MySQL, sendo primeiro necessário gerar o script SQL através do próprio DBDesigner. Para gerá-lo, siga as seguintes opções: Clique no menu File > Export > SQL create script, logo em seguida uma janela irá abrir conforme apresentado na Figura 2 (essa mesma figura já apresenta o gerenciador do MySQL - o SQLyog - com o banco de dados e as tabelas do PDV Web criados). No campo Target Data Base selecione a opção MySQL e por fim clique no botão Copy Script to Clipborad.

Essa opção permite que você cole o conteúdo do comando em qualquer editor de texto. Para isso, crie um banco de dados chamado “pdv_web”, abra uma janela de query na ferramenta e cole o script SQL. Veja na Listagem 1 o script gerado. Após isso, basta executar o mesmo.

Listagem 1. Script SQL para gerar o banco de dados PDV Web


  01 CREATE TABLE produto (
  02  id_produto INTEGER UNSIGNED  NOT NULL   AUTO_INCREMENT,
  03  nome VARCHAR(40)  NULL  ,
  04  descricao VARCHAR(60)  NULL  ,
  05  preco_compra DOUBLE(15,2)  NULL  ,
  06  preco_venda DOUBLE(15,2)  NULL  ,
  07  qtde_estoque DOUBLE(15,2)  NULL  ,
  08  imagem_produto TEXT  NULL  ,
  09  ativo CHAR(1)  NULL  ,
  10  data_cadastro DATE  NULL    ,
  11 PRIMARY KEY(id_produto));
  12
  13 CREATE TABLE usuario (
  14  id_usuario INTEGER UNSIGNED  NOT NULL   AUTO_INCREMENT,
  15  nome VARCHAR(100)  NULL  ,
  16  login VARCHAR(30)  NULL  ,
  17  senha VARCHAR(50)  NULL  ,
  18  ativo CHAR(1)  NULL  ,
  19  data_cadastro DATE  NULL    ,
  20 PRIMARY KEY(id_usuario));
  21
  22 CREATE TABLE cliente (
  23  id_cliente INTEGER UNSIGNED  NOT NULL   AUTO_INCREMENT,
  24  nome VARCHAR(100)  NULL  ,
  25  cpf_cnpj VARCHAR(14)  NULL  ,
  26  rg VARCHAR(20)  NULL  ,
  27  endereco VARCHAR(100)  NULL  ,
  28  bairro VARCHAR(60)  NULL  ,
  29  cidade VARCHAR(60)  NULL  ,
  30  estado VARCHAR(50)  NULL  ,
  31 telefone VARCHAR(12)  NULL  ,
  32  email VARCHAR(50)  NULL  ,
  33  ativo CHAR(1)  NULL  ,
  34  data_cadastro DATE  NULL    ,
  35 PRIMARY KEY(id_cliente));
  36
  37 CREATE TABLE venda_cabecalho (
  38  id_venda_cabecalho INTEGER UNSIGNED  NOT NULL   AUTO_INCREMENT,
  39  id_usuario INTEGER UNSIGNED  NOT NULL  ,
  40  id_cliente INTEGER UNSIGNED  NOT NULL  ,
  41  qtde_itens INTEGER UNSIGNED  NULL  ,
  42  valor_total DOUBLE(15,2)  NULL  ,
  43  status_venda VARCHAR(20)  NULL  ,
  44  data_hora_venda DATETIME  NULL    ,
  45 PRIMARY KEY(id_venda_cabecalho)  ,
  46 INDEX venda_cabecalho_FKIndex1(id_cliente)  ,
  47 INDEX venda_cabecalho_FKIndex2(id_usuario),
  48  FOREIGN KEY(id_cliente)
  49    REFERENCES cliente(id_cliente)
  50      ON DELETE NO ACTION
  51      ON UPDATE NO ACTION,
  52  FOREIGN KEY(id_usuario)
  53    REFERENCES usuario(id_usuario)
  54      ON DELETE NO ACTION
  55      ON UPDATE NO ACTION);
  56
  57 CREATE TABLE itens_venda (
  58  id_itens_venda INTEGER UNSIGNED  NOT NULL   AUTO_INCREMENT,
  59  id_produto INTEGER UNSIGNED  NOT NULL  ,
  60  id_venda_cabecalho INTEGER UNSIGNED  NOT NULL  ,
  61  sequencia INTEGER UNSIGNED  NULL  ,
  62  qtde INTEGER UNSIGNED  NULL  ,
  63  valor_unitario DOUBLE(15,2)  NULL  ,
  64  sub_total DOUBLE(15,2)  NULL  ,
  65  status_item VARCHAR(20)  NULL    ,
  66 PRIMARY KEY(id_itens_venda)  ,
  67 INDEX itens_venda_FKIndex1(id_venda_cabecalho)  ,
  68 INDEX itens_venda_FKIndex2(id_produto),
  69  FOREIGN KEY(id_venda_cabecalho)
  70    REFERENCES venda_cabecalho(id_venda_cabecalho)
  71      ON DELETE NO ACTION
  72      ON UPDATE NO ACTION,
  73  FOREIGN KEY(id_produto)
  74    REFERENCES produto(id_produto)
  75      ON DELETE NO ACTION
  76      ON UPDATE NO ACTION);

Banco de
dados PDV Web gerado pelo DBDesigner e SQLyog
Figura 2. Banco de dados PDV Web gerado pelo DBDesigner e SQLyog

Download e instalação do XAMPP

Antes da codificação do PDV Web é necessário baixar o XAMPP, um pacote que já tem o PHP, o servidor Apache e outras ferramentas para controle e administração de websites. Você pode baixar o XAMPP através do link de download do mesmo presente na seção Links deste artigo.

Para instalar, basta executar o instalador e ir avançando entre as telas sem alterar as opções já selecionadas. Após a conclusão da instalação, execute o XAMPP Control Panel (uma das opções que vem junto do instalador) e aguarde até que o ícone de administração ao lado do relógio do Windows apareça. Clique duas vezes no ícone para abrir o painel de controle conforme apresentado na Figura 3.

Painel de
controle do XAMPP
Figura 3. Painel de controle do XAMPP.

Perceba que estamos executando apenas o módulo Apache (destacado na cor verde) que roda na porta 8090. O leitor pode optar se deseja executar o MySQL pelo XAMPP ou se deseja instalar um SGBD à parte, como o Workbench (usaremos esta opção pela facilidade que ela apresenta). Caso não tenha instalado o MySQL em sua máquina não se preocupe, pois no ato da instalação do XAMPP o mesmo também foi instalado.

Outro detalhe importante a respeito do XAMPP é a porta que o servidor Apache usa por padrão, a porta 80. Alguns programas, como o Skype, também usam a mesma porta, logo quando você tentar iniciar o servidor poderá ter problemas de barramento. Para resolver isso, basta parar o programa via Gerenciador de Tarefas e tudo funcionará normalmente.

Download e configuração do Slim framework

Iniciaremos a implementação do PDV pelo desenvolvimento do serviço baseado em REST que o front-end irá consumir via Ajax com o auxílio do jQuery. Para isso, efetue o download do zip do Slim Framework através do site que consta na seção Links.

Para usá-lo basta descompactar os arquivos e copiar para dentro da pasta da aplicação web, neste caso a pasta do PDV Web. Essa pasta, assim como toda a estrutura do projeto, deverá ser criada dentro do diretório “C:\xampp\htdocs”, que é o local padrão para salvar os arquivos de websites quando se utiliza o servidor Apache com XAMPP.

Para evitar desperdício de espaço, descompacte o arquivo zip do Slim Framework em outro local de sua máquina e copie apenas a pasta Slim e o arquivo .htaccess para dentro da pasta pdv da aplicação PDV Web localizada dentro do diretório htdocs.

Após realizado este procedimento, ainda é necessário configurar o arquivo htaccess do Slim para apontar para o arquivo PHP que terá as rotas de implementação do mesmo referente ao serviço REST da aplicação. Defina o código do arquivo htaccess conforme apresentado na Listagem 2 e logo em seguida crie um arquivo dentro da pasta pdv denominado slim_rest.php. Este arquivo irá conter toda a configuração e implementação do serviço a ser utilizado pelo front-end da aplicação.

Listagem 2. Configuração do arquivo htaccess do Slim framework.


  01 RewriteEngine On
  02
  03 RewriteCond %{REQUEST_FILENAME} !-d
  04 RewriteCond %{REQUEST_FILENAME} !-f
  05 RewriteRule ^ slim_rest.php [QSA,L]

A configuração mais importante está na linha 5, que aponta para o arquivo recém-criado slim_rest.php. Ela é importante pois esse arquivo representará toda a implementação do serviço baseado no padrão arquitetural REST.

Serviço REST para autenticação de usuários

O primeiro passo para a implementação do serviço que proverá a autenticação de usuário no sistema será a criação do arquivo Bd.php que terá toda a configuração necessária para o acesso ao banco de dados. Crie este arquivo dentro para pasta pdv e adicione ao mesmo o código da Listagem 3.

Listagem 3. Arquivo de configuração para acesso ao banco de dados MySQL.


  01 <?php 
  02
  03 session_start();
  04
  05 function getConnection() {
  06     $dbhost="localhost";
  07     $dbuser="root";
  08     $dbpass="root";
  09     $dbname="pdv_web";
  10     $dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);    
  11     $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  12     return $dbh;
  13 }

A função getConnection retorna um objeto da classe PDO que é responsável por encapsular o acesso ao banco de dados. Sempre que for necessário realizar uma operação no banco de dados basta chamar este método e realizar a operação. Vejamos mais alguns detalhes:

· Linha 3: Esta linha faz a chamada à função session_start() que diz ao PHP que iremos trabalhar com a sessão no lado do servidor e que informações persistentes deverão ser sempre guardadas entre requisições HTTP. Também faremos uso da sessão para armazenar os dados do usuário logado no sistema.

· Linhas 6 a 9: Aqui definimos algumas variáveis para armazenar o endereço do servidor MySQL, nome de usuário, senha e o nome do banco de dados.

· Linha 10: Aqui é criado um objeto denominado dbh que recebe uma instancia da classe PDO do PHP. Perceba que foram passados como parâmetros todos os dados necessários para conectar ao banco de dados MySQL.

· Linha 11: Nesta linha são configurados alguns atributos para exibir um relatório de erro e exceções caso ocorra algum problema durante o acesso ao banco de dados. Como estaremos trabalhando de forma assíncrona com o serviço REST, será necessário repassar ao cliente o máximo de informação possível caso isso aconteça. Desta forma, será mais fácil identificar erros e tomar as devidas providências para solução.

Com o arquivo de acesso ao banco de dados devidamente configurado agora podemos implementar o serviço de autenticação de usuário. Para realizar este procedimento, abra o arquivo slim_rest.php criado anteriormente e implemente no mesmo o código da Listagem 4.

Ela, basicamente, inicia e configura algumas informações do Slim framework, implementando também duas rotas de acesso ao serviço de autenticação:

· A rota /pdv/autenticarUsuario para autenticar o usuário;

· E /pdv/logout para finalizar a sessão do usuário no sistema.

Listagem 4. Implementação do serviço para autenticação de usuários no sistema.


  01 <?php
  02 require ''Bd.php'';
  03 require ''Slim/Slim.php'';
  04
  05    \Slim\Slim::registerAutoloader();
  06    $app = new \Slim\Slim();
  07    $app->add(new \Slim\Middleware\SessionCookie(array(''secret'' => ''myappsecret'')));
  08
  09 //Início login--------------------------------------------------------------
  10 $app->post("/autenticarUsuario", function () use ($app) {
  11   $login = $app->request()->post(''login'');
  12    $senha = $app->request()->post(''senha'');
  13     $senhaCriptada = md5($senha);
  14     
  15
  16     $sql = "SELECT * FROM usuario WHERE login = :login AND senha = :senha";
  17     try {
  18           $db = getConnection();
  19           $stmt = $db->prepare($sql);  
  20           $stmt->bindParam("login", $login);             
  21           $stmt->bindParam("senha", $senhaCriptada);
  22           $stmt->execute();
  23           
  24           $objUsuario = $stmt->fetchObject(); 
  25           $db = null;
  26                  
  27           if ($objUsuario != null) { 
  28                  $_SESSION[''id_usuario''] = $objUsuario->id_usuario;
  29            $_SESSION[''nome''] = $objUsuario->nome;
  30                  $app->redirect("/pdv/pdv_web.php");
  31           } else {
  32                  $erro = "Erro na autenticação";
  33                  $app->redirect("/pdv/pdv_web.php?erro=".$erro);
  34           }                   
  35     } catch(PDOException $e) {
  36           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  37     }      
  38 });
  39
  40 $app->get("/logout", function () use ($app) {      
  41        unset($_SESSION[''id_usuario'']);
  42        unset($_SESSION[''nome'']);
  43        session_destroy();
  44        header("location: /pdv/pdv_web.php");
  45        exit;
  46 });
  47 //Fim login-------------------------------------------------------------
  48
  49 $app->run();
  50 ?>

Essa listagem apresenta várias características importantes, a saber:

· Linhas 2 e 3: Aqui é utilizado o comando require para que possamos ter acesso às funções definidas no arquivo Bd.php.

· Linhas 5 a 7: Configuramos o registro de carregamento do Slim, através da criação de um objeto chamado $app que, por sua vez, recebe uma instância do próprio Slim. Por fim, é chamada a função add do Slim para informar ao SessionCookie que podemos trabalhar com a sessão em conjunto com o Slim e o PHP.

· Linha 10: Nesta linha é definida a primeira rota chamada “/autenticarUsuario” do serviço de autenticação de usuários. Perceba que estamos usando a função post() do Slim passando o caminho da rota e o objeto app como argumentos. Isso significa que se quisermos acessar este serviço, devemos realizar sempre uma requisição POST ao servidor através do protocolo HTTP.

· Linhas 11 e 13: Aqui são criadas duas variáveis para recuperar o login e senha da requisição realizada via POST ao servidor. Perceba que foram utilizadas as funções request() e post() que recuperam os inputs do formulário HTML submetido ao servidor. Logo em seguida, é criada a variável senhaCriptada que recebe a senha criptografada através da chamada à função md5() do PHP. Desta forma, podemos consultar a senha na base de dados sem problemas, uma vez que a mesma se encontra criptografada.

· Linha 16: Nesta linha é definida a instrução SQL que verifica se o login e senha do usuário existem e conferem com os dados armazenados no banco. Perceba na instrução que os valores :login e :senha têm dois pontos na frente, isso significa que mais adiante iremos alterar estes valores pelos valores das variáveis que contém os reais valores de login e sanha, e, para isso, faremos uso da função bindParam.

· Linha 18 a 22: A função prepare() recebe a instrução SQL a ser executada no banco. Logo após chamamos a função bindParam() para alterar os valores de :login e :senha e, por fim, a função execute() é chamada para realizar a consulta na base de dados.

· Linhas 24 e 25: Neste intervalo, primeiramente é criado um objeto chamado objUsuario que recebe o resultado da consulta, e em seguida a função fetchObject() retorna o registro pertinente ao login e senha do usuário. Por fim, setamos null à variável db para inutilizá-la.

· Linhas 27 a 38: Validamos a autenticação do usuário e criamos duas sessions para armazenar o ID e o nome do usuário. Observe nas linhas 30 e 33 a utilização da função redirect() para redirecionar o usuário a outra página específica.

· Linha 40 a 46: A função get do Slim cria uma nova rota chamada “/logout” para que o usuário possa realizar o logoff no sistema. Esta rota deve ser acessada via requisição GET do HTTP. Usamos também o unset e o session_destroy para finalizar a sessão do usuário, e por fim é definida a página de redirecionamento no header, chamando o exit em seguida.

· Linha 49: A função run() do Slim é chamada para, de fato, tornar estas rotas acessíveis.

Bootstrap e jQuery

O Bootstrap é um framework que disponibiliza uma série de componentes CSS, JavaScript, ícones, templates, dentre outros recursos que facilitam o desenvolvimento de aplicações web. Você pode baixá-lo através do endereço também disponível na seção Links deste artigo.

Uma vez na página de download, deve ser baixado o arquivo da primeira opção: “Compiled and minified CSS, JavaScript, and fonts.” que tem uma versão minificada que deixa o carregamento das páginas do website com uma melhor performance. Após o download do zip, você deve extrair o mesmo dentro do diretório pdv localizado na pasta htdocs do XAMPP. Certifique-se de ter extraído as pastas css, js e fonts para dentro de pdv.

Nós também precisaremos baixar o arquivo do jQuery. Acessa a página de download na seção Links e baixe o arquivo referente à versão 1.11.2 e o posicione dentro do diretório js localizado na mesma pasta pdv.

Crie também um arquivo chamada javascript_pdv.js, pois é neste arquivo que colocaremos todo o código JavaScript da aplicação. É através do jQuery que serão realizadas todas as requisições assíncronas via Ajax ao serviço fornecido pelo Slim Framework.

No arquivo de downloads desse artigo, você encontrará também uma pasta chamada “img” com algumas imagens de produtos a serem vendidos no PDV, mas o leitor pode ficar à vontade para usar as que quiser.

Para finalizar esta etapa, veja na Figura 4 como deve ficar a estrutura de pastas e arquivos final do nosso projeto.

Estrutura de
pastas e arquivos do projeto PDV Web
Figura 4. Estrutura de pastas e arquivos do projeto PDV Web.

Estrutura de páginas Front-end e autenticação de usuário

Com o serviço REST para autenticação de usuário rodando no back-end e os devidos frameworks front-end distribuídos, agora é o momento de criar a estrutura de páginas do projeto, a começar pela página inicial do PDV Web.

Para isso vamos quebrar a página index em três: header, body e footer, desta forma iremos reaproveitar o header e o footer nas demais páginas que futuramente possam ser incluídas ao projeto. Esta estrutura de divisão é uma boa prática no PHP, pois através do comando require podemos incluir estruturas completas de código mesclado entre PHP, HTML e JavaScript em outras páginas do projeto, tornando-o mais manutenível.

A primeira página a ser criada é a “header.php”, que tem com propósito exibir o menu superior para colocar os links da página e também terá embutido o formulário de login para autenticação do usuário. Nesta página, usaremos várias classes do Bootstrap para criar o menu fixo e para que ele se adapte ao tamanho da tela do dispositivo do usuário, com um layout adaptável e responsivo.

Veja na Listagem 5 como deve ficar a implementação da referida página.

Listagem 5. Implementação da página “header.php”.


  01 <?php session_start(); ?>
  02 <!DOCTYPE html>
  03 <html lang="pt-br">
  04  <head>
  05    <meta charset="utf-8">
  06    <meta name="viewport" content="width=device-width, initial-scale=1">
  07    <title>PDV Web</title>
  08     <link href="css/bootstrap.min.css" rel="stylesheet">  
  09  </head>
  10  <body>
  11    <nav class="navbar navbar-inverse navbar-fixed-top">
  12      <div class="container">
  13        <div class="navbar-header">
  14          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
  15            <span class="sr-only">PDV Web</span>
  16            <span class="icon-bar"></span>
  17            <span class="icon-bar"></span>
  18            <span class="icon-bar"></span>
  19          </button>
  20          <a class="navbar-brand" href="#">PDV Web</a>
  21        </div>
  22           
  23        <div id="navbar" class="navbar-collapse collapse">
  24           
  25           <?php
  26             if(isset($_SESSION[''id_usuario''])){            
  27            echo "<ul class=''nav navbar-nav''><li><a href=''#''> Seus links aqui.</a></li></ul>";              
  28            echo "<label id=''id_usuario'' hidden=''hidden''>".$_SESSION[''id_usuario'']."</label>"; 
  29                  echo "<div class=''navbar-form navbar-right''>
  30                         <div class=''form-group''>
  31                                <label for=''usuarioLogado'' style=''color:#FFFFFF''>Olá ". $_SESSION[''nome''] ."!</label>
  32                                <a class=''btn btn-success'' href=''/pdv/logout''>Sair</a>
  33                         </div>
  34                  </div>";                                
  35                  }else{
  36                  echo "<form class=''navbar-form navbar-right'' method=''post'' action=''/pdv/autenticarUsuario''>
  37                         <div class=''form-group''>
  38                                <input name=''login'' type=''text'' placeholder=''login'' class=''form-control''>
  39                         </div>
  40                         <div class=''form-group''>
  41                                <input name=''senha'' type=''password'' placeholder=''senha'' class=''form-control''>
  42                         </div>
  43                                <button type=''submit'' class=''btn btn-success''>Logar</button>
  44                         </form>"; 
  45                  }
  46           ?>                  
  47        </div>
  48      </div>
  49    </nav>

Aqui está toda a implementação necessária para o header do PDV Web juntamente com o formulário de autenticação, porém são necessárias algumas explicações sobre este código. Veja a seguir mais detalhes:

· Linha 1: A primeira linha ativa a session_start() do PHP e pode, mais à frente, verificar se existe algum usuário logado no sistema.

· Linha 2: Aqui temos a tag DOCTYPE que define que o projeto irá utilizar HTML 5.

· Linha 3: Define o idioma que será utilizado na página, esta prática é importante pois é verificada pelos motores de busca na internet.

· Linhas 4 a 7: Na linha 5 é definido dentro do head o padrão de caracteres a ser utilizado pelo browser para renderizar a página, logo após na linha 6 é definido o meta viewport para que o Bootstrap possa capturar a informação sobre tipo e tamanho do dispositivo do cliente que está visualizando a página e assim possa aplicar os recursos de responsividade.

· Linha 8: Esta linha realiza uma referência ao arquivo bootstrap.min.css que é um stylesheet que contém todo o código CSS do Bootstrap para ser utilizado na página.

· Linha 11 e 49: Aqui é defino o bloco HTML da barra de navegação utilizando as classes CSS navbar, navbar-inverse e navbar-fixed-top do Bootstrap, que irão deixar a navegação fixa no topo da página. É aqui que você deve colocar os links de navegação de sua página conforme exemplo do link fake da linha 27.

· Linha 26: Nesta linha tem uma condicional if que, através da função isset do PHP, verifica se existe um usuário logado no sistema com o uso do comando $_SESSION[''id_usuario''], onde ‘''id_usuario''’ é o nome dado à sessão que contém o valor do ID do mesmo. Caso positivo, será executado o bloco de código entre as linhas 27 e 34 que apresenta o nome do usuário logado conforme linha 31. Na sequência, na linha 32, foi inserido um link que aponta para o serviço “/pdv/logout''” para que o usuário possa fazer logoff no sistema.

· Linhas 35 a 45: Contém o bloco else, ou seja, caso não exista nenhum usuário logado no sistema será exibido um formulário HTML para autenticar via POST junto ao serviço de rota ''/pdv/autenticarUsuario''.

Com a página header criada já temos o sistema de login disponível e em funcionamento, porém é necessário ter o banco de dados populado com dados para testes. Assim sendo, você deve inserir no MySQL o banco de dados contido nos fontes do projeto (caso use o que está disponível no arquivo de fontes, use o login: madson e a senha: 123), para realizar o teste de autenticação de usuário no PDV Web, conforme pode ser visto na Figura 5.

Sistema de autenticação de usuário em
funcionamento
Figura 5. Sistema de autenticação de usuário em funcionamento.

Agora é necessário criar a página footer.php que exibirá as informações do rodapé e realizará referências aos arquivos JavaScript que serão necessários utilizar no PDV Web. Veja na Listagem 6 como deve ficar a implementação dessa página.

No intervalo entre as linhas 7 e 9 temos as referências aos arquivos JavaScript do jQuery, Bootstrap e o js do PDV que será implementado mais adiante. Observe a sequência das referências aos arquivos js, pois existe uma dependência entre eles.

É importante colocar a referências aos arquivos após o último elemento da tag body, desta forma a página terá uma melhor performance no carregamento, uma vez que o browser já terá renderizado todos os elementos DOM da página. Isso é importante, pois evita erros nos códigos JavaScript que buscam elementos na página sem que ela tenha sido renderizada.

Listagem 6. Implementação da página “footer.php”.


  01     <div class="container">
  02      <footer>
  03        <p>© Devmedia 2014</p>
  04      </footer>
  05    </div>
  06     
  07     <script src="js/jquery-1.11.2.min.js"></script>
  08    <script src="js/bootstrap.min.js"></script>
  09     <script src="js/javascript_pdv.js"></script>
  10     </body>
  11 </html>

Página principal do PDV Web

Vamos criar agora uma nova página PHP chamada ‘pdv_web.php’. A mesma terá toda a estrutura de um layout para um PDV através do uso do Bootstrap e seu sistema de grids que é divido em linhas e colunas. Primeiramente, vejamos a estrutura estática da página em HTML e CSS para que depois possamos implementar os comportamentos dinâmicos através do JavaScript, jQuery e Ajax.

Em vista do tamanho da página pdv_web.php, dividiremos a sua criação em duas partes, para melhor entendimento. Veja na Listagem 7 a implementação inicial do arquivo.

Listagem 7. Implementação da página “pdv_web.php”.



  01 <?php require ''header.php'' ?> 
  02 <br> <br>
  03 <?php
  04 if(isset($_SESSION[''id_usuario''])){                                           
  05 echo "<div class=''container''>
  06
  07   <div class=''panel panel-default''>
  08        <div class=''panel-heading''><h3>Sistema de vendas <span class=''label label-default''>PDV Web</span></h3></div>
  09            <div class=''panel-body''>
  10                <div class''row''>
  11                     <div class=''col-md-12''>                                  
  12                    <select class=''btn btn-default'' id=''select_cliente''></select>
  13                    <button class=''btn btn-default btn-warning'' id=''btn_iniciar_venda''>Iniciar venda</button>
  14                    <button class=''btn btn-default btn btn-danger'' disabled=''true'' id=''btn_encerrar_venda'' onclick=''encerrarVenda()''>Encerrar venda</button>
  15                    <span class=''label label-default''><label>STATUS: </label></span>  
  16                    <label id=''status_venda''>Encerrada</label> 
  17                    <span class=''label label-default''><label>CÓD. VENDA: </label></span>  
  18                    <label id=''id_venda_cabecalho''></label>  
  19                    <span class=''label label-default''><label>CLIENTE: </label></span>                     
  20                    <label id=''codigo_cliente''></label>  
  21                    <label id=''cliente_nome''></label>                      
  22                 </div>
  23                </div>
  24            </div>
  25    </div>

Vejamos a seguir os detalhes do código:

· Linha 1: Aqui é comando require do PHP é utilizado para embutir na página pdv_web.php todo o código contido na página header. É desta forma que funciona o reaproveitamento de código no PHP.

· Linha 4: Aqui é feita a condição que comentamos antes, sobre verificar se o usuário está ou não logado.

· Linha 5: Div que utiliza a classe container do Bootstrap para organizar as coisas no layout.

· Linhas 7 a 9: Painel do Bootstrap construído através do uso das classes panel, panel-default, panel-heading e panel-body que servem para definir o escopo do design da página.

· Linha 12: Definimos o elemento select que irá compor a lista de clientes para que o usuário caixa possa escolher um no ato da abertura de uma venda no PDV Web.

· Linha 13: Aqui foi criado um botão que será responsável pelo disparo do evento click para iniciar uma venda no PDV.

· Linha 14: Novo botão para encerrar a venda, porém o mesmo só estará ativo para click quando tiver uma venda em andamento.

· Linha 15 a 21: Definimos vários labels para informar os dados da venda em andamento, como o status da venda, código e nome do cliente.

Em seguida, precisamos definir também o conteúdo HTML da página com a estrutura de navegação. Veja na Listagem 8 o código que você adicionar ao fim do arquivo.

Listagem 8. Implementação da estrutura HTML e de navegação.



  01    <div class=''panel panel-default'' id=''div_venda_itens'' hidden=''hidden''>
  02            <div class=''panel-body''>
  03                <div class=row>
  04                    <div class=''col-md-12''> 
  05                        <div class=''breadcrumb''>
  06                          <h3><label for=''nomeProduto'' id=''nomeProduto''></label></h3>
  07                        </div>
  08                    </div>
  09                </div>
  10                <div class''row''>
  11                     
  12                   <div class=''col-md-3''>
  13                       <div class=''breadcrumb''>
  14                        <div class=''form-group''>
  15                           <label for=''codigo_produto''>Código produto:</label>
  16                           <input type=''number'' class=''form-control'' id=''codigo_produto''>
  17                           <label for=''qtde''>Quantidade:</label>
  18                           <input type=''number'' class=''form-control'' id=''qtde_item''>
  19                           <label for=''preco''>Preço unitário:</label>
  20                           <input type=''number'' class=''form-control'' id=''preco_unitario'' disabled=''true''>
  21                           <label for=''codigo_produto''>Valor total:</label>
  22                           <input type=''number'' class=''form-control'' id=''valor_total_item'' disabled=''true''>                           
  23                        </div>
  24                       <button class=''btn btn-primary'' id=''btnAdicionarItem''>Adicionar ITEM</button>
  25                       </div>
  26                  </div>
  27                   
  28                  <div class=''col-md-2''>
  29                      <div class=''breadcrumb''>
  30                          <img src='''' class=''img-responsive'' id=''img_produto'' alt=''Responsive image''>
  31                      </div>
  32                  </div>
  33                  
  34                  <div class=''col-md-7''>
  35                      <div class=''breadcrumb''>
  36                          <input type=''number'' id=''contadorSeqItemVenda'' disabled=''true'' value=''1'' hidden=''hidden''> 
  37                          <!--<label for=''cupom''>ITENS CUPOM:</label>-->
  38                          <table class=''table table-striped'' id=''tabela_cupom''>                              
  39                          </table>
  40                      </div>
  41                  </div>                   
  42                </div>
  43                
  44                <div class''row''>
  45                     <div class=''col-md-12''> 
  46                      <div class=''breadcrumb''>
  47                        <h3>
  48                            <label for=''rotulo_total_geral''>TOTAL GERAL:</label>
  49                            <label id=''total_geral'' disabled=''true''>                            
  50                        </h3>
  51                      </div>
  52                  </div>
  53               </div>
  54                
  55            </div>
  56        </div>                
  57    </div>";}
  58 else{
  59    echo "<br/> Você deve realizar o login.";
  60 }
  61 ?>               
  62
  63 <?php require ''footer.php'' ?>  
  64     
  65    <script type="text/javascript">
  66          $(document).ready(function() {               
  67                    carregarNoLoadPagina();              
  68             });
  69     </script>

Vejamos algumas observações acerca do código:

· Linhas 1 a 9: Div que irá armazenar os itens da venda.

· Linhas 10 a 26: Os campos preço unitário e valor total do item serão preenchidos automaticamente via JavaScript. Perceba na linha 50 um botão com ID ‘btnAdicionarItem’ que será responsável por disparar o evento para vender o item e adicionar o mesmo no cupom não fiscal que será definido mais adiante na listagem.

· Linhas 26 a 30: Definimos uma tag img com ID para que possamos exibir as imagens dos produtos que serão vendidos.

· Linhas 34 a 42: Mais uma coluna para armazenar um contador de itens vendidos que ficará oculto para o usuário conforme linha 62, logo em seguida na linha 64 foi definida uma tabela que irá exibir todos os itens vendidos durante a venda. É importante citar que esta tabela será preenchida via JavaScript e terá um botão em cada item vendido possibilitando o cancelamento do mesmo pelo usuário.

· Linhas 44 a 53: Aqui é criado a última row da página do PDV web, esta linha contém apenas uma coluna conforme linha 71 com o papel de exibir a informação referente ao total geral da venda em andamento conforme componentes das linhas 74 e 75. O label de ID ''total_geral'' presente na linha 75 será preenchido automaticamente via JavaScript conforme forem sendo inseridos itens na venda em andamento.

· Linha 63: Comando require para inserir o código presente no arquivo ''footer.php''.

A estrutura HTML do PDV Web já está pronta, portando você pode executar o projeto e verificar o resultado conforme apresentado na Figura 6. Perceba que o PDV ainda não ganhou vida, pois ainda faremos a implementação JavaScript e jQuery no arquivo javascript_pdv.js para o tornar funcional.

Layout do PDV
Web em execução
Figura 6. Layout do PDV Web em execução.

Lista de clientes com jQuery e Ajax

Comecemos a dinamização do PDV pelo preenchimento do select que irá exibir a lista de clientes para que o usuário caixa possa selecionar um cliente e iniciar uma venda.

Primeiramente, implemente o código da Listagem 9 dentro do arquivo slim_rest.php, uma vez que ele será responsável por expor o serviço para retornar a listagem de clientes cadastrados no banco de dados e proporcionar a consulta de clientes por ID.

Listagem 9. Implementação do serviço REST para listagem de clientes e consulta por ID.



  01 $app->get(''/getCliente/:id'', function ($id) use ($app) {
  02    
  03     $sql = "select * FROM cliente WHERE id_cliente = :id";
  04     try {
  05        
  06        $db = getConnection();
  07           $stmt = $db->prepare($sql);  
  08        $stmt->bindParam("id", $id);
  09           $stmt->execute();
  10           
  11           $cliente = $stmt->fetchObject(); 
  12           $db = null;
  13           echo json_encode($cliente, JSON_UNESCAPED_UNICODE);
  14     } catch(PDOException $e) {
  15           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  16     }
  17 });
  18
  19 $app->get(''/getClientes'', function () use ($app) {
  20    
  21     $sql = "select * FROM cliente ORDER BY nome";
  22     try {
  23           $db = getConnection();
  24           $stmt = $db->query($sql);  
  25           $clientes = $stmt->fetchAll(PDO::FETCH_OBJ);
  26           $db = null;
  27           echo json_encode($clientes, JSON_UNESCAPED_UNICODE);
  28     } catch(PDOException $e) {
  29           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  30     }
  31 });

Agora abra o arquivo javascript_pdv.js contido dentro da pasta js e implemente o código JavaScript e jQuery descrito na Listagem 10.

Listagem 10. Implementação da lista de clientes.


  01 function carregarNoLoadPagina(){ 
  02
  03    //Carregar lista de clientes
  04    carregarClientesSelect();
  05
  06 }
  07     
  08 //Fim carregarNoLoadPagina()-----------------------------------------
  09
  10 function carregarClientesSelect(){                 
  11        $(function(){
  12            $.getJSON("/pdv/getClientes", function(j){
  13                var options = "<option value=''0''>Selecione um cliente</option>";
  14                for (var i = 0; i < j.length; i++) {
  15                options += ''<option value="'' + j[i].id_cliente + ''">'' + j[i].nome + ''</option>'';
  16                }
  17                $("select#select_cliente").html(options);
  18            });   
  19        }); 
  20 }

Vejamos maiores detalhes da implementação desta listagem:

· Linhas 1 a 6: Foi definida uma função carregarNoLoadPagina() que é chamada na página pdv_web.php após o carregamento total da mesma no browser. Dentro desta função colocaremos todas as funções necessárias para capturar os eventos que possam ocorrer durante a execução do PDV. Na linha 4 é chamada outra função, carregarClientesSelect(), que se encarrega de popular a lista de clientes no select.

· Linha 12 a 20: Aqui é utilizada a função getJSON do jQuery para acessar o serviço REST no endereço /pdv/getClientes e obter a listagem de clientes no formato JSON. Logo em seguida, é realizado um for na listagem de clientes para obter o ID e nome deles e assim popular o select conforme apresentado na linha 17, tudo isso através do uso da função html() do jQuery.

Execute novamente o projeto e veja o resultado conforme apresentado na Figura 7.

Select de clientes populado com jQuery via Ajax
Figura 7. Select de clientes populado com jQuery via Ajax.

Vendas no PDV

Agora é hora de iniciar uma venda através do botão “Iniciar Venda”. Para realizar este procedimento, primeiramente é necessário criar o serviço REST que irá auxiliar na inserção e finalização de uma venda no banco de dados. Implemente o código da Listagem 11 dentro do arquivo slim_rest.php para tornar alguns serviços disponíveis que precisamos usar no front-end.

Observe que temos duas rotas que apontam para o serviço: uma que irá abrir uma nova venda no banco de dados conforme linha 1 e outra rota para finalizar uma venda conforme linha 25.

Listagem 11. Implementação do serviço para iniciar e finalizar uma venda.



  01 $app->post(''/adicionarVendaCabecalho'', function () use ($app) {
  02    
  03    $id_usuario = $app->request->post(''id_usuario'');
  04     $id_cliente = $app->request->post(''id_cliente'');
  05    $status_venda = $app->request->post(''status_venda'');
  06     $sql = "INSERT INTO venda_cabecalho (id_usuario, id_cliente, status_venda, data_hora_venda) VALUES (:id_usuario, :id_cliente, :status_venda, :data_hora_venda)";
  07     try {
  08           $db = getConnection();
  09           $stmt = $db->prepare($sql);  
  10           $stmt->bindParam("id_usuario", $id_usuario);
  11        $stmt->bindParam("id_cliente", $id_cliente);             
  12        $stmt->bindParam("status_venda", $status_venda);
  13        $dataAtual = date(''Y-m-d H:i'');
  14        $stmt->bindParam("data_hora_venda", $dataAtual);         
  15           
  16           $stmt->execute();
  17           $id_venda_cabecalho = $db->lastInsertId();
  18           echo $id_venda_cabecalho;
  19           $db = null;
  20     } catch(PDOException $e) {
  21           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  22     }
  23 });
  24
  25 $app->post(''/updateVendaCabecalho'', function () use ($app) {
  26   
  27    $id_venda_cabecalho = $app->request->post(''id_venda_cabecalho'');
  28    $qtde_itens = $app->request->post(''qtde_itens'');
  29    $valor_total = $app->request->post(''valor_total'');
  30    $status_venda = $app->request->post(''status_venda'');
  31     $sql = "UPDATE venda_cabecalho  SET qtde_itens = :qtde_itens, valor_total = :valor_total, status_venda = :status_venda WHERE id_venda_cabecalho = :id_venda_cabecalho";
  32     try {
  33           $db = getConnection();
  34           $stmt = $db->prepare($sql);  
  35        $stmt->bindParam("id_venda_cabecalho", $id_venda_cabecalho);           
  36        $stmt->bindParam("qtde_itens", $qtde_itens);
  37        $stmt->bindParam("valor_total", $valor_total);
  38        $stmt->bindParam("status_venda", $status_venda);                
  39           $stmt->execute();
  40           $db = null;
  41     } catch(PDOException $e) {
  42           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  43     }
  44 });

Precisamos também incrementar a funcionalidade propriamente dita do botão de iniciar venda, logo será necessário colocar o código da Listagem 12 dentro da função carregarNoLoadPagina. O código desta listagem tem o papel de escutar o click do botão btn_iniciar_venda conforme linha 2. Caso exista um cliente selecionado, ela deve chamar a função iniciarNovaVenda() presente na linha 6.

Listagem 12. Código para escutar evento de click do botão de iniciar venda.



  01    //escutar click botão para iniciar uma venda
  02    $(''#btn_iniciar_venda'').click(function() {
  03        if($("#select_cliente").val() === "0"){
  04            alert("Selecione um cliente antes de iniciar uma venda.");
  05        }else{
  06            iniciarNovaVenda();
  07        }
  08    });

Esse código apenas escuta o click do botão, porém é necessário iniciar uma venda através de uma chamada via Ajax ao serviço REST que irá inserir e definir a abertura de uma nova venda no banco de dados. Veja a implementação da função iniciarNovaVenda na Listagem 13.

Listagem 13. Código para iniciar uma nova venda de fato.



  01 function iniciarNovaVenda(){
  02    $("#btn_iniciar_venda").attr("disabled", "disabled");
  03    $("#select_cliente").attr("disabled","disabled");
  04    $("#btn_encerrar_venda").removeAttr("disabled");    
  05    $("#status_venda").text("Em aberto");         
  06    $("#div_venda_itens").show();
  07    var cliente_id = $("#select_cliente").val();
  08           $(function(){
  09           //Busca os dados do cliente selecionado
  10           $.getJSON("/pdv/getCliente/"+cliente_id, function(cliente){
  11               $("#cliente_nome").text(cliente.nome);
  12              $("#codigo_cliente").text(cliente.id_cliente);                
  13                
  14                //Adicionar a abertura de uma nova venda no banco
  15                $.ajax({
  16                    type: "POST",
  17                    url: "/pdv/adicionarVendaCabecalho",
  18                    dataType: "html",
  19                    data:  {"id_cliente": cliente_id, "id_usuario": $("#id_usuario").text(), "status_venda": $("#status_venda").text()},
  20            success: function(retornoIdVendaCab){
  21                    $("#id_venda_cabecalho").text(retornoIdVendaCab); 
  22                    alert("Aberta uma nova venda de código: " + retornoIdVendaCab + " para o cliente: " + cliente.nome);
  23                    }
  24                });
  25            });   
  26        });                     
  27 }

Vejamos a seguir alguns detalhes:

· Linhas 2 a 7: É desativado o botão para iniciar uma venda e ativado o botão para encerrar a venda em andamento. Perceba ainda que é definida a exibição de vários componentes na página para dar início ao processo de venda de produtos. Por fim, capturamos o código do cliente selecionado para iniciar a venda conforme consta na linha 7.

· Linhas 10 a 12: Aqui é utilizada a função getJSON do jQuery para acessar o serviço /pdv/getCliente via Ajax e recuperar as informações do cliente selecionado para a venda. Logo em seguida, é setado o nome e ID do cliente nos labels da página para exibir estes dados ao usuário caixa.

· Linha 15 a 23: Neste bloco de código é realizada uma requisição Ajax via POST ao serviço REST no endereço /pdv/adicionarVendaCabecalho para gravar no banco de dados as informações da nova venda aberta com status em andamento.

Para verificar o resultado da implementação de abertura de venda no PDV Web execute o projeto e veja o resultado conforme consta na Figura 8.

Venda iniciada no PDV Web
Figura 8. Venda iniciada no PDV Web.

Busca de produto por ID e cálculo dos itens vendidos

Para vender itens no PDV Web é necessário que o usuário informe o código do produto e a quantidade a ser vendida. E para implementar esta operação, usaremos função focusout do jQuery para escutar o evento de perda de foco nos campos de código do produto e quantidade, ou seja, após a perda do foco no código do produto, validaremos o código e realizaremos uma consulta Ajax ao servidor para buscar todos os dados do mesmo, preenchendo alguns elementos HTML na página. Logo em seguida, faremos o mesmo para o campo quantidade em relação ao valor total.

O primeiro passo para a implementação da busca de produto por ID é criar o serviço para dispor tal funcionalidade. Assim sendo, implemente o trecho de código presente na Listagem 14 dentro do arquivo slim_rest.php. Desta forma, ficará disponível uma nova rota /getProduto para consultar o produto através de uma requisição GET via Ajax utilizado o jQuery.

Listagem 14. Código para consultar um produto pelo ID.



  01 $app->get(''/getProduto/:id'', function ($id) use ($app) {
  02    
  03     $sql = "select * FROM produto WHERE id_produto = :id_produto";
  04     try {
  05        
  06        $db = getConnection();
  07           $stmt = $db->prepare($sql);  
  08        $stmt->bindParam("id_produto", $id);
  09           $stmt->execute();
  10           
  11           $prduto = $stmt->fetchObject(); 
  12           $db = null;
  13           echo json_encode($prduto, JSON_UNESCAPED_UNICODE);
  14     } catch(PDOException $e) {
  15           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  16     }
  17 });

Voltando ao front-end da aplicação, é necessário implementar o trecho de código presente na Listagem 15 dentro da função carregarNoLoadPagina(), que é chamada após a renderização da página no browser. Desta forma, será possível monitorar os eventos focusout dos campos código do produto e quantidade.

Listagem 15. Código para monitorar os eventos de focusout dos campos.



  01    //Escutar evento perda de foco para mostrar os dados do produto
  02    $("#codigo_produto").focusout(function(){
  03        if($("#codigo_produto").val() !== "" && $("#codigo_produto").val() > 0){
  04            buscaProdutoPorId($("#codigo_produto").val());
  05        }else{
  06            alert("Valor informar o código do produto válido");
  07        }    
  08    });
  09    
  10    //Escutar evento perda de foco para calcular o total do item
  11    $("#qtde_item").focusout(function(){
  12        if($("#qtde_item").val() !== "" && $("#qtde_item").val() > 0){
  13            var valorTotalitem = parseFloat($("#qtde_item").val()) *  parseFloat($("#preco_unitario").val());            
  14            $("#valor_total_item").val(valorTotalitem.toString());            
  15        }else{
  16            alert("Valor informar a quantidade vendida válida.");
  17        }
  18    });

Na linha 2, o jQuery escuta o evento focusout através do ID (#codigo_produto) do campo código produto. Na linha 4 é chamada outra função buscaProdutoPorId() para realizar a consulta via Ajax e retornar os dados do produto. Veja agora na Listagem 16 como deve ser a implementação da consulta Ajax para a função buscaProdutoPorId().

Listagem 16. Consulta Ajax para buscar os dados do item a ser vendido no PDV.



  01 function buscaProdutoPorId(id_produto){
  02    $.getJSON("/pdv/getProduto/" + id_produto, function(produto){
  03        $("#preco_unitario").val(produto.preco_venda);
  04        $("#nomeProduto").text(produto.nome);
  05        $("#img_produto").attr("src", produto.imagem_produto);
  06    });
  07 }

Vejamos o seu detalhamento:

· Linha 1: Aqui temos a declaração da função onde é recebido o ID do produto a ser pesquisado.

· Linha 2: Nesta linha é realizada uma requisição via Ajax para buscar as informações do produto.

· Linha 3 a 5: De posse dos dados do produto, exibimos na página o preço unitário do produto, nome e a imagem do mesmo.

Para testar a implementação anterior, execute o projeto, inicie uma venda, informe o código do produto e a quantidade a ser vendida e veja o resultado conforme apresentado na Figura 9.

Pesquisa de produto por ID e cálculo subtotal do item
Figura 9. Pesquisa de produto por ID e cálculo subtotal do item.

Função adicionar item ao cupom

O próximo passo é implementar a funcionalidade de adicionar item ao cupom. Porém, antes disso, precisamos criar o serviço REST com algumas rotas para pesquisa, inclusão e alteração de itens na base de dados conforme apresentado na Listagem 17. O código deve ser inserido dentro do arquivo slim_rest.php para tornar as rotas das linhas 01, 34 e 50 disponíveis para acesso pela aplicação front-end.

Listagem 17. Serviço REST para inclusão e manutenção de itens na venda.



  01 $app->post(''/adicionarItemVenda'', function () use ($app) {
  02    
  03    $id_produto = $app->request->post(''id_produto'');
  04     $id_venda_cabecalho = $app->request->post(''id_venda_cabecalho'');
  05    $sequencia = $app->request->post(''sequencia'');
  06    $nome_produto = $app->request->post(''nome_produto'');
  07    $qtde = $app->request->post(''qtde'');
  08    $valor_unitario= $app->request->post(''valor_unitario'');
  09    $sub_total = $app->request->post(''sub_total'');
  10    $status_item = $app->request->post(''status_item'');    
  11        
  12     $sql = "INSERT INTO itens_venda (id_produto, id_venda_cabecalho, sequencia, nome_produto, qtde, valor_unitario, sub_total, status_item) VALUES (:id_produto, :id_venda_cabecalho, :sequencia, :nome_produto, :qtde, :valor_unitario, :sub_total, :status_item) ";
  13     try {
  14           $db = getConnection();
  15           $stmt = $db->prepare($sql);  
  16           $stmt->bindParam("id_produto", $id_produto);   
  17        $stmt->bindParam("id_venda_cabecalho", $id_venda_cabecalho);
  18        $stmt->bindParam("sequencia", $sequencia);
  19        $stmt->bindParam("nome_produto", $nome_produto);
  20        $stmt->bindParam("qtde", $qtde);
  21        $stmt->bindParam("valor_unitario", $valor_unitario);
  22        $stmt->bindParam("sub_total", $sub_total);
  23        $stmt->bindParam("status_item", $status_item);
  24           
  25           $stmt->execute();
  26           $id_itens_venda = $db->lastInsertId();
  27           echo json_encode($id_itens_venda, JSON_UNESCAPED_UNICODE);
  28           $db = null;
  29     } catch(PDOException $e) {
  30           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  31     }
  32 });
  33
  34 $app->get(''/getItensVenda/:id_venda'', function ($id_venda) use ($app) {
  35    
  36     $sql = "select * FROM itens_venda WHERE id_venda_cabecalho = :id_venda_cabecalho ORDER BY sequencia";
  37     try {
  38           $db = getConnection();
  39        $stmt = $db->prepare($sql); 
  40        $stmt->bindParam("id_venda_cabecalho", $id_venda);
  41        $stmt->execute(); 
  42           $itensVenda = $stmt->fetchAll(PDO::FETCH_OBJ);
  43           $db = null;
  44           echo json_encode($itensVenda, JSON_UNESCAPED_UNICODE);
  45     } catch(PDOException $e) {
  46           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  47     }
  48 });
  49
  50 $app->post(''/updateItemVenda'', function () use ($app) {
  51    
  52    $id_itens_venda = $app->request->post(''id_itens_venda'');  
  53    
  54    $sql = "UPDATE itens_venda  SET status_item = ''cancelado'' WHERE id_itens_venda = :id_itens_venda";
  55    
  56     try {
  57           $db = getConnection();
  58           $stmt = $db->prepare($sql);  
  59        $stmt->bindParam("id_itens_venda", $id_itens_venda);            
  60           $stmt->execute();
  61           $db = null;
  62     } catch(PDOException $e) {
  63           echo ''{"error":{"text":''. $e->getMessage() .''}}''; 
  64     }
  65 });

Após todo o serviço REST implementado no back-end, podemos a partir deste ponto trabalhar somente no front-end da aplicação. O próximo passo é adicionar o trecho de código da Listagem 18 dentro da função carregarNoLoadPagina() para que possamos capturar o evento de click do botão adicionar item ao cupom.

O código captura algumas informações do item a ser vendido e logo na linha 6 chama a função adicionarItemCupom() para gravar o item no banco de dados. Veja os detalhes da função adicionarItemCupom() conforme apresentado na Listagem 19.

Listagem 18. Código para escutar o evento click do botão adicionar item ao cupom.



  01    //Escuta o evento click para adicionar o item ao cupom
  02    $("#btnAdicionarItem").click(function(){
  03        if($("#qtde_item").val() !== "" && $("#qtde_item").val() > 0 && $("#codigo_produto").val() >0 ){
  04                       
  05            var statusItem = "vendido";
  06            adicionarItemCupom($("#codigo_produto").val(), $("#id_venda_cabecalho").text(), $(contadorSeqItemVenda).val(), $("#nomeProduto").text(), $("#qtde_item").val(), $("#preco_unitario").val(), $("#valor_total_item").val(), statusItem);            
  07        }else{
  08            alert("Valor informar o código do produto e uma quantidade válida.");
  09        }
  10    });

Listagem 19. Código para gravar item vendido no banco de dados por requisição Ajax com jQuery.



  01 function adicionarItemCupom(codigo_produto, codigo_venda, seqItemVenda, nome_produto, qtde_item, preco_unitario, valor_total_item, statusItem){
  02                var codigo_vend = parseFloat(codigo_venda.replace(''"'',''''));   
  03                //Adicionar item vendido no banco de dados
  04                $.ajax({
  05                  type: "POST",
  06                  url: "/pdv/adicionarItemVenda",
  07                  dataType: "html",
  08                  data:  {"id_produto": codigo_produto, "id_venda_cabecalho": codigo_vend, "sequencia": seqItemVenda, "nome_produto": nome_produto, "qtde": qtde_item, "valor_unitario": preco_unitario, "sub_total": valor_total_item, "status_item": statusItem},
  09            success: function(retornoIdItemVenda){
  10                
  11                 //Incrementa e seta + 1 na sequencia de itens
  12                 var seq = parseInt(seqItemVenda) + 1;
  13                 $("#contadorSeqItemVenda").val(seq);
  14                    
  15                 //Preenchar a tabela com os itens vendidos
  16                 $.getJSON("/pdv/getItensVenda/" + codigo_vend, function(itens){
  17                        
  18                 //Definir cabelha tabela
  19                 var linhasTabela = ''<tr><th>ITEM</th> <th>CÓDIGO</th> <th>DESCRIÇÃO</th> <th>QDTE</th> <th>PREÇO</th> <th>TOTAL</th> <th>STATUS</th><th></th> </tr>'';
  20                    
  21                 var totalGeralVenda = 0.0; //Armazenar o total geral
  22                        
  23                 for (var i = 0; i < itens.length; i++) {                     
  24                 linhasTabela += "<tr><th>"+ itens[i].sequencia +"</th><th>"+ itens[i].id_produto +"</th><th>"+ itens[i].nome_produto +"</th><th>"+ itens[i].qtde +"</th><th>"+ itens[i].valor_unitario +"</th><th>"+ itens[i].sub_total +"</th><th>"+ itens[i].status_item +"</th><th><button class=''glyphicon glyphicon-remove'' aria-hidden=''true'' onClick=''cancelarItemVenda("+ itens[i].id_itens_venda +","+ itens[i].sequencia + ","+ itens[i].id_venda_cabecalho +")''/></th></tr>";
  25                        
  26                 //Calcula o total geral da venda
  27                 if(itens[i].status_item === "vendido"){
  28                   totalGeralVenda += parseFloat(itens[i].sub_total);
  29                 }
  30                       
  31                    //Exibir tabela e setar total geral
  32                    $("table#tabela_cupom").html(linhasTabela);
  33                    $("#total_geral").text("R$ " + totalGeralVenda.toString());                                              
  34                 }
  35           }); 
  36                
  37           //Limpa os campos 
  38           $("#codigo_produto").val("");
  39           $("#qtde_item").val("");
  40           $("#preco_unitario").val("");
  41           $("#valor_total_item").val("");
  42           $("#nomeProduto").text("");
  43           $("#img_produto").attr("src", "");
  44          }});    
  45 }

A última listagem apenas grava os dados do item vendido na base de dados através de uma requisição Ajax conforme linha 4. Logo na sequência, recupera todos os itens vendidos relacionados à venda em andamento e popula a tabela tabela_cupom com a utilização da função html() do jQuery presente na linha 32.

Execute o projeto novamente, faça a venda de itens e obtenha o resultado apresentado na Figura 10.

Inclusão de itens no cupom
Figura 10. Inclusão de itens no cupom.

Função cancelamento de item do cupom

Como em qualquer PDV, às vezes pode ser necessário cancelar um item no cupom, assim sendo perceba que ao lado de cada item vendido foi adicionado um botão para cancelamento. O click no botão cancelamento irá chamar a função cancelarItemVenda() conforme pode ser visto na Listagem 20. O código desta listagem realiza o update do item a ser cancelado na base de dados, e logo em seguida recarrega os itens vendidos na página descontando do valor total da venda o valor do item cancelado.

Listagem 20. Código para cancelamento de item no cupom



  01 function cancelarItemVenda(id_itens_venda, sequencia, id_venda_cabecalho){
  02    $.ajax({
  03        type: "POST",
  04        url: "/pdv/updateItemVenda",
  05        dataType: "html",
  06        data:  {"id_itens_venda": id_itens_venda},
  07        success: function(retornoIdItemCancelado){ 
  08            
  09                //Preenchar a tabela com os itens vendidos
  10                $.getJSON("/pdv/getItensVenda/" + id_venda_cabecalho, function(itens){
  11                        
  12                //Definir cabelha tabela
  13                linhasTabela = ''<tr><th>ITEM</th> <th>CÓDIGO</th> <th>DESCRIÇÃO</th> <th>QDTE</th> <th>PREÇO</th> <th>TOTAL</th> <th>STATUS</th><th></th> </tr>'';
  14                var totalGeralVenda = 0.0;
  15                        
  16                for (var i = 0; i < itens.length; i++) {                     
  17                    linhasTabela += "<tr><th>"+ itens[i].sequencia +"</th><th>"+ itens[i].id_produto +"</th><th>"+ itens[i].nome_produto +"</th><th>"+ itens[i].qtde +"</th><th>"+ itens[i].valor_unitario +"</th><th>"+ itens[i].sub_total +"</th><th>"+ itens[i].status_item +"</th><th><button class=''glyphicon glyphicon-remove'' aria-hidden=''true'' onClick=''cancelarItemVenda("+ itens[i].id_itens_venda +","+ itens[i].sequencia +")''/></th></tr>";
  18                //Calcula o total geral da venda
  19                if(itens[i].status_item === "vendido"){
  20                    totalGeralVenda += parseFloat(itens[i].sub_total);
  21                }                        
  22             }                    
  23                //Exibir tabela e setar total geral
  24                $("table#tabela_cupom").html(linhasTabela);
  25                $("#total_geral").text("R$ " + totalGeralVenda.toString());                        
  26            });             
  27            alert("O item: " + sequencia + " foi cancelado.");                        
  28        }
  29    });
  30 }

Execute o projeto novamente, venda alguns itens e realize o cancelamento de um item. Após isso, você irá obter um resultado conforme apresentado na Figura 11, onde o item de número 3 foi cancelado. Perceba também que o valor total geral da venda foi recalculado após o cancelamento do item.

Exemplo de cancelamento de item
Figura 11. Exemplo de cancelamento de item.

Função de encerramento da venda

A última funcionalidade a ser implementada no PDV é o encerramento da venda em andamento. Para implementar isso, copie o código da Listagem 21 para o arquivo javascript_pdv.js.

O código define uma função chamada encerrarVenda(), que, por sua vez, está amarrada ao evento de click do botão “Encerrar Venda” localizado na parte superior da página. Execute o projeto, venda alguns itens e encerre a venda para obter o resultado apresentado na Figura 12.

Listagem 21. Código para encerramento da venda.



  01 function encerrarVenda(){
  02     //Recuperar dados para finalizar venda
  03     var id_venda = $("#id_venda_cabecalho").text();
  04     var id_venda = parseInt(id_venda);
  05     var qtde_itens_vendidos = $("#contadorSeqItemVenda").val();
  06     var total_geral_venda = $("#total_geral").text().replace(''R$ '','''');
  07    
  08     
  09     //Alterar a tabela venda cabeçalho para finalizada    
  10     $.ajax({
  11        type: "POST",
  12        url: "/pdv/updateVendaCabecalho",
  13        dataType: "html",
  14        data:  {"id_venda_cabecalho": id_venda, "qtde_itens": qtde_itens_vendidos, "valor_total": total_geral_venda, "status_venda": "Finalizada"},
  15        success: function(){
  16            alert("Venda finalizada - Total: " + $("#total_geral").text());     
  17            $("table#tabela_cupom").html();
  18            $("#total_geral").text("");   
  19            $("#btn_iniciar_venda").removeAttr("disabled");  
  20            $("#select_cliente").removeAttr("disabled");  
  21            $("#btn_encerrar_venda").attr("disabled", "disabled");    
  22            $("#status_venda").text("Finalizada");         
  23            $("#div_venda_itens").hide();
  24            $("#cliente_nome").text("");
  25            $("#codigo_cliente").text(""); 
  26            $("#contadorSeqItemVenda").val(1);
  27            $("#id_venda_cabecalho").text("");       
  28        }     
  29     });
  30    
  31 }

Mensagem de encerramento da venda no PDV Web
Figura 12. Mensagem de encerramento da venda no PDV Web.

Ao longo deste artigo, foi possível acompanhar todo o desenvolvimento de uma aplicação real conforme exemplo apresentado do PDV Web. O desenvolvimento de aplicações desse tipo, muitas vezes, cai em meio comum, motivado principalmente pela aproximação com o desinteresse causado por aplicações do tipo CRUD nos profissionais da área.

Independentemente do tipo de aplicação que você venha a desenvolver, seja qual for a sua finalidade, é importante que exista planejamento e organização. O Bootstrap consegue trazer tudo isso de forma integrada, principalmente pela abstração de muitas tarefas já não mais necessárias. Cabe a você, como desenvolvedor, se aprimorar cada vez mais e praticar bastante os conceitos vistos aqui e disponíveis ao longo da documentação oficial do framework.

Links

Download XAMP
http://www.XAMP.com/en/

Slim framework
http://www.slimframework.com/

Download Bootstrap
http://getBootstrap.com/getting-started/#download

Download biblioteca jQuery
http://jquery.com/downloa