UNIVERSIDADE DO VALE DO ITAJAÍ CENTRO DE CIÊNCIAS TECNOLÓGICAS DA TERRA E DO MAR
CURSO DE CIÊNCIA DA COMPUTAÇÃO
SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS
Área de Inteligência Artificial
por
Rafael Toigo
Adhemar Maria do Valle Filho, Dr. Orientador
Fabio Beylouni Lavratti, M.Sc. Co-orientador
Itajaí (SC), julho de 2006
UNIVERSIDADE DO VALE DO ITAJAÍ CENTRO DE CIÊNCIAS TECNOLÓGICAS DA TERRA E DO MAR
CURSO DE CIÊNCIA DA COMPUTAÇÃO
SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS
Área de Inteligência Artificial
por
Rafael Toigo Relatório apresentado à Banca Examinadora do Trabalho de Conclusão do Curso de Ciência da Computação para análise e aprovação. Orientador: Adhemar Maria do Valle Filho, Dr.
Itajaí (SC), julho de 2006
ii
SUMÁRIO
LISTA DE ABREVIATURAS..................................................................iv
LISTA DE FIGURAS.................................................................................v
LISTA DE TABELAS...............................................................................vi LISTA DE EQUAÇÕES ..........................................................................vii RESUMO..................................................................................................viii ABSTRACT................................................................................................ix
1. INTRODUÇÃO ......................................................................................1 1.1. OBJETIVOS ..................................................................................................... 4 1.1.1. Objetivo Geral................................................................................................ 4 1.1.2. Objetivos Específicos...................................................................................... 4 1.2. METODOLOGIA............................................................................................. 4 1.3. ESTRUTURA DO TRABALHO ..................................................................... 5
2. FUNDAMENTAÇÃO TEÓRICA ........................................................7 2.1. ROTEIRIZAÇÃO ............................................................................................ 9 2.2. HEURÍSTICA................................................................................................... 9 2.2.1. Métodos de Construção de Roteiros............................................................ 11 2.2.2. Métodos de Melhorias de Roteiros .............................................................. 12 2.3. CLASSES DE PROBLEMAS ........................................................................ 12 2.3.1. Classe P e NP ................................................................................................ 13 2.3.2. Classe NP-Completo e NP-Hard.................................................................. 14 2.4. PROBLEMAS DE OTIMIZAÇÃO COMBINATÓRIA.............................. 15 2.4.1. Problema do Caixeiro Viajante ................................................................... 16 2.4.1.1. Formulações ................................................................................................ 18 2.4.1.1.1. Formulação de Dantzig-Fulkerson-Johnson..................................................................18 2.4.1.1.2. Formulação de Miller-Tucker-Zemlin ..........................................................................20 2.4.1.1.3. Formulação de Fox-Gavish-Graves ..............................................................................21 2.4.1.1.4. Formulação de Claus....................................................................................................22 2.4.1.2. Aplicações ................................................................................................... 24 2.4.1.3. Solução através de Heurísticas..................................................................... 24 2.4.1.3.1. Heurística k-opt............................................................................................................25 2.4.1.3.2. Heurística das Economias.............................................................................................26 2.4.2. Problema de Roteirização de Veículos ........................................................ 28 2.4.2.1. Taxonomia Geral ......................................................................................... 29 2.4.2.2. Formulação.................................................................................................. 30 2.4.2.3. Aplicações ................................................................................................... 32 2.4.2.4. Solução através de Heurísticas..................................................................... 33 2.4.2.4.1. Heurística k-opt............................................................................................................33 2.4.2.4.2. Heurística das Economias.............................................................................................34
iii
3. DESENVOLVIMENTO ......................................................................36 3.1. SISTEMAS SIMILARES E SISTEMA PROPOSTO .................................. 36 3.2. MÉTODOS HEURÍSTICOS UTILIZADOS ................................................ 38 3.2.1. Método das economias (Clarke & Wright) ................................................. 38 3.2.2. Método de Melhoria K-opt .......................................................................... 41 3.3. REQUISITOS DO SISTEMA....................................................................... 42 3.4. MODELAGEM DO SISTEMA ..................................................................... 45 3.4.1. Diagrama de Casos de Uso........................................................................... 45 3.4.2. Diagrama de Classes .................................................................................... 51 3.4.3. Diagrama Entidade-Relacionamento do Banco de Dados ......................... 53 3.5. MATRIZ DE DISTÂNCIAS .......................................................................... 53 3.6. IMPLEMENTAÇÃO E FUNCIONAMENTO ............................................. 54 3.7. INSERÇÃO DE DADOS E SIMULAÇÃO DO SOFTWARE ..................... 68
4. CONCLUSÕES ....................................................................................74
REFERÊNCIAS BIBLIOGRÁFICAS ...................................................77
ANEXOS....................................................................................................79
iv
LISTA DE ABREVIATURAS
ACO Ant Colony Optimization CD Centro de Distribuição CNH Carteira Nacional de Habilitação CNPJ Cadastro Nacional de Pessoa Jurídica CPF Cadastro de Pessoa Física EA Enterprise Architect GA Genetic Algorithm GPDP General Pickup and Delivery Problem IE Inscrição Estadual NP Não Polinomial P Polinomial PCV Problema do Caixeiro Viajante PHP Hypertext Preprecessor PRV Problema de Roteirização de Veículos SA Simulated Annealing SISROTEN Sistema de Roteirização de Entregas TCC Trabalho de Conclusão de Curso TS Tabu Search TSP Traveling Salesman Problem UF Unidade Federal VRP Vehicle Routing Problem
v
LISTA DE FIGURAS
Figura 1. Representação das classes de problemas .........................................................................15 Figura 2. Representação do PCV ...................................................................................................16 Figura 3. Restrições de Cardinalidade para o PCV: (a) Solução Ilegal; (b) Restrições Associadas..19 Figura 4. Etapas da heurística das economias.................................................................................27 Figura 5. Aplicação da heurística k-opt: (a) Solução So; (b) Solução S...........................................33 Figura 6. O procedimento de economia..........................................................................................34 Figura 7. Aplicação da heurística de Clarke e Wright ....................................................................35 Figura 8. Representação da Economia ...........................................................................................39 Figura 9. Métodos de Otimização: (a) 2-opt; (b) 3-opt. ..................................................................42 Figura 10. Caminhão Toco ............................................................................................................43 Figura 11. Caminhão Truck ...........................................................................................................43 Figura 12. Carreta..........................................................................................................................43 Figura 13. Cavalo Mecânico ..........................................................................................................44 Figura 14. Caminhoneta.................................................................................................................44 Figura 15. Casos de Uso ................................................................................................................46 Figura 16. Diagrama de Classes.....................................................................................................51 Figura 17. Diagrama do Banco de Dados.......................................................................................53 Figura 18. Tela Inicial ...................................................................................................................55 Figura 19. Tela Principal ...............................................................................................................56 Figura 20. Tela com conteúdo de cada opção do menu ..................................................................57 Figura 21. Tela para edição e exclusão dos dados ..........................................................................57 Figura 22. Tela das opções para novo cadastro ou alterar os dados.................................................58 Figura 23. Tela com conteúdo de Roteiros do menu Opções ..........................................................59 Figura 24. Tela para emissão de roteiro .........................................................................................60 Figura 25. Primeira Rotina – Busca Caminhão...............................................................................61 Figura 26. Segunda Rotina – Busca Distância................................................................................61 Figura 27. Terceira Rotina – Busca Entregas por Cidade ...............................................................62 Figura 28. Quarta Rotina – Busca Entregas por Peso .....................................................................63 Figura 29. Quinta Rotina – Ordena Entregas..................................................................................63 Figura 30. Primeiro passo do Algoritmo ........................................................................................64 Figura 31. Segundo passo do Algoritmo ........................................................................................64 Figura 32. Terceiro passo do Algoritmo.........................................................................................65 Figura 33. Quarto passo do Algoritmo ...........................................................................................65 Figura 34. Tela para visualização do roteiro gerado .......................................................................66 Figura 35. Primeiro passo k-opt .....................................................................................................66 Figura 36. Segundo passo k-opt .....................................................................................................67 Figura 37. Tela do roteiro gerado com melhoria.............................................................................68 Figura 38. Roteiro gerado para Chapecó ........................................................................................70 Figura 39. Roteiro gerado para Cascavel........................................................................................71 Figura 40. Roteiro gerado para Porto Alegre..................................................................................73
vi
LISTA DE TABELAS
Tabela 1. Trabalhos mais importantes na área de roteirização de veículos........................................8 Tabela 2. Tabela com os trabalhos para o PCV clássico .................................................................24 Tabela 3. Critérios de classificação e subdivisões ..........................................................................29 Tabela 4. Tabela comparativa de sistemas .....................................................................................37 Tabela 5. Cenário Efetua Cadastro de Caminhões..........................................................................46 Tabela 6. Cenário Altera Cadastro de Caminhões ..........................................................................46 Tabela 7. Cenário Exclui Cadastro de Caminhões..........................................................................47 Tabela 8. Cenário Efetua Cadastro de Cidades...............................................................................47 Tabela 9. Cenário Altera Cadastro de Cidades ...............................................................................47 Tabela 10. Cenário Exclui Cadastro de Cidades.............................................................................47 Tabela 11. Cenário Efetua Cadastro de Clientes.............................................................................48 Tabela 12. Cenário Altera Cadastro de Clientes .............................................................................48 Tabela 13. Cenário Exclui Cadastro de Clientes.............................................................................48 Tabela 14. Cenário Efetua Cadastro de Entregas............................................................................48 Tabela 15. Cenário Altera Cadastro de Entregas ............................................................................49 Tabela 16. Cenário Exclui Cadastro de Entregas............................................................................49 Tabela 17. Cenário Cliente não Cadastrado....................................................................................49 Tabela 18. Cenário Efetua Cadastro de Motoristas.........................................................................50 Tabela 19. Cenário Altera Cadastro de Motoristas .........................................................................50 Tabela 20. Cenário Exclui Cadastro de Motoristas.........................................................................50 Tabela 21. Cenário Emissão de Roteiro .........................................................................................50
vii
LISTA DE EQUAÇÕES
Equação 1.....................................................................................................................................18 Equação 2......................................................................................................................................18 Equação 3......................................................................................................................................18 Equação 4......................................................................................................................................18 Equação 5......................................................................................................................................18 Equação 6......................................................................................................................................20 Equação 7......................................................................................................................................20 Equação 8......................................................................................................................................20 Equação 9......................................................................................................................................21 Equação 10....................................................................................................................................21 Equação 11....................................................................................................................................21 Equação 12....................................................................................................................................21 Equação 13....................................................................................................................................21 Equação 14....................................................................................................................................21 Equação 15....................................................................................................................................22 Equação 16....................................................................................................................................22 Equação 17....................................................................................................................................22 Equação 18....................................................................................................................................22 Equação 19....................................................................................................................................23 Equação 20....................................................................................................................................23 Equação 21....................................................................................................................................23 Equação 22....................................................................................................................................23 Equação 23....................................................................................................................................23 Equação 24....................................................................................................................................23 Equação 25....................................................................................................................................23 Equação 26....................................................................................................................................23 Equação 27....................................................................................................................................24 Equação 28....................................................................................................................................31 Equação 29....................................................................................................................................31 Equação 30....................................................................................................................................31 Equação 31....................................................................................................................................31 Equação 32....................................................................................................................................31 Equação 33....................................................................................................................................31 Equação 34....................................................................................................................................31 Equação 35....................................................................................................................................31 Equação 36....................................................................................................................................39 Equação 37....................................................................................................................................39 Equação 38....................................................................................................................................39 Equação 39....................................................................................................................................40
viii
RESUMO
TOIGO, Rafael. Sistema de Roteirização de Entregas. Itajaí, 2006. 139 f. Trabalho de Conclusão de Curso (Graduação em Ciência da Computação)–Centro de Ciências Tecnológicas da Terra e do Mar, Universidade do Vale do Itajaí, Itajaí, 2006. A partir dos anos 90, diversas mudanças no setor econômico e comercial brasileiro fizeram com que as empresas buscassem novas formas de gerenciamento. As organizações precisam baixar cada vez mais os seus custos. Surge a logística como diferencial que passa a ser imprescindível para manutenção dos níveis de competitividade e expansão em novos mercados. Outra característica importante é que os produtos devem estar em seus clientes finais com eficiência e no tempo planejado. A principal preocupação neste projeto foi o desenvolvimento de um sistema que auxilie no planejamento de entregas de mercadorias realizadas pelas empresas que prestam o serviço logístico às indústrias. Uma boa gestão de transportes garante melhores aproveitamentos dos recursos, disponibilizando o produto ao cliente em prazos menores, ganhando o mercado da concorrência. Para gerenciar a distribuição e roteirizar da melhor forma as entregas, o sistema proposto baseou-se no conceito de Busca Heurística na área de Inteligência Artificial. Foi usado também um método de otimização da rota, pois nem sempre o método heurístico sugere um caminho ótimo a ser percorrido pelo caminhão. Na elaboração e implementação foram utilizados conceitos de sistemas para web; a linguagem de programação PHP e o banco de dados MySQL. A modelagem foi feita no Enterprise Architect. O produto final destinou-se ao uso na Web. Os resultados esperados para este projeto foram principalmente focados na agilidade para criação da rota de entrega e que a mesma traga benefícios financeiros para as empresas de transporte/logística. Palavras-chave: Inteligência Artificial. Roteirização Inteligente. Heurística.
ix
ABSTRACT
Starting from the nineties, several changes in the economical and commercial Brazilian section
forced the companies to look for new administration forms. The organizations need to lower more
and more their costs. The logistics appears as a differential that passes to be indispensible for the
maintenance of the levels of competitiveness and expansion in new markets. Another important
characteristic is that the products should be in their final customers with efficiency and the planned
time. The main concern in this project was the planning of deliveries of goods accomplished by the
companies that do the logistics service to the industries. A good administration of transports
guarantees better uses of the resources, turning available the product to the customer in smaller
periods, gaining the market of the competition. To manage the distribution and create a route of the
best way to the deliveries, the proposed system was based on the concept of Heuristic Search in the
area of Artificial Intelligence. It was used, a method of otimization of the route, because not always
the heuristic method suggests a great road to be traveled by the truck. In the elaboration and
implementation were used tools and concepts of Web PHP, MySQL database and modeling with the
Enterprise Architect. The final product was destined to the use in the Web. The expected results for
this project are mainly focused on the agility for the creation of the delivery route and which, this
brings financial benefits for the transport/logistics companies.
Keyword: Artificial Inteligence. To create an Inteligent Route. Heuristic.
1. INTRODUÇÃO
Num mundo cada vez mais determinado por bens duráveis, mercados regionais e nacionais
bem definidos, necessidades que dificilmente se alteram nos consumidores e uma concorrência bem
identificada, a chave para a vantagem competitiva por parte de qualquer organização é a escolha de
um segmento característico e um aprimoramento em cima dele. Na economia atual praticamente
estática as estratégias competitivas podem ser limitadas (CUSTODIO, 2001).
Hoje em dia, à medida que a concorrência cresce, os mercados se fragmentam e expandem,
está cada vez mais difícil possuir um segmento único de mercado. Como os produtos estão com
seus ciclos de vida cada vez mais curtos, dominar segmentos únicos deixou de ser importante,
dando lugar à criação de novos produtos, comercializando-os rapidamente. Além disso, a
globalização dá espaço a novos concorrentes unindo os mercados nacionais e internacionais
(ibidem).
A estratégia competitiva torna-se mais dinâmica. As empresas têm que se antecipar às
tendências de mercado gerando respostas rápidas e eficazes aos clientes. Portanto, a estrutura dos
produtos e os mercados deixaram de ser uma estratégia competitiva, pois o sucesso depende da
organização e transformação dos processos existentes na empresa para gerar satisfação aos clientes
(ibidem).
Unir os processos em capacidades organizacionais requer que as empresas façam
investimentos estratégicos na infra-estrutura permitindo a relação entre as funções. Assim, surge
uma nova lógica de integração. Como hoje em dia os custos levam empresas a ignorar algumas das
suas atividades para uma tentativa de economia, aquelas que dão ênfase aos processos em sua
estratégia garantem uma ascensão. Nestas empresas os processos chave do negócio são controlados
(ibidem).
Modificando as estratégias para relacionar-se com a realidade da empresa pode-se obter
reduções de custo e/ou melhorias de serviço em muitos sistemas de distribuição das organizações.
Estas estratégias normalmente exploram as economias de escala que surgem ao conseguir
carregamentos completos, o que muitas vezes obriga as empresas a combinar entregas em locais
diferentes em rotas eficientes. As melhorias de eficiência e serviço exigem uma análise conjunta de
2
várias funções no ramo logístico, em particular o planejamento de transportes e o controle de
inventário (ibidem).
As diversas mudanças na estrutura das empresas e em suas políticas organizacionais com
aumento no número de pedidos, porém com volume de compra menor, bem como seus estoques
reduzidos fizeram com que, ultimamente, houvesse um crescimento muito grande do número de
entregas e de veículos trafegando pelas rodovias e vias urbanas, provocando, além de
engarrafamentos, aumento nos insumos relacionados aos custos de entregas e nos tempos para se
percorrer um determinado roteiro de distribuição da carga. Este fato, associado à necessidade por
parte das empresas de reduzir os custos no transporte de cargas, tem despertado o interesse de
inúmeros pesquisadores em estudos nessa área, na busca de soluções ótimas para os problemas de
roteirização de veículos (PIMENTA, 2001).
Hoje em dia, as empresas se preocupam muito em utilizar-se de forma racional todos os
recursos a fim de reduzir os custos relacionados ao transporte. Esse custo é o grande responsável
pelo aumento do preço das mercadorias. A redução e a melhora do serviço a fim de satisfazer da
melhor forma possível a necessidade do cliente são problemas que as empresas têm de se preocupar
dia a dia escolhendo um modal, ou seja, especializar-se somente em um meio de transporte, e o
trajeto para diminuir tempo e distância percorrida (SILVA, 2003).
Segundo Silva (2003), a roteirização e a programação de veículos são uma extensão do
problema da roteirização do veículo, em que a cada acréscimo de restrições o problema aproxima-se
da realidade. Essas restrições dificultam bastante a obtenção de uma solução ótima, que através de
algum procedimento heurístico lógico ou uma boa programação e roteirização pode-se chegar a
resultados satisfatórios. Para isso, são necessárias técnicas e dados para análises de transporte.
O estudo de elaboração de rotas e de programação de veículos vem crescendo
consideravelmente com o passar dos anos, já que são técnicas muito importantes para empresas que
necessitam realizar entregas. Silva (2003), classifica as técnicas da seguinte forma:
- Abordagem Heurística: adota regras empíricas de agrupamento ou técnicas baseadas em
“economias”, acrescentando ou excluindo paradas;
- Abordagem Exata: utilização de programação linear. Evoluiu bastante, mas ainda apresenta
dois problemas: um número grande de variáveis, mesmo para problemas mais simples; e elevado
tempo de processamento e memória necessária para realizá-lo;
3
- Abordagem Interativa: utiliza combinação de simulação com cálculo de custos para apoiar
o processo decisório. O desempenho custo e tempo das rotas definidas em um mapa são calculados,
a fim de se encontrar a melhor solução. O problema é a dependência da habilidade e talento do
analista; e
- Abordagem Combinada (Alternativas): combinação das três abordagens citadas. Nesta
abordagem há dois aspectos importantes para realizá-la: capacidade de generalização (modelar
características particulares) e precisão (determina o nível de credibilidade de possíveis economias
resultantes da melhoria do sistema de transporte).
Conforme Silva (2003), três tipos de dados são importantes para análise de transportes:
- Malha de Transporte: representação de todas as rotas possíveis. Contém informações
relacionadas à localização de clientes/fornecedores, tempo de viagem e outros detalhes;
- Demanda de Coletas e Entregas: são observados dados de demandas periódicas de coletas
e entregas. A demanda é então especificada em quantidades periódicas médias de coletas e de
entregas por cliente. As rotas são estabelecidas, de acordo com a demanda média, com uma
tolerância de capacidade para períodos de pico ou demanda alta;
- Características Operacionais: estão relacionadas aos recursos disponíveis, aos custos
associados à operação, bem como as limitações operacionais; e
- Métodos de Construção de Roteiro.
O projeto desenvolvido para uso em uma empresa de transporte ou operador logístico
oferece uma solução que prima pelo uso racional dos recursos existentes, facilitando a identificação
de falhas e levantando possíveis mudanças no sistema logístico atual. O roteiro que será gerado pelo
sistema deve garantir redução na distância percorrida bem como auxílio na carga e descarga do
caminhão em uma empresa de transporte ou logística.
4
1.1. OBJETIVOS
1.1.1. Objetivo Geral
Desenvolver um sistema para transportadoras de mercadorias ou operadores logísticos,
aplicando a roteirização inteligente nas entregas gerando itinerários com distâncias mínimas e
aproveitando da melhor forma a capacidade do veículo.
1.1.2. Objetivos Específicos
Os objetivos específicos deste projeto são:
• Pesquisar na área de Inteligencia Artificial sobre heurística, bem como, pesquisar
softwares de roteirização semelhantes ao projeto;
• Escolher o método heurístico a ser implementado em comum acordo, com o
coorientador especialista na área;
• Determinar os requisitos funcionais, não funcionais e as variáveis de entrada e saída para
o desenvolvimento do protótipo;
• Montar a matriz de distâncias entre as cidades;
• Modelar o sistema proposto;
• Implementar os cadastros e a heurística do sistema;
• Verificar a funcionalidade do sistema; e
• Documentar o trabalho realizado.
1.2. METODOLOGIA
O trabalho foi desenvolvido observando as seguintes etapas:
• Levantamento bibliográfico: foi feito buscando conhecimento teórico sobre o assunto
abordado através de livros, teses, dissertações, trabalhos de conclusão de curso, artigos
científicos e declarações de professores especialistas na área;
• Análise de requisitos: definiu-se a melhor técnica heurística na área de Inteligência
Artificial em comum acordo com o coorientador especialista na área, para ser utilizada
no desenvolvimento do trabalho, bem como, a linguagem de programação, banco de
5
dados e as ferramentas a serem utilizadas na modelagem e implementação do sistema.
Nesta etapa também foi definida a matriz de distâncias entre as cidades;
• Especificação do protótipo: realização da modelagem do sistema na ferramenta
Enterprise Architect;
• Inserção de dados reais para verificação da funcionalidade do software;
• Redação do volume final.
1.3. ESTRUTURA DO TRABALHO
O presente trabalho de conclusão de curso está estruturado da maneira descrita a seguir.
No Capítulo 1 está descrito principalmente a introdução dando uma abrangência geral da
economia do país e onde se aplica o projeto neste contexto. Há também os objetivos gerais e
específicos do trabalho.
O Capítulo 2, denominado Fundamentação Teórica, traz o levantamento bibliográfico feito
com todos os conceitos necessários para entender o problema em questão, para posteriormente
aplicá-lo no projeto. O material do capitulo dois é dividido da seguinte maneira:
- A Seção 2.1 define roteirização e roteamento, pois as palavras vêm do inglês routing.
- A Seção 2.2 define heurística e explica os métodos de construção e melhorias de
roteiros utilizados no protótipo para obter a roteirização inteligente.
- As classes dos problemas foram explicadas na Seção 2.3 já que o Problema do
Caixeiro Viajante e o Problema de Roteirização de Veículos pertencem à classe NP-
Hard, ou seja, problemas intratáveis.
- A última Seção do Capítulo 2, 2.4, apresenta os principais problemas de otimização
combinatória relacionados ao trabalho: Problema do Caixeiro Viajante e o Problema
de Roteirização de Veículos. São descritas as formulações, aplicações e soluções. No
PRV, a taxonomia facilita a identificação do problema.
O Capítulo 3, trata do desenvolvimento do projeto. A primeira Seção deste Capítulo, 3.1
apresenta de forma suscinta as caracteristicas dos sistemas similares ao SISROTEN pesquisados. A
Seção 3.2 refere-se aos métodos heurísticos utilizados no desenvolvimento do protótipo
6
apresentando o método das economias de Clarke e Wright e a heurística de otimização k-opt. Neste
Capítulo, conforme Seção 3.3, é determinado os requisitos funcionais e não funcionais do projeto. A
próxima Seção deste Capítulo, 3.4, refere-se a modelagem do sistema expondo o modelo de casos
de uso e a descrição de seus cenários, o diagrama de classes e a modelagem entidade-
relacionamento do banco de dados. A Seção 3.5 apresenta a idéia da matriz de distâncias. Um
cruzamento de quarenta e oito cidades determinando a distância em quilômetros entre todas. A
implementação e o funcionamento foram descritas no item 3.6. Para melhor entendimento de como
o sistema gera um roteiro de entrega são exibidos trechos de código e telas do sistema. A última
Seção, 3.7, descreve a inserção dos dados no banco de dados e a funcionalidade do software
desenvolvido.
O último Capítulo, 4, apresenta a conclusão do trabalho seguido da bibliografia e dos
anexos.
[FIM DE SEÇÃO. Não remova esta quebra de seção]
2. FUNDAMENTAÇÃO TEÓRICA
Logística é a integração das diversas funções de uma empresa como marketing, vendas,
armazenagem, estoque, distribuição e transporte, tendo como objetivo principal a melhoria na
movimentação e armazenagem de materiais e produtos (SILVA, 2003).
Um completo sistema de logística compreende em administrar toda cadeia que vai desde
onde os produtos são produzidos até onde são consumidos observando o fluxo de bens e serviço,
tendo como atividades primárias o transporte, a manutenção de estoques e o processamento de
pedidos. As empresas consideram o transporte como a principal atividade dentro de um sistema
logístico, pois a mesma tem seu custo associado em todo o processo e representa entre um e dois
terços do total dos custos logísticos. Sendo assim, a necessidade de melhorar a eficiência desta
atividade é de relevante importância. A busca pela redução do custo do transporte, através da
criação de um modelo de roteirização que disponibilize trajetos mais econômicos visando à
minimização do tempo, distância e custos associados, além da quantidade de veículos utilizados é
um problema freqüente de tomada de decisão na área da logística. A importância dos problemas de
roteirização é de grande importância devido aos custos de distribuição estarem cada vez mais altos.
Nesse contexto, um pequeno percentual que consiga se reduzir do custo representa uma
significativa economia (SIMAS, 2004).
Conforme Pimenta (2001), o modelo clássico de uma rede de transporte de cargas considera
diversos caminhões entregando e coletando os pedidos, commodities, circulando através do(s) nó(s)
de oferta (pontos de coleta) para os nós de demanda (pontos de entregas). Os veículos com
capacidades limitadas devem atender um conjunto de nós de oferta e de demanda, ou somente um
nó de oferta e diversos nós de demanda. Para que isso ocorra, os veículos circulam através das rotas
existentes entre os nós. A cada rota, ou arco, é associado um custo. O custo é um conjunto de
fatores que estão intrínsecos no deslocamento do veículo de um nó para outro, como combustível,
tempo, desgaste do veículo, características da via, distância percorrida, dentre outros.
O sistema de roteirização é definido como "um conjunto organizado de meios que objetiva o
atendimento de demandas localizadas nos arcos e/ou nos vértices de alguma rede de transportes"
(PIMENTA, 2001).
8
No caso de roteirização de veículos, o objetivo mais comum é respeitar um conjunto de
restrições e utilizar-se de uma frota de veículos para atender a um conjunto de pedidos de entrega,
cujas demandas estão localizadas nos nós da rede denominado destino. As restrições podem ser as
mais diversas, como: capacidade limitada dos veículos, capacidade limitada dos arcos ou dos nós;
tamanho da frota; quantidade de nós; tempo de entrega; etc.
Na literatura, há inúmeros trabalhos publicados, os quais abordam os mais diversos temas,
desde modelos simples (com frota homogênea, commodities de único tipo e sem janela de tempo) a
modelos bem mais complexos (com frota não-homogênea, commodities de diferentes tipos, janela
de tempo para a entrega da encomenda, com roteirização dinâmica, etc.).
Pimenta (2001), destaca os trabalhos mais importantes que são apresentados na Tabela 1.
Tabela 1. Trabalhos mais importantes na área de roteirização de veículos
Ano Pesquisador Restrições Objetivos 1987 Kolen, Kan
e Trienekens Janela de tempo (time windows), uma frota fixa de veículos, com capacidade limitada e disponível em um único depósito.
Atender a um conjunto de clientes com uma dada demanda. Cada cliente devia ser visitado dentro de um período específico
de tempo. 1993 Taillard Veículos idênticos (quantidade
não definida), possuindo capacidade de carga limitada, com as cargas concentradas em um único depósito. As cidades deveriam receber sua encomenda através de um só veículo. Mais tarde, considerou o mesmo problema formulado com restrição de janela de tempo.
Minimizou a distância percorrida pelos veículos para completar um percurso fechado entre várias cidades
1998 Savelsbergh e Sol
Em cada pedido são especificados o tamanho da carga a ser transportada, a sua origem e o seu destino e o tempo admitido entre a coleta e a entrega da mesma. Foi considerada uma frota heterogênea de veículos disponível para operar as rotas. Os parâmetros considerados no modelo de cada veículo são: capacidade, origem, tempo necessário para sua disponibilidade no local onde ele está sendo requisitado.
Seu trabalho é conhecido como problema geral de coleta e entrega (GPDP - General Pickup and Delivery Problem). Apresentaram um software para planejamento de transporte a ser incorporado em um sistema de suporte de decisão para uma grande companhia de transporte rodoviário na região de “Benelux“ (Bélgica, Holanda e Luxemburgo), com cerca de 1400 veículos, transportando 160 mil encomendas para centenas de consumidores, para dezenas de centenas de endereços.
9
2.1. ROTEIRIZAÇÃO
Como o termo Roteirização tem grande relevância ao trabalho e será citado posteriormente é
necessário sua definição. Isto é importante, pois pode fazer uma confusão com o termo
“roteamento” já que os dois vêm do inglês routing. Foram selecionadas as definições do dicionário
Michaelis (WEISZFLOG, 1998):
Roteirização – ato ou efeito de roteirizar.
Roteirização – ato de dividir em roteiros (itinerários ou planos de trabalho).
Roteamento – determinação da rota apropriada para uma mensagem através de uma rede.
Roteamento – processo de seleção do caminho mais curto ou mais confiável para os dados
no momento da conexão.
Assim o termo “roteamento” parece ser mais adequado à área de Informática enquanto o
termo “roteirização”, derivado do verbo roteirizar, representa melhor o ato de “preparar o
itinerário”.
2.2. HEURÍSTICA
Conforme Cunha, Bonasser e Abrahão (2002), heurísticas são procedimentos de solução que
muitas vezes se apóiam em uma abordagem intuitiva, na qual a estrutura particular do problema
possa ser considerada e explorada de forma inteligente, para a obtenção de uma solução adequada.
Os métodos heurísticos são aqueles que permitem a obtenção de soluções viáveis, não
necessariamente ótimas, mas com uma boa aproximação para problemas reais e com maior rapidez
que os métodos exatos.
Devido à existência de problemas de elevado nível de complexidade surgem as heurísticas
ou algoritmos heurísticos para resolvê-los em tempo computacional razoável. Ao se pensar em um
problema altamente combinatório, uma opção seria analisar todas as combinações possíveis para
conhecer a melhor. Se o problema possui um universo de dados pequeno, realmente esta é a
maneira correta de se buscar a melhor solução, mas os problemas reais, normalmente, possuem um
número de combinações muito extenso, o que torna inviável a análise de todas as combinações, uma
vez que o tempo computacional exigido fica impraticável. As heurísticas procuram encontrar
10
soluções boas em um tempo computacional razoável, sem, no entanto, conseguir definir se esta é a
solução ótima, nem se está próxima da solução ótima.
Assim, na maioria dos casos as heurísticas propostas tendem a ser bastante específicas e
particulares para um determinado problema, isto é, não conseguem produzir boas soluções para
problemas com características condicionantes ou restrições pouco diferentes daquelas para as quais
foram desenvolvidas (CUNHA, BONASSER e ABRAHÃO, 2002).
Métodos heurísticos compõem um campo muito grande de soluções para problemas de
otimização combinatória. Tais métodos possuem origens distintas, geralmente utilizadas
especificamente para um problema combinatório. Quando um método é aplicado especificamente
no problema sob a forma de um algoritmo, este é denominado um método heurístico, ou
simplesmente uma heurística.
Existe também na literatura o termo Metaheurística (ANDRADE, BATISTA e TOSO, 2004;
CUNHA, BONASSER e ABRAHÃO, 2002; PELIZARO, 2000). A distinção entre tais
denominações faz-se por:
- Metaheurística: possui grande abrangência podendo ser aplicada na maioria dos problemas
de otimização combinatória. Pode-se citar com exemplo as Metaheurística ACO (Ant Colony
Optimization), GA (Genetic Algorithm), SA (Simulated Annealing) e TS (Tabu Search); e
- Heurística: é uma instanciação de uma Metaheurística, ou seja, a aplicação da mesma em
um problema específico de otimização. Por exemplo, denominou-se AntSystem a heurística ACO
aplicada na resolução do problema do caixeiro viajante (PCV).
Conforme Helsgaun (2000 apud CUNHA, BONASSER e ABRAHÃO, 2002) os
procedimentos heurísticos para o PCV podem ser divididos em dois grupos: os métodos de
construção de roteiros e os métodos de melhorias de roteiros. Pode-se ainda considerar um terceiro
grupo, o dos métodos compostos, em que heurísticas de construção e melhorias de roteiros são
utilizadas de forma conjunta.
Nas Sessões 2.2.1 e 2.2.2 a seguir, tem-se a explicação dos métodos de construção de
roteiros e métodos de melhorias de roteiros. Os dois métodos são responsáveis conjuntamente pelo
resultado satisfatório para um determinado problema. Quanto maior for o nível de abstração e
implementação da realidade em cima dos métodos melhor será a solução.
11
2.2.1. Métodos de Construção de Roteiros
Nos métodos de construção de roteiros, os nós ou cidades são incluídos no roteiro de forma
seqüencial e gradual, sem que a solução parcial obtida seja melhorada. Assim, um roteiro é
construído iterativamente, sem modificações posteriores das seqüências iniciais de cidades,
definidas ao longo do processamento do algoritmo.
A construção do roteiro pode se dar através (Laporte, 1992 apud CUNHA, BONASSER e
ABRAHÃO, 2002):
- do método do vizinho mais próximo, no qual o caixeiro inicia do depósito ou ponto inicial
e então vai para a cidade mais próxima; a partir desta, busca-se a cidade mais próxima ainda não
visitada e assim sucessivamente até que todas as cidades sejam percorridas uma vez somente. Ao
final o caixeiro viajante retorna à cidade de origem; e
- de métodos de inserção, nos quais, parte-se de um conjunto de cidades inicial,
normalmente com apenas duas cidades, e considerando todas as demais cidades ainda não incluídas
no roteiro. As cidades não incluídas no roteiro parcial são inseridas atendendo um determinado
critério pré-estabelecido. Esse procedimento é repetido sucessivamente, com a análise da inserção
entre cada par de cidades do roteiro parcial, até que todas as cidades sejam inseridas no roteiro.
Os métodos de construção de roteiros compreendem ainda (Reinelt, 1994 apud CUNHA,
BONASSER e ABRAHÃO, 2002):
- heurísticas baseadas em árvores de cobertura nas quais a árvore de cobertura mínima é
utilizada como base para guiar a construção do roteiro; e
- o método das economias, proposto por Clarke e Wright. As cidades vão sendo
sucessivamente agrupadas, de forma seqüencial, para formar um roteiro, com base em uma ordem
decrescente do cálculo de economias decorrentes da sua união que considera a distância de cada um
dos pontos ao ponto inicial e também à distância entre eles.
Cunha, Bonasser e Abrahão (2002), destacam que segundo testes computacionais realizados
pelos mais diversos pesquisadores da área de otimização, o método das economias e suas variações
dentre os mais de 36 métodos proporciona uma das melhores soluções para problemas do caixeiro
viajante. Os testes feitos foram comparados em um abrangente experimento computacional.
12
2.2.2. Métodos de Melhorias de Roteiros
Genericamente esses métodos procuram melhorar a solução para o problema do caixeiro
viajante obtido através de algum outro método. Os métodos de melhorias mais utilizados são do
tipo k-opt, conforme proposto por Lin e Kernighan (1973 apud CUNHA, BONASSER e
ABRAHÃO, 2002), nos quais k arcos são removidos de um roteiro e substituídos por outros k
arcos, com a finalidade de diminuir a distância total percorrida.
Conforme Laporte (1992 apud CUNHA, BONASSER e ABRAHÃO, 2002), quanto maior o
valor de k, melhor a precisão do método, porém maior também é o esforço computacional. Na
prática, são considerados os métodos 2-opt e 3-opt, isto é, k assumindo os valores 2 ou 3.
Resumidamente em outras palavras, o método 2-opt faz testes em possíveis trocas entre
pares de arcos, refazendo as conexões quando houver uma melhoria no roteiro. O processo termina
quando não for possível mais realizar nenhuma troca que resulte em melhoria. Este procedimento
possui ordem de complexidade O(n2). Como pode ocorrer inversões de sentido em alguma parte do
roteiro, supõe-se que as distâncias são iguais (ibidem).
No caso do método 3-opt são considerados três arcos ao invés de dois, a fim de se avaliarem
as alterações nas conexões entre os nós, o que resulta em sete possíveis combinações.
Existem outros métodos de melhorias para otimização que são baseados em metaheurística
do tipo simulated annealing e busca tabu, que também se baseiam em métodos de melhorias do tipo
2-opt ou 3-opt. A diferença destes métodos é que eles procuram ir além da solução final obtida. No
tipo simulated annealing utiliza-se a temperatura para controlar possibilidades de soluções melhores
partindo-se de soluções piores no início. Já na busca tabu selecionam-se movimentos que são
temporariamente proibidos, por isso seu nome tabu.
2.3. CLASSES DE PROBLEMAS
Conforme Simas (2004) algoritmos são geralmente definidos como procedimentos para a
resolução de um problema que recebem valores como conjunto de entrada e devem produzir, a
partir deles, valores como conjunto de saída. Um algoritmo pode resolver um problema quando,
para qualquer entrada, ele produz uma resposta correta, concedendo tempo e memória suficiente
para a sua execução. Entretanto, mesmo que o algoritmo retorne uma solução não significa que ele
13
seja aceito, pois os recursos concedidos de memória e tempo de processamento para resolução do
problema são limitados e nem sempre suficientes para que um algoritmo seja executável.
Um algoritmo é aceito se seu tempo de execução pode ser expresso por um polinômio no
tamanho de sua entrada. Caso contrário, assume-se que seu tempo de execução é exponencial. Um
problema é considerado solucionável quando existe um algoritmo de complexidade polinomial que
o resolva e intratável quando todos os algoritmos conhecidos para resolvê-los possuem
complexidade exponencial ou não polinomial. O termo intratável é utilizado porque o algoritmo tem
um tempo de execução que cresce tão rapidamente com o tamanho de sua entrada “n” que, para um
“n” razoavelmente grande, a sua execução torna-se proibitiva. Muitos problemas que são
considerados intratáveis para os quais, não há algoritmo de tempo polinomial conhecido. O
Problema do Caixeiro Viajante e o Problema de Roteirização de Veículos são problemas
classificados como intratáveis. Normalmente, este assunto é estudado para problemas de decisão.
Os problemas de decisão são aqueles cujas respostas geram saídas do tipo sim ou não. Uma vez que
exista um algoritmo que resolva em tempo polinomial um problema de otimização, ele pode ser
modificado para resolver também o problema de decisão associado (SIMAS, 2004).
Nas Seções 2.3.1 e 2.3.2 é apresentada uma breve explicação das classes de P, NP, NP-
Completo e NP-Hard tendo como objetivo principal mostrar os critérios relevantes a tratabilidade.
2.3.1. Classe P e NP
É necessário antes de definir estas duas classes, apresentar os conceitos de determinismo e
não – determinismo que são aplicados aos algoritmos. Simas (2004) conceitua que os algoritmos
que rodam de uma maneira determinística são aqueles que quando executados para um mesmo
conjunto de dados de entrada produzem sempre o mesmo resultado, pois para cada passo de
execução eles têm apenas uma opção de escolha. Já um algoritmo não-determinístico tem opções de
escolha que não estão especificadas no algoritmo e nem são probabilísticas. Este tipo de algoritmo
consiste de duas fases: a primeira em que é sugerida uma resposta ao problema e uma fase de
verificação que testa se esta resposta serve como solução ao problema. A idéia do não-
determinismo está relacionada com a parte dos testes para determinar qual a saída correta. A classe
P é composta pelos problemas para os quais existe um algoritmo determinístico que o resolva com
complexidade de tempo polinomial. Os problemas que possuem algoritmos não-determinísticos
com complexidade de tempo polinomial são ditos da classe NP. Uma vez que um problema de
14
decisão foi resolvido então deve haver uma justificativa para esta resposta. Para justificar a resposta
dos problemas de decisão há duas fases:
Fase 1: Exibição – Exibir a justificativa; e
Fase 2: Reconhecimento – Análise da justificativa e verificar se é satisfatória ao problema.
Em problemas de decisão que se justifica a resposta SIM também são classificados como
NP. A fase de reconhecimento pode ser realizada por um algoritmo polinomial.
2.3.2. Classe NP-Completo e NP-Hard
Primeiramente é preciso o entendimento do conceito de redução associado a esta classe. Um
problema de decisão A pode ser reduzido a outro problema de decisão A’ se para qualquer instância
de A uma instância de A’ puder ser construída em tempo polinomial. Uma notação que pode ser
utilizada para representar a redução de A para A’ é A α A’ (SIMAS, 2004).
As três etapas do processo de redução são:
1 – Transformar uma instância de um problema A numa instância de um outro problema A’;
2 – Aplicar um algoritmo para a instância A’, obtendo uma solução S’; e
3 – Transformar a solução S’ para a solução S de A.
A Redutibilidade permite que um problema seja resolvido em termos de outro e isso implica
que se A α A’, então A pode ser considerado um caso particular de A’ e que é pelo menos tão difícil
quanto A’.
A classe NP-Completo é composta pelos problemas para os quais se conhecem algoritmos
não-determinísticos eficientes, porém não se sabe se existe ou não algoritmos polinomiais eficientes
que os resolvam. Os problemas NP-Completo são considerados os de “maior dificuldade” da classe
NP. Um problema de decisão A é NP-Completo se:
1. A está na classe NP; e
2. Qualquer outro problema da classe NP pode ser reduzido a A em tempo polinomial.
15
Os problemas NP-Completo compartilham a propriedade de que se um problema NP-
Completo for resolvido por um algoritmo determinístico polinomialmente, então todos os
problemas NP também o serão.
Conforme Toscani e Velozo (2001 apud SIMAS, 2004) a classe NP-Hard é composta pelos
problemas em que apenas a condição (2) é considerada, ou seja, um problema A é NP-Hard se
qualquer problema NP puder ser reduzido polinomialmente a A não importando se A está na classe
NP ou não, logo, um problema NP-Hard é pelo menos tão difícil quanto um problema NP-
Completo. A Figura 1, representa as quatro classes apresentadas neste trabalho.
Figura 1. Representação das classes de problemas
Fonte: Adaptado de Toscani e Velozo (2001 apud SIMAS, 2004).
2.4. PROBLEMAS DE OTIMIZAÇÃO COMBINATÓRIA
A grande dificuldade de solução dos problemas de otimização combinatória está no número
elevado de soluções existentes e não ótimas.
Se a distância de uma cidade i a outra j seja simétrica, isto é, que dij = dji, o número total de
soluções possíveis é (n – 1)! / 2, sendo classificado na literatura como NP-Hard, isto é, não existem
algoritmos que o resolvam em tempo polinomial, somente exponencial. Mesmo com os rápidos
avanços tecnológicos a solução é inconcebível para elevados valores da variável n.
16
Como há um limite acima do qual tal problema torna-se intratável computacionalmente, este
é normalmente abordado através de heurísticas. Os principais problemas utilizados na roteirização
de entregas são: o Problema do Caixeiro Viajante (PCV), o Problema Geral de Coletas e Entregas
(GPDP) e o Problema de Roteirização de Veículos (PRV).
2.4.1. Problema do Caixeiro Viajante
Um dos problemas mais estudados em otimização combinatória é o Problema do Caixeiro
Viajante – PCV (do inglês Traveling Salesman Problem - TSP). Diversos estudos já foram feitos
sobre este problema e hoje representa um dos grandes desafios na otimização combinatória para a
área de Pesquisa Operacional e Inteligência Artificial. Outro grande interesse por este problema é
que com o PCV e suas variações muitos problemas reais podem ser modelados.
Portanto, a importância do modelo é evidente tanto no aspecto prático como no aspecto
teórico. Toda essa importância é principalmente pela sua grande aplicação prática, grande relação
com os outros modelos e grande dificuldade de se obter uma solução final exata.
Cunha, Bonasser e Abrahão (2002) definem o PCV como sendo o problema de encontrar o
roteiro de menor distância ou custo que passa por um conjunto de cidades, sendo cada cidade
visitada exatamente uma vez.
A Figura 2, representa um dos vários possíveis roteiros para um conjunto de cidades.
Figura 2. Representação do PCV
Fonte: Adaptado de Skiena (1997 apud SIMAS, 2004).
17
O PCV é considerado como intratável e pertence à categoria conhecida como NP-Hard, o
que significa que possui ordem de complexidade exponencial, ou seja, o esforço computacional
para a sua resolução cresce exponencialmente com o tamanho do problema. Isto significa que não
se obtém soluções ótimas para problemas reais que pertencem a mesma classe que o Problema do
Caixeiro Viajante. Os métodos aplicados para resolução destes problemas, métodos heurísticos, não
geram saídas ótimas do ponto de vista matemático, mas sim próximas a solução ideal (CUNHA,
BONASSER e ABRAHÃO, 2002).
Narciso e Lorena (2003) afirmam que um possível modelo a ser considerado em transporte
de produtos é o problema do caixeiro viajante e propõe: suponha que um caixeiro ou caminhão, a
partir de sua cidade de origem, precise visitar um conjunto de n - 1 cidades onde estão os pontos de
entrega. As cidades deverão ser visitadas somente uma vez. Após visitar todas as n - 1 cidades,
então o caixeiro deverá voltar a sua cidade inicial. O caixeiro poderá escolher a primeira cidade a
ser visitada, a segunda, e assim por diante. Entretanto, caso o caixeiro queira economizar tempo e
energia (ou ainda gasolina, recursos, etc.), ele deverá procurar o menor caminho de tal forma que
todas as cidades sejam visitadas somente uma vez e então retornar para a sua cidade de origem. Se o
caixeiro sabe a distância entre as cidades, então ele pode encontrar o caminho mais curto para a sua
viagem simplesmente por comparar todas as maneiras possíveis de se visitar as n - 1 cidades e
voltar. Entretanto, admitindo-se que exista sempre um caminho ligando uma cidade à outra, à
medida que o número de cidades vai crescendo, o número de maneiras de se visitar todas as
cidades, que é dado por (n - 1)!, cresce também.
Os métodos não exatos ou heurísticos são os métodos ideais para encontrarmos soluções
para o PCV quando o número de cidades é elevado, pois as saídas são viáveis devido a proximidade
com a solução ótima sem que seja necessário analisar todas as soluções possíveis. Porém, é
necessário a escolha de um bom método que em geral forneça esta solução perto da otimalidade. A
partir deste método pode-se melhorá-lo ou aceitar a solução obtida (NARCISO e LORENA, 2003).
Conforme a literatura estudada (CUNHA, BONASSER e ABRAHÃO, 2002; GOLDBARG
e LUNA, 2000; NARCISO e LORENA, 2003; SIMAS, 2004) existem dois métodos para a solução
do PCV: métodos heurísticos e métodos exatos. Os métodos exatos são baseados em árvores e
apresentam várias limitações. Devido a esta dificuldade dos métodos exatos retornarem uma
solução viável em tempo computacional adequando os métodos heurísticos compõe o principal foco
de estudo para o problema.
18
2.4.1.1. Formulações
Existem várias formulações para esse problema. Devido sua importância é apresentado as
mais difundidas. Essas formulações podem ser consideradas como canônicas, tanto por sua larga
difusão na literatura especializada como por desenvolverem modos peculiares de caracterização do
problema (GOLDBARG e LUNA, 2000).
2.4.1.1.1. Formulação de Dantzig-Fulkerson-Johnson
Esta formulação define o PCV como sendo um problema de programação 0-1 sobre um
grafo G = (N,A), onde N é o conjunto de nós ou vértices, e A é o conjunto de arcos ou arestas que
conectam cada par de cidades i e j ∈ N, conforme pode ser visto na seqüência:
Equação 1
Sujeito a:
Equação 2
Equação 3
Equação 4
Equação 5
19
A variável binária Xij assume valor igual a 1, se o arco (i,j) ∈ A for escolhido para integrar a
solução, e 0 em caso contrário. S é tido como um subgrafo de G, em que |S| representa o número de
vértices desse subgrafo. Nessa formulação é assumido implicitamente que Xij não existe e que se
tem n (n – 1) variáveis inteiras 0-1 e O(2n) restrições.
As restrições (Equação 2) e (Equação 3) são semelhantes às do problema de designação, de
modo que, configurações como as presentes na Figura 3, seriam válidas. Já o conjunto de restrições
(Equação 4) determina a eliminação desses circuitos pré-hamiltonianos.
As equações |S| tornam os circuitos pré-hamiltonianos ilegais, conforme se pode ver na
Figura 3, onde |S| = 5.
(a) (b)
Figura 3. Restrições de Cardinalidade para o PCV: (a) Solução Ilegal; (b) Restrições Associadas
Fonte: Adaptado de Goldbarg e Luna (2000).
Para circuito pré-hamiltoniano possível é necessário uma restrição do tipo (Equação 4), o
que justifica o número de O(2n) restrições.
Segundo Goldbarg e Luna (2000), essa formulação testa um importante aspecto do PCV,
que é a sua natureza combinatória. E que para solucioná-lo basta determinar uma certa permutação
legal do custo mínimo.
Esta formulação também auxilia no entendimento da ligação do PCV aos problemas de
seqüenciamento de operações, que são comuns na manufatura, onde supondo que exista um certo
20
tempo de preparação de cada máquina para receber uma determinada tarefa, e que as tarefas possam
ser distribuídas de várias formas no conjunto de máquinas existentes. O problema de encontrar uma
seqüência de operações que minimiza o tempo de preparação dessas máquinas e, conseqüentemente,
os custos relacionados ao trabalho, podem ser modelados como um PCV.
2.4.1.1.2. Formulação de Miller-Tucker-Zemlin
De acordo com Goldbarg e Luna (2000), a formulação para o PCV proposta por Miller,
Tucker e Zemlin, é denominada Folha de Cravo e é apresentada da seguinte forma:
“Denota-se a cidade 1 como a cidade início-fim ou cidade origem. O Caixeiro Viajante deve
visitar as outras (n-1) cidades exatamente uma vez. Durante seu trajeto deve retornar a cidade de
origem exatamente t vezes, incluindo o retorno final, e não deve visitar mais de p cidades diferentes
em um tour ou ciclo.”
A formulação descrita acima requer que:
Equação 6
Onde a denota o menor inteiro maior ou igual ao valor de a, ou teto da divisão, para
garantir a existência de tours viáveis. Sendo assim, o PCV pode ser formulado da seguinte forma:
Equação 7
Sujeito a:
Equação 8
21
Equação 9
Equação 10
Equação 11
Equação 12
Equação 13
A restrição (Equação 8) da formulação explicitada anteriormente garante que a cidade de
origem é visitada exatamente t vezes. O arco (i,j) em toda solução viável 0-1 das restrições
(Equação 8), (Equação 9) e (Equação 10) obrigam o conjunto de restrições em p a transformar-se
em:
Equação 14
A formulação expressa nesta seção envolve O(2n) restrições em n2 – 1 variáveis. Quando t =
1 e p ≥ n – 1, então modela o PCV.
2.4.1.1.3. Formulação de Fox-Gavish-Graves
Esta formulação do PCV é uma generalização denominada time dependent, ou seja,
dependente de tempo. Aqui o custo de percorrer o caminho entre as cidades i-j depende da posição t
do arco (i,j) em um tour de uma dada cidade origem indexada por 1.
22
A proposta original foi proposta por Fox para solucionar o problema 1-machine n-job
scheduling. As variáveis de decisão desse modelo Zijt são triplamente indexadas. Zijt = 1 se o arco
de i para j é designado na t-ésima posição do tour, Zijt = 0 para o caso contrario. Sendo assim, tem-
se:
Equação 15
Sujeito a:
Equação 16
Equação 17
Equação 18
A restrição (Equação 16) ou restrição de agregação do problema de alocação 3-dimensional,
garante que cada cidade é visitada exatamente uma única vez e que para cada posição do tour exista
um arco designado. Esta restrição garante também a eliminação de subtours.
2.4.1.1.4. Formulação de Claus
Esta formulação utiliza conceitos de fluxos em rede, onde denotando por s a cidade origem
ou fonte, e transformando todo ciclo hamiltoniano em um caminho hamiltoniano, por considerar
também a cidade origem como um destino t, pode-se interpretar o PCV como um problema de
determinar um caminho hamiltoniano de s para t no dígrafo G = (V,E), onde tem-se:
23
Equação 19
Pode-se interpretar a variável binária x associada a aresta (i,j) como: Xij = 1 se (i,j) pertence
a um caminho hamiltoniano, e 0 caso contrário.
O fluxo na rede envolve n+1 comodidades. Claus define uma variável auxiliar Yijk como o
fluxo da k-ésima comodidade no arco (i,j). Sendo assim, tem-se:
Equação 20
Sujeito a:
Equação 21
Equação 22
Equação 23
Equação 24
Equação 25
Equação 26
24
Equação 27
A formulação C envolve um conjunto de restrições da ordem de n³ e (n³ + n² + 3n) variáveis.
2.4.1.2. Aplicações
O PCV, em suas diversas versões, está presente em inúmeros problemas práticos. Pode-se
destacar:
- Programação de operações de máquinas em manufatura, transporte entre células de
manufatura;
- Otimização do movimento de ferramentas de corte, de perfurações de furos em
placas de circuitos impressos;
- Na maioria dos problemas de roteirização de veículos;
- Na solução de problemas de seqüenciamento, de programação e distribuição de
tarefas em plantas; e
- Trabalhos administrativos.
2.4.1.3. Solução através de Heurísticas
A literatura que aborda a solução do PCV é muito diversificada. A Tabela 2 apresenta o que
Goldbarg e Luna (2000) organizaram de principais trabalhos numa visão panorâmica para o
Problema do Caixeiro Viajante.
Tabela 2. Tabela com os trabalhos para o PCV clássico
Ano Pesquisador Trabalho 1954 Dantzig Trabalho referência para o PCV 1972 Christofides, e Eilon Métodos exatos 1973 Laporte, e Norbert Métodos exatos 1973 Lin, e Kernighan Métodos heurísticos 1980 Carpaneto e Toth Critérios para algoritmos B&B 1980 Golden Heurísticas para o PCV 1980 Kanellakis e Papadimitriou Busca local 1980 Crowder e Padberg B&B 1981 Belas e Christofides Restrições lagrangeanas para o PCV
25
1983 Adrabinski Experimentos computacionais para heurísticas 1985 Fleischmann Algoritmo com uso de plano de cortes 1985 Goldberg e Lingle Algoritmos genéticos 1985 Grefenstette Algoritmos genéticos 1985 Cerny Métodos termodinâmicos (Simulated annealing) 1987 Laarhoven e Aarts Métodos termodinâmicos (Simulated annealing) 1988 Burr Métodos elásticos 1990 Johnson Otimização local 1991 Ulder Algoritmos genéticos 1991 Whitley Algoritmos genéticos 1991 Glover Busca tabu 1991 Miller e Pekny Métodos exatos 1992 Gendreau Procedimentos de pós-otimização 1993 Reeves Métodos aproximativos 1995 Jünger Relaxações e B&Cut 1995 Potts e Van de Velde Heurística híbrida de k-substituição 1996 Chatterjee Algoritmos genéticos 1996 Potvin Algoritmos genéticos 1997 Somhom Redes neuronais 1977 Rosenkrantz Revisão das abordagens heurísticas 1990 Melamed Revisão do estado da arte 1992 Laporte Revisão do estado da arte 1994 Bianco Revisão do estado da arte
Fonte: Adaptado de Goldbarg e Luna (2000).
Goldbarg e Luna (2000) apresentaram as soluções do PCV através dos métodos de k-opt e
economia.
2.4.1.3.1. Heurística k-opt
As heurísticas de substituição ou k-opt são estratégias de melhoria e partem de um ciclo
hamiltoniano inicial. Existem relatos de que elas têm bom desempenho computacional,
especialmente as 2-opt e 3-opt.
Goldbarg e Luna (2000) demonstraram a heurística de k-opt:
1 – Iniciar por um ciclo hamiltoniano {V1, V2,...,Vn};
2 – Remover k vértices do ciclo corrente, tornando-o incompleto;
3 – Construir todas as soluções viáveis que contenham o ciclo anterior;
4 – Escolher a melhor solução entre as encontradas; e
26
5 – Testar as condições de parada (número de iterações, elementos em subconjunto
de controle, limites para o valor da solução etc.), prosseguindo ou não em nova
iteração.
O esforço computacional para testar todas as possíveis trocas sugeridas pela remoção das k
arestas cresce exponencialmente na ordem de n! / ((n-k)! k!), ou seja, com o número de
subconjuntos que são gerados na lista L. Além do mais, o crescimento de k também aumenta o
número dos possíveis ciclos hamiltonianos.
2.4.1.3.2. Heurística das Economias
Concluindo-se que a heurística das economias é uma abordagem adequada para o PCV
euclidiano e simétrico, sua aplicação é necessária à utilização de um grafo completo. O algoritmo
pode ser descrito da seguinte forma:
1 – Iniciar pelo vértice k, selecionado por algum critério ou aleatoriamente;
2 – Considerar todos os vértices ligados ao vértice k, ou seja, um circuito não
hamiltoniano que passa n vezes pelo nó k;
3 – Obter a lista das economias da seguinte forma: Sij = Cjk – Cij, i,j = 1,...,n, onde S é
a economia se o vértice i for ligado diretamente ao vértice j sem passar por k;
4 – Ordenar as economias em lista monótona decrescente;
5 – Percorrer a lista iniciando pela primeira posição. Tentar a ligação correspondente
ao maior Sij;
6 – Se a inserção da aresta (i,j) e a retirada da aresta (k,i) e (j,k) resultar em uma rota
iniciando em k e passando pelos demais vértices, eliminar da lista. Caso
contrário, tentar a ligação seguinte na lista; e
7 – Repetir o procedimento até obter o ciclo hamiltoniano.
27
Na Figura 4, apresentada por Goldbarg e Luna (2000), é demonstrado as etapas da heurística
das economias.
Figura 4. Etapas da heurística das economias
Fonte: Adaptado de Goldbarg e Luna (2000).
28
2.4.2. Problema de Roteirização de Veículos
Larsen (2000 apud ANDRADE, BATISTA e TOSO, 2004) define o Problema de
Roteirização de Veículos (PRV) como segue: dado um conjunto de cidades (ou consumidores), cada
qual com uma demanda qi por um produto, e um depósito com veículos de capacidade Q, encontrar
as rotas para os veículos minimizando os custos de transporte.
O problema de roteirização de veículos PRV também é conhecido como VRP (Vehicle
Routing Problem). O problema é uma generalização do problema do caixeiro viajante, consistindo
em determinar rotas de veículos, onde uma rota é um ciclo que começa em um depósito. Os
veículos precisam visitar um determinado conjunto de clientes ou nós de demanda em determinado
roteiro e voltando ao depósito a seguir. Todos os pontos de demanda devem ser visitados apenas
uma vez e o total da demanda dos clientes de uma rota não pode exceder a capacidade do veículo
(ibidem).
Uma variação do PRV é o Problema Geral de Coletas e Entregas (General Pickup and
Delivery Problem) que consiste em um conjunto de rotas que deve ser construído a fim de satisfazer
pedidos de transporte. Uma frota de veículos é disponibilizada para operar nas rotas. Cada veículo
tem certa capacidade, um local inicial e um local final. Cada pedido de transporte especifica um
tamanho da carga a ser transportada, as localidades onde serão feitas as coletas e as localidades
onde serão feitas as entregas. Cada carga deve ser transportada por um veículo do seu conjunto de
origens para o seu conjunto de destinos sem nenhuma baldeação em outras localidades. Neste
problema, cada pedido de transporte especifica uma simples origem e um simples destino e todos os
veículos partem e retornam ao depósito central (ANDRADE, BATISTA e TOSO, 2004).
A noção de roteirização de veículos já é bastante comum no cotidiano das pessoas. Desde a
distribuição de gás à coleta de lixo, da entrega de encomendas normais às de grande porte e
urgência, o problema básico de definição de rotas para que os veículos de transporte possam
entregar suas encomendas se faz presente. Um problema típico de roteirização de veículos (PRV)
pode ser descrito, como o problema de definição do menor custo das rotas de um depósito a um
conjunto de clientes distribuídos em um plano geográfico. As rotas devem ser definidas para que
cada cliente seja visitado somente uma única vez por exatamente um único veículo, começando e
terminando no depósito, de forma a não exceder a capacidade do veículo. Todas as demandas dos
clientes devem ser satisfeitas (NEVES, 2004).
29
Para a modelagem matemática destes problemas reais o fator complicante é a grande
quantidade de restrições existentes. É aceitável que existam vários pontos de fornecimento, os
depósitos, veículos com diversas capacidades, restrições de entrega como tempo ou distância.
Todos estes fatores devem ser considerados como essenciais para a perfeita modelagem do
problema a ser solucionado pela heurística. Dependendo da determinada restrição que aplicamos ao
problema o PRV é dividido em subclasses ou variações como roteirização de veículos com janela
de tempo, com restrição de capacidade de peso ou volume, entre outros.
Conforme Andrade, Batista e Toso (2004) a formulação matemática do PRV engloba o que
foi descrito no Problema Geral de Coleta e Entregas e também são acrescidas algumas restrições.
No PRV, ou o veículo faz uma coleta ou ele faz uma entrega, e nunca faz os dois numa mesma
viagem, ou seja, |W| = |N+i| = |N−i| = 1 ∀i ∈ N, onde N+ = W ou N− = W, onde N é um conjunto de
pedidos de transporte e i é cada pedido. Desta forma, o pedido de transporte que o veículo irá
atender só pode estar contido em um dos conjuntos, ou seja, ou no conjunto de origens ou locais de
coleta, ou no conjunto de destinos ou locais de entrega.
2.4.2.1. Taxonomia Geral
A roteirização é um problema que está intimamente ligado ao problema de seqüenciamento.
O resultado de uma roteirização, além da seqüência de visitas, pode depender da ordem com que as
atividades em cada local de visita sejam realizadas. Devido à complexidade de cada etapa do
problema e às diversas modelagens possíveis, a tarefa de definir uma abordagem é de suma
importância. A taxonomia baseia-se nas características do problema. A principal vantagem é a
facilidade de identificação do problema. Goldbarg e Luna (2000) classificam o problema de
roteirização em relação a diversos critérios que são apresentados na Tabela 3.
Tabela 3. Critérios de classificação e subdivisões
Critério Subdivisão Tempo para servir um determinado nó ou arco
- Tempo especificado e prefixado - Janela de Tempo
Número de domicílios - Um domicílio - Mais de um domicílio
Tamanho da frota de veículos
- Um veículo - Mais de um veículo
Tipo de frota disponível
- Homogênea - Heterogênea
Natureza da demanda e parâmetros
- Determinística - Estocástica
30
Localização da demanda
- Nos vértices - Nos arcos
Grafo de substrato
- Direcionado - Não direcionado - Misto
Restrições na capacidade de veículos
- Todos sujeitos às mesmas restrições - Restrições diferentes
Tempo de roteirização
- O mesmo para todos os veículos - Tempos diversos - Sem restrições de tempo
Custos
- Variáveis (associados à rota escolhida) - Fixos
Operação
- De entrega - De recolhimento - Ambas
Objetivo
- Minimizar custos fixos - Minimizar custos de operação na rota - Minimizar o número de veículos
Restrições na capacidade dos arcos
- Imposta a todos os arcos - Impostas a um subconjunto de arcos - Sem restrições
2.4.2.2. Formulação
A importância e a influência do modo de formular um problema de otimização,
especialmente em áreas complexas como as de roteirização deve-se ao impacto direto no
desempenho dos algoritmos de solução.
Quanto maior for o número de variáveis e restrições de um mesmo problema, normalmente,
maior será o esforço necessário para encontrarmos sua solução. Assim o porte das formulações
influencia na possibilidade de solução.
Em virtude das características de NP-Hard de muitos problemas combinatórios, a
formulação ideal pode ser inalcançável em termos práticos. Por outro lado os problemas e
otimização podem admitir diversas formulações diferentes.
Conforme Goldbarg e Luna (2000) a formulação mais utilizada é a de Fisher e Jaikumar
como segue:
31
Equação 28
Sujeito a:
Equação 29
Equação 30
Equação 31
Equação 32
Equação 33
Equação 34
Equação 35
Onde:
Xijk = variável binária que assume valor 1 quando o veículo k visita o cliente j
imediatamente após o cliente i, 0 em caso contrário;
32
Yik = variável binária que assume valor 1 se o cliente i é visitado pelo veículo k, 0 em caso
contrário;
qi = é a demanda do cliente i;
Qk = é a capacidade do veiculo k; e
Cij = é o custo de percorrer o trecho que vai do cliente i ao j.
As restrições (Equação 29) assegurarão que um veículo não visite mais de uma vez um
cliente. As restrições (Equação 30) garantem que o depósito receba uma visita de todos os veículos.
As restrições (Equação 31) obrigam que a capacidade dos veículos não seja ultrapassada. As
restrições (Equação 32) garantem que os veículos não param suas rotas em um cliente. As restrições
(Equação 33) constituem as tradicionais restrições de eliminação de subtours.
2.4.2.3. Aplicações
Goldbarg e Luna (2000), destacaram as principais aplicações do Problema de Roteirização
de Veículos. Dentre as mais perceptíveis pela sociedade estão as escalas de serviço e os roteiros
utilizados pelos meios de transporte.
- Distribuição de jornais, manufaturados, alimentos, correspondência, bebidas,
valores, produtos químicos, gás, vagões ferroviários, derivados de petróleo e
produtos diversos;
- Transporte escolar, pedras;
- Recolhimento de lixo, material reciclável, borracha;
- Medidores elétricos;
- Roteirização de helicópteros, linhas aéreas, células de manufatura flexível, navios de
longo curso e cabotagem;
- Sistemas de transportes coletivos urbanos, proteção contra incêndio;
- Serviços de emergência, patrulhamento policial;
- Escalas de operários nas empresas, auditores bancários; e
33
- Alocação de recursos para não sobrecarregar determinados equipamentos, veículos.
2.4.2.4. Solução através de Heurísticas
Assim como no Problema do Caixeiro Viajante, o método das economias de Clarke e Wright
e o método de otimização k-opt, são apresentados para a solução do Problema de Roteirização de
Veículos conforme estudados e apresentados por Goldbarg e Luna (2000).
2.4.2.4.1. Heurística k-opt
A heurística k-opt é o exemplo de uma heurística de busca local. De fato a heurística propõe
uma busca em uma k vizinhança de uma solução de roteirização. A busca se faz pelo exame da
possibilidade de troca de k variáveis (arcos) entre so e s. Na medida em que k cresce, o
procedimento aproxima-se da enumeração total (caso em que k = n-2), a vizinhança de so cresce
exponencialmente na forma de n! / [(n-k)!k!]. Para k=2 o tamanho da vizinhança de so é igual a n(n-
1) / 2. Golbarg e Luna (2000) relatam soluções eficientes somente para k=2 e k=3. A Figura 5
exemplifica um procedimento de 2-trocas onde a substituição dos arcos é bem clara.
(a) (b)
Figura 5. Aplicação da heurística k-opt: (a) Solução So; (b) Solução S
Fonte: Adaptado de Goldbarg e Luna (2000).
Os arcos 5-4 e 9-6 são substituídos pelos arcos 5-9 e 4-6. O arco 9-4 é percorrido no sentido
inverso da solução s. Se o grafo de substrato é não direcionado, o procedimento anterior é
tipicamente de duas trocas. Se o grafo é direcionado e os custos de percorrer o arco 9-4 são
diferentes do de percorrer 4-9, poderíamos considerá-lo como de três trocas.
34
2.4.2.4.2. Heurística das Economias
Goldbarg e Luna (2000) consideram que o vetor sij representa o valor da economia obtida
pela reorganização de duas ligações do tipo (i-1-i) e (j-1-j) em uma nova (i,j) como mostra a Figura
6.
Figura 6. O procedimento de economia
Fonte: Adaptado de Goldbarg e Luna (2000).
Goldbarg e Luna (2000) demonstram a heurística das Economias:
1 – Ler G = (N,A), cij. {*nó 1 é o depósito central do roteamento*};
2 – Inicializar Rota := (x1-xs-x1);
3 – Calcular a economia sij:=c1j-cij+cj1 para todo o par de clientes xi e xj {*nós em
G*};
4 – Ordenar as economias em ordem não crescente e colocá-las em uma lista;
5 – Enquanto existirem ligações na lista Faça;
5.1 – Iniciando pela maior economia da lista Faça; e
5.1.1 – Determine a primeira ligação na lista que pode ser utilizada para ser
acrescida em um dos dois extremos de Rota, aumentando seu
35
comprimento e retirando-o da lista; Se Rota não pode ser expandida
da forma anterior, então escolha a primeira ligação na lista para
iniciar uma nova rota e a retire da lista.
A Figura 7, letra (a), mostra um grafo inicial de um roteiro. Na letra (b) e (c) é apresentado
um desenvolvimento da heurística de Clarke e Wright conforme Goldbarg e Luna (2000).
Figura 7. Aplicação da heurística de Clarke e Wright
Fonte: Adaptado de Goldbarg e Luna (2000).
À medida que uma rota vai sendo construída, é possível realizar os testes relativos às
restrições. Em relação ao comportamento do algoritmo, ele possui a característica de aninhar os
clientes nas rotas que vão se formando. Na Figura 7, o nó 2, após a segunda melhoria, passou à
condição de interno (sem ligação direta com o vértice depósito) não sendo mais candidato a
melhoria na rota, uma vez que só são testados para a inserção os nós extremos, ou seja, aqueles que
se ligam diretamente ao nó central (vértice 1). [FIM DE SEÇÃO. Não remova esta quebra de seção]
3. DESENVOLVIMENTO
O software SISROTEN consiste em um sistema que automatiza as entregas de uma empresa
através da roteirização inteligente. O projeto destina-se ao uso de empresas de transporte ou
operadores logísticos.
Neste Capítulo, são descritos os sistemas similares, conforme Seção 3.1, e os métodos
heurísticos de economias e k-opt, Seção 3.2, que serão utilizados para implementação do protótipo.
A Seção 3.3 e 3.4, apresenta os requisitos funcionais e não-funcionais do software e a
modelagem do sistema respectivamente. Na modelagem estão representados os diagramas de casos
de uso, diagrama de classes e a modelagem entidade-relacionamento do banco de dados.
A matriz de distâncias utilizada no cálculo de quilometragem entre uma cidade e outra é
descrita na Seção 3.5. A tabela de distâncias foi incorporada ao TCC nos Anexos.
As duas últimas Sessões, 3.6 e 3.7, expõe a implementação e funcionamento do software
desenvolvido, e a inserção de informações no banco de dados para simulações de roteiros.
3.1. SISTEMAS SIMILARES E SISTEMA PROPOSTO
O primeiro software pesquisado foi chamado de Multitrans e serve para otimização da
roteirização de veículos. Foi implementado no ambiente Delphi, da Borland, o qual utiliza o Object
Pascal como linguagem de programação orientada a objetos. Nesta primeira versão, utilizou-se o
Paradox para manipular o banco de dados, devido à facilidade e simplicidade de implementação de
sua estrutura de tabelas, além do mesmo ser gratuito, estando disponível para download na internet.
O sistema operacional utilizado foi o Windows. Foram considerados 2 tipos de veículos: furgão e
ônibus. Assim transportam-se passageiros e cargas / encomendas. Os pontos de parada, depósito são
cadastrados não utilizando mapas (PIMENTA, 2001).
Para obtenção da rota e do veículo apropriado utiliza-se o algoritmo de menor caminho para
obtenção da primeira solução. Após este primeiro conjunto de veículos e suas rotas estarem
formadas utiliza-se à relaxação lagrangeana para o tratamento das restrições. As restrições
implementadas são de exclusividade (uma commoditie é somente carregada em um veículo) e
capacidade (carga máxima do veiculo em questão). A cada restrição o software aplica testes para
saber se a frota e as rotas serão as definitivas. Caso contrário novas mudanças são feitas (ibidem).
37
O pacote de otimização usado é o CPLEX, que tem como origem o método Simplex na área
da Pesquisa Operacional. O uso deste método é eficaz, porém gera muito esforço computacional
ocasionando demora da resposta dos problemas mais complexos.
O software Delivery é composto por uma base cartográfica vetorizada de todas as cidades,
rodovias e hidrovias do Brasil. Esta base não pode ser editada, ou seja, modificada pelo usuário. As
restrições implementadas são: frota heterogênea, um depósito, janelas de tempo, limites de
capacidade em peso e volume e cálculos de tempo de entrega, paradas, etc. O software não é
multiplataforma e pode ser utilizado somente no sistema operacional Windows. O custo do software
é aproximadamente R$ 3.000,00. O esforço computacional é médio, pois não possui muitas
restrições (PELIZARO, 2000).
No software TransCAD pode-se inserir uma base cartográfica qualquer ou ainda cadastrar
novos pontos de entrega / coleta. As restrições utilizadas são: janelas de tempo, frota heterogênea,
mais de um depósito, tipos de produtos, capacidade dos veículos (peso), cálculos de tempo de
entrega, percurso, etc. A heurística utilizada é a do menor caminho. O sistema, assim como o
Delivery, só pode ser utilizado em plataforma Windows. Seu custo aproximado é U$ 11.000,00.
Além de sua robustez o TransCad requer grande esforço computacional (ibidem).
O software proposto neste Trabalho de Conclusão de Curso recebe o nome de SISROTEN –
Sistema de Roteirização de Entregas. O software em questão não pretende ser a solução ótima para
problema de roteirização de veículos, mas sim mais um estudo na área que está em evidência
atualmente. O SISROTEN utiliza o método heurístico de Clarke e Wright conhecido como método
das economias e com o algoritmo de otimização k-opt. Multiplataforma foi desenvolvido em PHP
para uso na Internet e com banco de dados MySQL. As restrições serão: capacidade (peso e
volume), frota heterogênea, um depósito. Não foram calculados tempos de entrega, viagem, paradas
de abastecimento, etc.
A Tabela 4, apresenta a comparação entre os sistemas:
Tabela 4. Tabela comparativa de sistemas
SISROTEN TransCAD Delivery Multitrans Comercial Não Sim Sim Não Preço R$ 0,00 U$ 11000,00 R$ 3000,00 R$ 0,00 Plataforma Multiplataforma Windows Windows Windows Banco de Dados MySQL Não Informado Não Informado Paradox Implementação PHP Não Informado Não Informado Delphi
38
Veículos Carreta e Truck Não Informado Não Informado Furgão e Ônibus Restrições Peso e Volume Janela de Tempo e
Peso Janela de Tempo, Peso e Volume.
Peso
Heurística Método das Economias
Caminho Mínimo Não Informado Menor Caminho
Otimização k-opt Não Informado Não Informado CPLEX Esforço computacional
Fraco Grande Médio Grande
Depósitos 1 Vários 1 1 Mapas Não Sim Sim Não
3.2. MÉTODOS HEURÍSTICOS UTILIZADOS
Dentre os trabalhos pesquisados Silva (2003), descreve que o método das economias de
Clarke e Wright, quando utilizado para roteirização, gera uma saída muito próxima ao ideal.
Em comum acordo com a coorientação, foi definido que além de usar o método das
economias o sistema deve apresentar um método para possível melhora deste roteiro gerado. Em
pesquisa realizada a teses e dissertações com a ajuda da coorientacão, foi determinado que o método
k-opt atinge os objetivos deste projeto.
Nas Sessões, 3.2.1 e 3.2.2, é apresentado os métodos heurísticos utilizados para o
desenvolvimento do sistema.
3.2.1. Método das economias (Clarke & Wright)
O método das economias vem sendo utilizado em larga escala, pois possibilita a
implementação de diversas restrições e seu método de construção de roteiros é muito bem
elaborado. Das diversas restrições o método, assim como os outros, respeita principalmente tempo e
capacidade. Seu objetivo é gerar roteiros com distâncias mínimas para a realização das entregas.
Esse método é um dos mais importantes da categoria, pois produz uma saída bem próxima da
realidade, ou seja, seu erro em relação a solução ótima é muito baixo (SILVA, 2003).
Este método, também conhecido como o método de Clarke e Wright, inicia assumindo que
um único veículo serve um único cliente. Conforme são cadastrados clientes são requeridos os
caminhões, ou seja, para um conjunto de N clientes, o método assume que N veículos serão
requeridos. O método então calcula a economia Sij, em distância, que pode ser obtida unindo os
clientes i e j e atendendo a eles com um único veículo. A economia Sij é calculada através da
fórmula:
39
Sij = Sji=di1 + d1j – dji Equação 36
Simas (2004) representa através da Figura 8 a economia obtida através da união dos clientes
i e j que passam a ser atendidos por um único veículo.
Figura 8. Representação da Economia
Fonte: Adaptado de Goldbarg e Luna (1998 apud SIMAS, 2004).
À medida que o roteiro diminui, o número de veículos também diminui, reduzindo, assim os
investimentos e os custos de operação.
Conforme Simas (2004) o método das economias baseia-se na pior hipótese e a partir do
momento que começa a combinar entregas mostra sua importância. Em primeira instância, como foi
dito, o método considera um veiculo para uma única entrega e depois retorna ao ponto de partida.
Para se atender todos os clientes, obviamente seriam necessários uma quantidade muito grande de
veículos e de pessoal. Suponha que o cliente j seria atendido após o cliente i, onde dD,i e dD,j são as
distâncias do CD ao cliente i e j, respectivamente. Então o veículo faria o seguinte percurso:
L = 2 x dD,i + 2 x dD,j Equação 37
Uma possibilidade de melhoria seria unir esses dois clientes em um único roteiro. Dessa
forma a distância percorrida seria:
L’ = dD,i + di,j + dD,j Equação 38
40
A economia de percurso (ganho) será a diferença entre os dois roteiros (L-L’):
gi,j = L – L’= dD,i + dD,j - di,j Equação 39
Durante a formação da seqüência do roteiro procura-se selecionar o par com maior ganho gi,
j, respeitando sempre as restrições de tempo e capacidade. Analisando a terceira equação, verificam-
se duas propriedades:
- O ganho tende a crescer quando os pontos i e/ou j se afastam do CD, pois as parcelas dD,i +
dD,j têm valores positivos; e
- O ganho tende a crescer quando os pontos i e j estão mais próximos, pois a parcela di,j, que
aparece com sinal negativo na relação tem menor valor absoluto.
O método é iniciado através da análise das combinações possíveis em grupos de dois a dois
e listados em ordem decrescente de ganho. Conforme Silva (2003), os maiores ganhos são dos
pontos mais afastados do ponto de partida (CD) e mais próximos entre si, portanto, o roteiro é
formado a partir dos pontos mais distantes e vindo em direção ao CD. As etapas desse método são:
Etapa 1. Combinam-se todos os pontos dois a dois e calcula-se o ganho para cada
combinação;
Etapa 2. Ordenam-se todas as combinações i, j, de forma decrescente, segundo os valores
dos ganhos gi,j;
Etapa 3. Inicia-se com a combinação de maior ganho. Posteriormente, na análise de outras
situações, vai-se descendo na lista de combinações, sempre obedecendo à seqüência decrescente de
ganhos;
Etapa 4. Para um par de pontos (i, j), verificar:
(a) se i e j não foram incluídos em nenhum roteiro já iniciado, criar então um novo
roteiro com esses dois pontos;
(b) se o ponto i já pertence a um roteiro iniciado, verificar se esse ponto é primeiro
ou último desse roteiro (sem contar o CD). Se a resposta for positiva, acrescentar o par de pontos
41
(i,j) na extremidade apropriada. Fazer a mesma análise para j; se nenhum dos dois pontos satisfizer
essa condição separadamente, passar para o item (c);
(c) se ambos os pontos i e j fazem parte, cada um deles, de roteiros iniciados, mas
diferentes, verificar se ambos são extremos dos respectivos roteiros. Se a resposta for positiva,
fundir os dois roteiros num só, juntando-os de forma a unir i e j. Caso contrário, Etapa 5; e
(d) se ambos os nós pertencerem ao mesmo roteiro, passar para Etapa 5.
Etapa 5. Cada vez que se acrescentar um ou mais pontos num roteiro, ou quando se fundir
dois roteiros num só, verificar se a nova configuração satisfaz as restrições de tempo e de
capacidade. Se atender aos limites das restrições, a nova configuração é aceita; e
Etapa 6. O processo termina quando todos os pontos (clientes) tiverem sido incluídos num
roteiro.
3.2.2. Método de Melhoria K-opt
Os métodos de melhorias procuram aperfeiçoar o resultado obtido por um método qualquer,
através da uma sistemática preestabelecida. Os métodos mais utilizados são o 2-opt e o 3-opt,
desenvolvidos por Lin e Kernighan (1965). O método 2-opt, que é mais simples consiste em
permutar arcos em uma rota inicial, buscando encontrar uma rota de menor custo conforme é
constituído pelas seguintes etapas (Novaes, 2001 apud SILVA, 2003):
Etapa 1. Começa com um roteiro qualquer, de preferência gerado por um método de
construção;
Etapa 2. Removem-se dois arcos do roteiro e reconectam-se (tentativa) os nós que formam
esses dois arcos, modificando as ligações. Se o resultado for melhor que o anterior, ou seja, roteiro
menor, substitui-se o roteiro inicial pelo novo e repete-se a Etapa 2. Caso contrário, o roteiro
anterior é mantido, outros dois arcos são escolhidos, repetindo a Etapa 2 e assim sucessivamente; e
Etapa 3. O processo termina quando não é possível obter nenhuma melhoria, ao realizar
todas as trocas de ligação possíveis.
O método 3-opt tem o mesmo conceito que o 2-opt, com a diferença que agora são tomados
três pares de nós de cada vez. O método 3-opt é um pouco mais complexo que o 2-opt, no entanto,
42
oferece resultados mais precisos. Outra diferença é que esse método permite sete alterações para
cada configuração básica.
Cunha, Bonasser e Abrahão (2002) demonstram a movimentação dos métodos de
otimização 2-opt e 3-opt conforme a Figura 9.
(a) (b)
Figura 9. Métodos de Otimização: (a) 2-opt; (b) 3-opt.
Fonte: Adaptado de Novaes (2001 apud CUNHA, BONASSER e ABRAHÃO, 2002).
3.3. REQUISITOS DO SISTEMA
Como foi dito anteriormente, o software foi desenvolvido em PHP e banco de dados
MySQL. Para automação da empresa de transporte ou operador logístico o roteiro será gerado
através do método das economias de Clarke e Wright. Para otimização deste roteiro para se chegar
mais próximo do ideal possível será utilizado o método heurístico k-opt.
Terá como restrições a capacidade (peso e volume). Serão utilizados cinco tipos de veículos
para realizar as entregas: caminhão truck, com capacidade de dez a dezessete toneladas, carreta,
com capacidade de vinte e cinco a trinta toneladas, caminhoneta, com capacidade de tres a quatro
toneladas, cavalo mecânico, com peso de zero toneladas e caminhão toco com peso entre quatro mil
e quinhentos quilos a seis mil quilos, ou seja, toneladas. A capacidade do caminhão em quilogramas
varia na fração de quinhentos quilos, ou seja, no caso da caminhoneta a capacidade de carga pode
ser de três mil quilos, três mil e quinhentos quilos ou quatro mil quilos.
A Figura 10, mostra um caminhão do tipo toco. A diferenciação deste veículo para os outros
é um único eixo abaixo do baú ou carroceria, onde são carregadas as mercadorias.
43
Figura 10. Caminhão Toco
A Figura 11, apresenta um caminhão do tipo truck. O veículo tem dois eixos abaixo do baú
ou carroceria.
Figura 11. Caminhão Truck
A carreta, conforme Figura 12, pode ter um, dois e três eixos abaixo do baú ou carroceria. A
grande diferença dos demais veículos é o pino de engate na parte dianteira. Assim, esse veículo não
tem motor, ou seja, o veículo do tipo cavalo mecânico, “puxa” a carreta.
Figura 12. Carreta
44
Conforme já mencionado o veículo cavalo mecânico é usado em comum acordo com o
veículo carreta. O cavalo mecânico não tem espaço para carregar mercadorias. Sua função é engatar
a carreta e deslocá-la ao destino. A Figura 13, representa o veículo cavalo mecânico.
Figura 13. Cavalo Mecânico
A caminhoneta, Figura 14, tem as mesmas características do caminhão toco, porém, de
menor porte. Portanto seu chassi não é reforçado, não aguentando muito peso de mercadorias.
Figura 14. Caminhoneta
O sistema de entregas baseia-se em somente uma commoditie, ou seja, os caminhões de
entregas só levarão mercadorias. Uma grande evolução nos softwares de otimização é que o
SISROTEN é multiplataforma, pois é destinado ao uso na Internet.
Os requisitos do software foram divididos em funcionais, relativo a utilização do software e
não-funcionais, que são os requisitos relacionados ao universo global do uso da ferramenta.
Os requisitos funcionais são:
- O sistema permite cadastrar, excluir, alterar e visualizar motoristas;
- O sistema propicia o cadastro, exclusão, alteração e visualização de cidades;
- O sistema permite cadastrar, excluir, alterar e visualizar caminhões;
- O sistema permite cadastrar, excluir, alterar e visualizar clientes;
- O sistema propicia o cadastro, exclusão, alteração e visualização de entregas; e
45
- O sistema emite o roteiro de entregas para o carregamento dos caminhões;
Os requisitos não funcionais são:
- O sistema deve garantir a segurança e integridade dos dados;
- O roteiro de entregas deve apresentar dados confiáveis para a tomada de decisões em nível
operacional e estratégico dentro da empresa;
- O sistema via Web deve possuir um mecanismo de segurança para evitar que pessoas não
autorizadas tenham acesso a dados restritos;
- As informações do sistema são armazenadas fisicamente em banco de dados MySQL; e
- O software será implementado em linguagem PHP para uso na Internet;
3.4. MODELAGEM DO SISTEMA
Os diagramas de casos de uso, de classes e entidade relacionamento do banco de dados
foram realizados na ferramenta Enterprise Architect. Primeiramente será apresentado o diagrama de
casos de uso e seus cenários para cada ação do sistema, conforme Seção 3.4.1. Na Seção 3.4.2 será
explicado o diagrama de classes e suas características. Por último, na Seção 3.4.3, será apresentado
a modelagem do banco de dados.
3.4.1. Diagrama de Casos de Uso
A emissão do roteiro pode ser feita por qualquer usuário que opere o sistema. O sistema
deve dar suporte no controle de caminhões, motoristas, clientes, entregas e cidades. Com as
informações anteriores é possível gerar o roteiro de entregas com quilometragem mínima que
deverá ser capaz de agilizar o carregamento e descarregamento dos caminhões.
Na Figura 15, são representadas as ações que o usuário deverá realizar para emissão do
roteiro.
46
ud Modelo Use Case
Cadastro de
Clientes
Operador
Cadastro de
Motoristas
Cadastro de
Caminhões
Cadastro de
Entregas
Emissão de
Roteiro
Cadastro de
Cidades
Figura 15. Casos de Uso
O Cadastro de Caminhões serve principalmente para o controle da tara (peso máximo em
quilogramas que o caminhão suporta). Nesta função têm-se as seguintes opções que serão
representadas através das tabelas 5, 6 e 7.
Tabela 5. Cenário Efetua Cadastro de Caminhões
Efetua Cadastro {Principal} 1) Funcionário solicita cadastro de caminhão. 2) Sistema exibe tela de cadastro de caminhões. 3) Funcionário solicita novo cadastro. 4) Sistema limpa os campos da tela para preenchimento. 5) Funcionário informa os dados do caminhão. 6) Funcionário solicita salvar as informações. 7) Sistema pesquisa Placa na base de dados. 8) Se Placa não encontrado, sistema salva as informações.
Tabela 6. Cenário Altera Cadastro de Caminhões
Altera Cadastro {Alternativo} 1) Funcionário solicita cadastro de caminhão. 2) Sistema exibe tela de cadastro de caminhões. 3) Funcionário seleciona a Placa do caminhão e solicita pesquisa. 4) Sistema pesquisa Placa na base de dados.
47
4) Sistema exibe os dados atuais do caminhão. 5) Funcionário efetua as alterações. 6) Funcionário solicita salvar as alterações. 7) Sistema salva as alterações.
Tabela 7. Cenário Exclui Cadastro de Caminhões
Exclui Cadastro {Alternativo} 1) Funcionário solicita cadastro de caminhão. 2) Sistema exibe tela de cadastro de caminhões. 3) Funcionário seleciona a Placa do caminhão e solicita pesquisa. 4) Sistema pesquisa Placa na base de dados. 5) Sistema exibe os dados do caminhão. 6) Funcionário solicita exclusão do caminhão. 7) Sistema efetua exclusão da base de dados.
A função primordial do cadastro de cidades é a manutenção das distancias entre as cidades e
auxilio para que os endereços estejam corretos. Portanto, tem-se os seguintes cenários:
Tabela 8. Cenário Efetua Cadastro de Cidades
Efetua Cadastro {Principal} 1) Funcionário solicita cadastro de cidade. 2) Sistema exibe tela de cadastro de cidade. 3) Funcionário solicita novo cadastro. 4) Sistema limpa os campos da tela para preenchimento. 5) Funcionário informa o nome da cidade. 6) Funcionário informa o estado. 7) Funcionário solicita salvar as informações. 8) Sistema salva as informações.
Tabela 9. Cenário Altera Cadastro de Cidades
Altera Cadastro {Alternativo} 1) Funcionário solicita cadastro de cidade. 2) Sistema exibe tela de cadastro de cidade. 3) Funcionário seleciona o nome da cidade e solicita pesquisa. 4) Sistema pesquisa nome na base de dados. 5) Sistema exibe os dados atuais da cidade. 6) Funcionário efetua as alterações. 7) Funcionário solicita salvar as alterações. 8) Sistema salva as alterações.
Tabela 10. Cenário Exclui Cadastro de Cidades
Exclui Cadastro {Alternativo} 1) Funcionário solicita cadastro de cidade. 2) Sistema exibe tela de cadastro de cidade. 3) Funcionário seleciona o nome da cidade e solicita pesquisa. 4) Sistema pesquisa o nome na base de dados.
48
5) Sistema exibe os dados da cidade. 6) Funcionário solicita exclusão da cidade. 7) Sistema efetua exclusão da base de dados.
O cadastro de clientes é necessário para relacioná-los às entregas.
Tabela 11. Cenário Efetua Cadastro de Clientes
Efetua Cadastro {Principal} 1) Funcionário solicita cadastro de cliente. 2) Sistema exibe tela de cadastro de clientes. 3) Funcionário solicita novo cadastro. 4) Sistema limpa os campos da tela para preenchimento. 5) Funcionário informa os dados do cliente. 6) Funcionário solicita salvar as informações. 7) Sistema pesquisa CNPJ na base de dados. 8) Se CNPJ não encontrado, sistema salva as informações.
Tabela 12. Cenário Altera Cadastro de Clientes
Altera Cadastro {Alternativo} 1) Funcionário solicita cadastro de cliente. 2) Sistema exibe tela de cadastro de clientes. 3) Funcionário seleciona o nome do cliente e solicita pesquisa. 4) Sistema pesquisa CNPJ na base de dados. 5) Sistema exibe os dados atuais do cliente. 6) Funcionário efetua as alterações. 7) Funcionário solicita salvar as alterações. 8) Sistema salva as alterações.
Tabela 13. Cenário Exclui Cadastro de Clientes
Exclui Cadastro {Alternativo} 1) Funcionário solicita cadastro de cliente. 2) Sistema exibe tela de cadastro de clientes. 3) Funcionário seleciona o nome do cliente e solicita pesquisa. 4) Sistema pesquisa CNPJ na base de dados. 5) Sistema exibe os dados do cliente. 6) Funcionário solicita exclusão do cliente. 7) Sistema efetua exclusão da base de dados.
No cadastro de entregas o cliente deseja armazenar uma determinada quantidade de entregas
de determinados clientes com sua origem, destino e número de nota fiscal e características da carga
como peso, volume e quantidade.
Tabela 14. Cenário Efetua Cadastro de Entregas
Efetua Cadastro {Principal} 1) Funcionário solicita cadastro de Entrega.
49
2) Sistema exibe tela inicial de cadastro de Entrega. 3) Funcionário informa o número da Nota Fiscal. 4) Funcionário informa o CNPJ do remetente. 5) Sistema pesquisa CNPJ na base de dados. 6) Se cliente encontrado: 6.4) Funcionário informa o CNPJ do destinatário. 6.5) Sistema pesquisa CNPJ na base de dados. 6.6) Se cliente encontrado: 7) Funcionário informa o peso da nota fiscal. 8) Funcionário informa a quantidade de volumes. 9) Funcionário informa o volume em m3 da carga. 10) Funcionário informa a data de emissão da nota fiscal 11) Funcionário solicita concluir o cadastro da Nota Fiscal. 12) Sistema salva as informações.
Tabela 15. Cenário Altera Cadastro de Entregas
Altera Cadastro {Alternativo} 1) Funcionário solicita cadastro de entrega. 2) Sistema exibe tela de cadastro de entrega. 3) Funcionário seleciona o número da nota fiscal e solicita pesquisa. 4) Sistema pesquisa nota fiscal na base de dados. 5) Sistema exibe os dados da entrega. 6) Funcionário efetua as alterações. 7) Funcionário solicita salvar as alterações. 8) Sistema salva as alterações.
Tabela 16. Cenário Exclui Cadastro de Entregas
Exclui Cadastro {Alternativo} 1) Funcionário solicita cadastro de entrega. 2) Sistema exibe tela de cadastro de entrega. 3) Funcionário seleciona o número da Nota Fiscal e solicita pesquisa. 4) Sistema pesquisa número na base de dados. 5) Sistema exibe os dados da entrega. 6) Funcionário solicita exclusão da entrega. 7) Sistema efetua exclusão da base de dados.
Tabela 17. Cenário Cliente não Cadastrado
Cliente não Cadastrado {Exceção} No passo 6 e 6.6, se CNPJ do cliente não está cadastrado: 6.1) Sistema exibe tela para cadastro de clientes. 6.2) Se cadastro for efetuado, prossegue com cadastro de Entrega. 6.3) Se cadastro de cliente não for efetuado, aborta operação de Entrega.
O cadastro de motorista serve para dar auxílio e distribuí-los nos roteiros de entregas. Nas
Tabelas 18, 19 e 20 são apresentados seus cenários.
50
Tabela 18. Cenário Efetua Cadastro de Motoristas
Efetua Cadastro {Principal} 1) Funcionário solicita cadastro de motorista. 2) Sistema exibe tela de cadastro de motoristas. 3) Funcionário solicita novo cadastro. 4) Sistema limpa os campos da tela para preenchimento. 5) Funcionário informa os dados do motorista. 6) Funcionário solicita salvar as informações. 7) Sistema pesquisa CPF na base de dados. 8) Se CPF não encontrado, sistema salva as informações.
Tabela 19. Cenário Altera Cadastro de Motoristas
Altera Cadastro {Alternativo} 1) Funcionário solicita cadastro de motorista. 2) Sistema exibe tela de cadastro de motoristas. 3) Funcionário seleciona o nome do motorista e solicita pesquisa. 4) Sistema pesquisa CPF na base de dados. 5) Sistema exibe os dados atuais do motorista. 6) Funcionário efetua as alterações. 7) Funcionário solicita salvar as alterações. 8) Sistema salva as alterações.
Tabela 20. Cenário Exclui Cadastro de Motoristas
Exclui Cadastro {Alternativo} 1) Funcionário solicita cadastro de motorista. 2) Sistema exibe tela de cadastro de motoristas. 3) Funcionário seleciona o nome e solicita pesquisa. 4) Sistema pesquisa CPF na base de dados. 5) Sistema exibe os dados do motorista. 6) Funcionário solicita exclusão do motorista. 7 Sistema efetua exclusão da base de dados.
Por último é apresentada a parte mais importante do sistema. A emissão de um roteiro
constitui em despachar um caminhão. Neste caminhão podem viajar várias notas fiscais / entregas,
de vários clientes, ou somente uma nota fiscal / entrega, de um cliente. Tudo depende do peso das
mercadorias, e do peso máximo que o caminhão suporta (tara). A Tabela 21 descreve o cenário.
Tabela 21. Cenário Emissão de Roteiro
Emite Roteiro {Principal} 1) Funcionário solicita a emissão de roteiro. 2) Sistema exibe tela para emissão de roteiro. 3) Funcionário informa o caminhão que efetuará o transporte 4) Funcionário informa o motorista que efetuará o transporte. 5) Funcionário informa localidade de viagem. 6) Sistema analisa a soma dos pesos das mercadorias que estão à espera de roteiro.
51
7) Se a soma ultrapassa a tara do caminhão, sistema analisa notas fiscais com prioridade. 8) Sistema salva as informações do roteiro e exibe para visualização ou impressão.
3.4.2. Diagrama de Classes
O Diagrama de Classes, implementado na ferramenta Enterprise Architect, vem contribuir
com o trabalho, pois trata a visão lógica do sistema. São apresentadas, conforme a Figura 16, as
operações (métodos) e/ou variáveis (atributos) de cada classe.
cd Modelo Lógico
Pessoa
- nome: String
- endereco: String
- telefone: String
Cliente
- cnpj: LongInt
- email: String
- ie: LongInt
+ cadastraCliente() : void
+ excluiCliente() : void
+ visualizaCliente(Char) : void
+ alteraCliente() : void
Motorista
- cpf: LongInt
- cnh: LongInt
- categoria: String
- vencimentocnh: Data
+ cadastraMotorista() : void
+ excluiMotorista() : void
+ visualizaMotorista(Char) : void
+ alteraMotorista() : void
Roteiro
- data: Data
+ emiteRoteiro() : void
+ visualizaRoteiro() : void
+ excluiRoteiro() : void
Entrega
- numero: Integer
- data: Data
- peso: Integer
- quantidade: Integer
- volume: Integer
+ cadastraEntrega() : void
+ excluiEntrega() : void
+ visual izaEntrega(Integer) : void
+ alteraEntrega() : void
Caminhao
- placa: String
- chassis: String
- cor: String
- marca: String
- volume: Integer
- ano: Integer
+ cadastraCaminhao() : void
+ excluiCaminhao() : void
+ visualizaCaminhao(Char) : void
+ alteraCaminhao() : void
TipoCaminhao
- codigo: Integer
- descricao: String
- tara: Integer
Cidade
- nome: String
- uf: String
+ cadastraCidade() : void
+ excluiCidade() : void
+ visualizaCidade() : void
+ alteraCidade() : void
1
0..*
1
0..*
1..*
1..*
1
0..*0..1
1..*
1
0..*
0..*
1
Figura 16. Diagrama de Classes
A Classe Caminhão, conforme o diagrama de casos de uso, trata de operações de exclusão,
cadastro, alteração e visualização de veículos. As informações que são armazenadas através de
52
variáveis como placa, chassis, cor e marca (fabricante do caminhão) são do tipo string (texto). As
variáveis volume (capacidade em metros cúbicos) e ano (ano de fabricação do veículo) são do tipo
integer (inteiro).
A Classe, TipoCaminhao, possui uma descrição do tipo de caminhão. As variáveis são
código, descrição (tipo do veículo) e tara. A variável tara é do tipo integer visto que traz a
quantidade de peso em quilogramas suportado pelo caminhão. Não possui operações pois, os tipos
já estão pré-definidos no banco de dados.
A Classe Cliente assim como na classe caminhão, deve conter operações de exclusão,
cadastro, alteração e visualização de clientes. Os atributos pertencentes a esta classe são: cnpj
(cadastro nacional de pessoa jurídica), email e ie (inscriçaõ estadual).
A Classe Motorista assim como outras classes que fazem a manutenção das informações tem
operações de inclusão, exclusão, alteração e visualização de motoristas. As variáveis são publicas e
do tipo string ou longint. São elas: cpf (cadastro de pessoa física), cnh (cadastro nacional de
habilitação), vencimentocnh (data de vencimento da cnh) e categoria. A categoria é a permissão que
o motorista tem para dirigir determinado veículo, por exemplo: A categoria ‘C’ é a permissão para
dirigir somente veículos de truck a automóveis. Se o motorista pretende dirigir carreta seria
necessária a categoria ‘E’.
A Classe Pessoa generaliza as classes cliente e motorista. Por esse motivo não possui
operações. As variáveis são: nome, endereço, telefone. A cidade é obtida pela associação com a
Classe Cidade.
Na Classe Cidade, também há operações de cadastro, exclusão, alteração e visualização dos
dados. Os únicos dados pertencentes a esta classe são dois atributos públicos e do tipo string: nome
e uf (Unidade Federal). Esta Classe, não esta ligada a matriz de distâncias, portanto, pode-se efetuar
operações, porém, esta nova cidade não será roteirizada, uma das desvantagens do software.
A Classe Entrega é referente ao cadastro das entregas para posterior emissão do roteiro. As
variáveis são todas do tipo integer com exceção da data que é do tipo data. Além da data é
implementadas características de peso e volume da carga, quantidade de caixas e o número da nota
fiscal. As operações existentes nesta classe são: exclusão, alteração, inclusão (cadastro) e
visualização de entregas.
53
A Classe Roteiro possui a função emite roteiro que relaciona as informações do caminhão,
motorista e entregas. A única variável é a data que é obtida automaticamente pelo sistema.
3.4.3. Diagrama Entidade-Relacionamento do Banco de Dados
A modelagem Entidade-Relacionamento do Banco de Dados, também foi elaborada na
ferramenta EA (Entreprise Architect). A Figura 17, apresenta o diagrama com as tabelas e os
campos no Banco de Dados.
cd E-R Banco
tbl_caminhao
*PK «column» codigo:
* «column» placa:
* «column» chassis:
* «column» tara:
«column» cor:
«column» marca:
«column» ano:
* «column» tipo:
+ «PK» PK_tbl_caminhao()
tbl_caminhao_tipo
*PK «column» codigo:
* «column» descricao:
+ «PK» PK_tbl_caminhao_tipo()
tbl_cidade
*PK «column» codigo:
* «column» nome:
«column» estado:
+ «PK» PK_tbl_cidade()
tbl_cliente
*PK «column» codigo:
* «column» nome:
* «column» endereco:
«column» telefone_area:
* «column» telefone:
* «column» cidade:
* «column» cnpj_cpf:
«column» email :
«column» inscricao:
+ «PK» PK_tbl_cl iente()
tbl_distancia
*PK «column» origem:
*PK «column» destino:
* «column» distancia:
+ «PK» PK_tbl_distancia(, )
tbl_entrega
*PK «column» codigo:
* «column» numero_nota:
* «column» cnpj_remetente:
* «column» cnpj_destinatario:
* «column» peso:
* «column» qtde_volume:
* «column» volume_m3_carga:
* «column» data:
* «column» ativo:
+ «PK» PK_tbl_entrega()
tbl_estado
*PK «column» codigo:
* «column» sigla:
* «column» nome:
+ «PK» PK_tbl_estado()
tbl_motorista
*PK «column» codigo:
* «column» nome:
* «column» endereco:
«column» telefone_area:
* «column» telefone:
* «column» cidade:
* «column» cpf:
* «column» cnh:
«column» cnh_vencimento:
* «column» categoria:
+ «PK» PK_tbl_motorista()
tbl_roteiro
*PK «column» codigo:
* «column» cidade:
* «column» caminhao:
* «column» motorista:
* «column» data:
«column» cavalo:
+ «PK» PK_tbl_roteiro()
tbl_roteiro_entrega
*PK «column» roteiro:
*PK «column» entrega:
* «column» ordem:
+ «PK» PK_tbl_roteiro_entrega(, )
tbl_usuario
*PK «column» codigo:
* «column» login:
* «column» senha:
+ «PK» PK_tbl_usuario()
+ «unique» UQ_login()
0..*1..*
0..*1
1
1
1
0..*
1
0..*
0..*
*
1
0..*
0..*
1
*
*
10..*
10..*
1
0..*
Figura 17. Diagrama do Banco de Dados
3.5. MATRIZ DE DISTÂNCIAS
O primeiro passo para a crição da Matriz de Distâncias (Anexo), foi a pesquisa de cidades,
onde a empresa de transporte ou operador logístico que utilizará o sistema, teria suas filiais. Com
54
base em três empresas de transporte de cargas e encomendas que tem grande expressão no cenário
da região sul foram definidas quarenta e oito cidades. Dezoito cidades de Santa Catarina, dezenove
cidades do Rio Grande do Sul e onze cidades do Estado do Paraná. As empresas de transporte
pesquisadas foram: Expresso Joaçaba Ltda, Expresso Mercúrio Ltda e Transportes Plimor Ltda. A
pesquisas foi realizada através de folders e na página web das empresas.
Após definida as cidades, a matriz teve sua pesquisa realizada no Guia Quatro Rodas do ano
de 2005 e na web, na Associação Brasileira de Concessionárias de Rodovias (2006). Com essa
matriz, foi possível a criação de um roteiro de entregas buscando através desta, as cidades mais
próximas que o caminhão percorreria até um destino final.
A matriz teve suas dimensões determinadas em 49 linhas por 49 colunas (49x49) e nela
consta um cruzamento de 48 cidades da região sul, cidades onde estão localizadas as filiais. No
cruzamento de todas as cidades com todas as cidades é informado a distância em quilômetros.
As cidades onde estão os pontos de entregas de mercadorias são: Chapecó, Xanxerê,
Joaçaba, Caçador, Concórdia, Mafra, Joinville, Jaraguá do Sul, Blumenau, Itajaí, Lages, Rio do Sul,
Florianópolis, Criciúma, São Miguel do Oeste, São Bento do Sul, Brusque e Tubarão no Estado de
Santa Catarina. Frederico Westphalen, Erechim, Santa Rosa, Passo Fundo, Bento Gonçalves,
Caxias do Sul, Ijuí, Lajeado, Porto Alegre, Santa Maria, Santa Cruz do Sul, Camaquã, Uruguaiana,
Alegrete, Santana do Livramento, Bagé, Pelotas, São Borja e Santiago no Rio Grande do Sul.
Curitiba, Ponta Grossa, Cianorte, Londrina, Guarapuava, Maringá, Umuarama, Cascavel, Foz do
Iguaçú, Francisco Beltrão e Pato Branco no Estado do Paraná.
3.6. IMPLEMENTAÇÃO E FUNCIONAMENTO
As primeiras etapas desenvolvidas foram os cadastros de clientes, motoristas, entregas,
caminhões e cidades. Antes destas etapas foi realizada apenas uma tabela de usuários, onde foi
cadastrado um único usuário somente direto no banco de dados. Não existe cadastro de usuários.
Além disso, foi realizado o cadastro da tabela de distâncias no banco de dados.
As primeiras telas a serem desenvolvidas foram a tela de login (inicial) e a tela principal do
sistema, que é exibida quando o usuário informa o login e a senha corretamente. A Figura 18,
apresenta a tela inicial do sistema.
55
Figura 18. Tela Inicial
A tela principal conta com um menu com todas as opções do sistema do lado esquerdo. Do
lado direito é exibido o conteúdo, de acordo com cada opção do menu escolhida.
As opções de Arquivo são: Caminhões, Clientes, Motoristas, Cidades e Entregas.
Nas opções de Arquivo, a cada escolha é listado os dados já inseridos no banco de dados.
Pode-se realizar funções de novo cadastro, exclusão, visualização e edição os dados. Também há a
opção de Roteiros e a opção Sair. A opção de Roteiros monta o roteiro inicial e faz melhorias com o
método k-opt.
A Figura 19, mostra a tela principal do sistema após confirmação dos dados corretos de
login e senha.
56
Figura 19. Tela Principal
Os cadastros de clientes, caminhões, motoristas, cidades e entregas seguiram um esquema
padrão, onde os dados cadastrados são exibidos em forma de uma lista simples. Para cada registro
existe uma opção para visualizar o cadastro. Sempre na parte superior da lista existe um link para
novo cadastro.
A Figura 20, mostra exatamente o esquema de apresentação de dados em forma de lista
citados anteriormente como as opções de manutenção do banco de dados.
57
Figura 20. Tela com conteúdo de cada opção do menu
Caso o usuário escolha visualizar um cadastro, os dados aparecem bloqueados para
alteração. Há opções de edição, exclusão dos dados. O botão ‘cancelar’ volta para a tela de cadastro.
A Figura 21, representa a tela após acionar o botão ‘visualizar’.
Figura 21. Tela para edição e exclusão dos dados
58
No cadastro de Entrega, foi necessário realizar a validação do CNPJ do remetente e do
destinatário, com o intuito de não permitir que um CNPJ fosse cadastrado, sem antes existir o
cadastro desse cliente no sistema. Essa verificação é importate ao banco de dados, pois caso a
empresa utilize o sistema futuramente para relatórios comerciais por região ou cliente, o cadastro
completo deste deve estar armazenado.
Caso o CNPJ informado ainda não possua cadastro, é aberto uma tela onde o usuário deverá
realizar o cadastro do cliente. Para fazer essa validação foi utilizado um método de programação
chamado AJAX. O método faz com que não precise recarregar a página web sempre que for
necessário uma consulta no banco de dados. Dessa forma, consegue-se enviar os dados para
verificar o CNPJ e retornar a resposta se está cadastrado ou não (MINETTO, 2006).
Durante o desenvolvimento dos cadastros também foi feita uma pequena validação de dados,
em JavaScript, para evitar que o usuário digite caracteres inválidos em campos como CNPJ, Tara,
CNH onde são aceitos somente caracteres numéricos.
Na Figura 22, é apresentado a tela tanto de cadastro de um novo dado ou para alterar uma
informação já existente.
Figura 22. Tela das opções para novo cadastro ou alterar os dados
59
Para a emissão dos roteiros, também foi usada uma lista simples para mostrar os já emitidos.
Cada roteiro gerado poderá ser visualizado. Também existe um link, novo roteiro, onde o usuário
irá emití-los.
Ao emitir o roteiro, os dados de entregas automaticamente não aparecem mais na lista de
entregas pendentes dentro do menu Entregas. A partir do momento que se exclui um roteiro gerado,
as entregas voltam para o relatório de entregas, onde não estão roteirizadas, para posteriormente
participarem de um novo roteiro.
Na Figura 23, é apresentado a tela dos roteiros gerados com data extraída do sistema
operacional em forma de lista. Também é apresentado a placa e o destino do caminhão.
Figura 23. Tela com conteúdo de Roteiros do menu Opções
Para emitir um roteiro, o usuário deve informar a localidade, ou seja, a cidade de destino do
caminhão. Também é necessário informar a placa do caminhão que irá transportar a carga e o
motorista.
60
A Figura 24, apresenta a tela de escolha da localidade destino do caminhão, caminhão e
cavalo mecânico, caso o caminhão seja uma carreta e o motorista. Confirmando estes dados o
roteiro é gerado caso existam notas para a cidade destino.
Figura 24. Tela para emissão de roteiro
No caso do caminhão ser uma carreta, ou seja, veículo com capacidade de carga acima de
vinte toneladas, abre a opção para a escolha da placa do cavalo mecânico. A carreta é a parte da
carroceria onde são embarcadas as mercadorias. O cavalo mecânico é a parte que engata no eixo da
carroceria e tem o motor com força o suficente para puxar quarenta toneladas até o destino final.
Para a emissão dos roteiros, foi necessário implementar algumas rotinas auxiliares para
consultar os dados necessários no banco de dados. Os algoritmos abaixo estão escritos na
linguagem PHP, utilizada para a implementação do sistema. As consultas no banco de dados são
feitas com a linguagem SQL, a linguagem padrão para consultas.
Quando o usuário seleciona emitir um roteiro para uma determinada cidade, o primeiro
passo do algoritmo de roteirização é buscar os dados do caminhão escolhido, conforme Figura 25.
61
function BuscaCaminhao($codigo) { $query = Consulta('select codigo, tara, volume, tipo ' . ' from tbl_caminhao where codigo = ' . $codigo); return mysql_fetch_array($query); }
Figura 25. Primeira Rotina – Busca Caminhão
O caminhão selecionado pelo usuário é posteriormente avaliado, com seus dados adicionais,
como a tara e volume do caminhão.
O segundo passo do algoritmo, Figura 25, realiza a busca da distância entre duas cidades
(origem e destino). Ao emitir um roteiro para determinada cidade, quando sobra espaço no
caminhão, é necessário encher o caminhão com entregas de cidades próximas, para aproveitar o
espaço livre do caminhão. Para avaliar as cidades mais próximas, utiliza-se a função descrita
abaixo.
function BuscaDistancia($origem, $destino) { $query = Consulta('select distancia from tbl_distancia where origem = ' . $origem . ' and destino = ' . $destino); $registro = mysql_fetch_array($query); return $registro['distancia']; }
Figura 26. Segunda Rotina – Busca Distância
A terceira rotina, Figura 27, seleciona as entregas de clientes que estão disponíveis para uma
determinada cidade. Ao emitir o roteiro para uma cidade específica, por exemplo, Londrina, o
algoritmo busca no banco de dados as entregas que estão disponíveis para aquela cidade. A busca é
feita através da junção de várias tabelas no banco de dados, para poder trazer todos os dados
necessários de clientes, entregas e cidades. Ao final, o algoritmo monta um vetor com as entregas
que foram buscadas.
function BuscaEntregasPorCidade($codigo_cidade) { // Busca no banco de dados as entregas disponíveis para a cidade $query = Consulta('select e.codigo, e.numero_nota, e.data, e.peso, ' ' e.volume_m3_carga, origem.codigo as cidade, origem.nome ' . ' from tbl_entrega e ' . ' inner join tbl_cliente dest on (dest.cnpj_cpf = e.cnpj_destinatario) ' . ' inner join (tbl_cliente rem ' . ' inner join tbl_cidade origem on (origem.codigo=rem.cidade)) ' . ' on (rem.cnpj_cpf = e.cnpj_remetente) ' . ' where (dest.cidade = ' . $codigo_cidade . ') and (ativo=1) ' . ' order by e.data asc'); $entregas = array(); // Monta um vetor com as entregas selecionadas while ($registro = mysql_fetch_array($query)) { $entrega = array(); $entrega['distancia'] =
62
BuscaDistancia($registro['cidade'], $codigo_cidade); $entrega['codigo'] = $registro['codigo']; $entrega['numero_nota'] = $registro['numero_nota']; $entrega['peso'] = $registro['peso']; $entrega['volume'] = $registro['volume_m3_carga']; $entrega['data'] = $registro['data']; $entrega['origem_codigo'] = $registro['cidade']; $entrega['origem_nome'] = $registro['nome']; $entrega['destino_codigo'] = $codigo_cidade; $entrega['destino_nome'] = ''; array_Push($entregas, $entrega); } // Retorna o vetor com as entregas selecionadas return $entregas; }
Figura 27. Terceira Rotina – Busca Entregas por Cidade
As entregas para esta determinada cidade armazenadas no vetor têm seus pesos e volumes
somados. Caso essa soma ultrapasse os limites do caminhão tanto em peso ou volume, o algoritmo
irá dar prioridade para as entregas mais antigas conforme data informada no registro de uma nova
entrega.
Caso as entregas não sejam suficientes para lotar o caminhão, ou seja, a soma de peso e
volume das entregas selecionadas são inferiores aos limites do caminhão, o algoritimo busca as
entregas mais próximas à cidade de origem.
Portanto o algoritmo, responsável pela busca de mais entregas caso o caminhão não esteja
com sua capacidade máxima esgotada, recebe três parâmetros de busca. O primeiro é o código da
cidade de destino do roteiro. O segundo e terceiro parâmetros correspondem ao peso e volume que
ainda cabem no caminhão, respectivamente.
As entregas são selecionadas no banco de dados de acordo com o peso e volume, e não com
relação a cidade de destino, ou seja, são selecionadas somente as entregas que cabem dentro do peso
e volume restantes no caminhão. Após as entregas serem selecionadas, é montado um vetor, a
exemplo do algoritmo anterior.
Como o algoritmo traz todas as entregas que podem caber no caminhão, o último passo do
algoritmo é filtrar as entregas, somando os pesos e volumes de cada uma, para avaliar quais cabem
no espaço restante do caminhão conforma a Figura 28 apresenta:
function BuscaEntregasPorPeso($codigo_cidade, $peso, $volume) { // Busca as entregas que possuem peso e volume abaixo do procurado $query = Consulta('select e.codigo, e.numero_nota, e.peso, ' . ' e.volume_m3_carga, origem.codigo as origem_cod, ' . ' origem.nome as origem_nome, destino.codigo as destino_cod, ' . ' destino.nome as destino_nome ' . ' from tbl_entrega e ' . ' inner join (tbl_cliente dest ' . ' inner join tbl_cidade destino on (destino.codigo=dest.cidade)) ' .
63
' on (dest.cnpj_cpf = e.cnpj_destinatario) ' . ' inner join (tbl_cliente rem ' . ' inner join tbl_cidade origem on (origem.codigo=rem.cidade)) ' . ' on (rem.cnpj_cpf = e.cnpj_remetente) ' . ' where (e.peso < ' . $peso .') and (volume_m3_carga < ' . $volume . ')' . ' and (dest.cidade != ' . $codigo_cidade . ') and (e.ativo=1)'); $entregas = array(); // Monta uma matriz com os dados das entregas while ($registro = mysql_fetch_array($query)) { $entrega = array(); $entrega['distancia'] = BuscaDistancia($codigo_cidade, $registro['destino_cod']); $entrega['codigo'] = $registro['codigo']; $entrega['numero_nota'] = $registro['numero_nota']; $entrega['peso'] = $registro['peso']; $entrega['volume'] = $registro['volume_m3_carga']; $entrega['data'] = 0; $entrega['origem_codigo'] = $registro['origem_cod']; $entrega['origem_nome'] = $registro['origem_nome']; $entrega['destino_codigo'] = $registro['destino_cod']; $entrega['destino_nome'] = $registro['destino_nome']; array_push($entregas, $entrega); } // Ordena o vetor, // deixando primeiro as entregas mais próximas da cidade de destino sort($entregas); $soma_peso = 0; $soma_volume = 0; $selecionadas = array(); // Filtra as entregas retornadas, selecionando apenas aquelas que cabem no // peso e volume especificado for ($i = 0; $i < count($entregas); $i++) // Verifica se cabe no peso e volume if (($soma_peso + $entregas[$i]['peso'] <= $peso) && ($soma_volume + $entregas[$i]['volume'] <= $volume)) { $soma_peso += $entregas[$i]['peso']; $soma_volume += $entregas[$i]['volume']; array_push($selecionadas, $entregas[$i]); } // Retorna o vetor com as entregas selecionadas return $selecionadas; }
Figura 28. Quarta Rotina – Busca Entregas por Peso
O quinto algoritmo, conforme Figura 29, faz apenas a ordenação das entregas selecionadas,
colocando nas primeiras posições as entregas mais próximas da cidade de origem, e nas últimas
posições coloca as entregas mais próximas da cidade de destino do roteiro.
function OrdenarEntregas($entregas) { for ($i =0; $i < count($entregas); $i++) $entregas[$i]['distancia'] = BuscaDistancia($entregas[$i]['origem_codigo'], $entregas[$i]['destino_codigo']); sort($entregas); return $entregas; }
Figura 29. Quinta Rotina – Ordena Entregas
O algoritmo para emissão do roteiro utiliza todas as rotinas descritas acima, e será
explicado a seguir. O primeiro trecho do código, conforme Figura 30, recebe os dados da tela de
64
cadastro, onde o usuário seleciona a cidade de destino do roteiro, qual o caminhão e qual o
motorista.
// Recebe os dados do formulário da tela de emissão de roteiro $localidade = $_POST['rot_localidade']; $motorista = $_POST['rot_motorista']; $caminhao = BuscaCaminhao($_POST['rot_caminhao']); // Se o caminhão for Carreta, então tem um cavalo mecânico if ($caminhao['tipo'] == 3) $cavalo = $_POST['rot_cavalo']; else $cavalo = 0;
Figura 30. Primeiro passo do Algoritmo
Após receber os dados, o algoritmo busca as entregas que estão disponíveis para a cidade de
destino, conforme Figura 31.
// Busca as entregas que estão à espera para a localidade de destino $entregas = BuscaEntregasPorCidade($localidade);
Figura 31. Segundo passo do Algoritmo
Após buscar as entregas, o algoritmo soma os pesos e volumes, para verificar se as entregas
são suficientes para encher o caminhão. Caso ainda sobre espaço no caminhão, é feita a busca das
entregas de cidades próximas, segundo a tabela de distâncias. A Figura 32, apresenta o código
responsável pelas ações descritas acima.
$soma_pesos = 0; $soma_volumes = 0; // Contabiliza a soma dos pesos e volumes das entregas para a localidad foreach ($entregas as $entrega) { $soma_pesos += $entrega['peso']; $soma_volumes += $entrega['volume']; } if (($soma_pesos > $caminhao['tara']) || ($soma_volumes > $caminhao['volume'])) { // A soma dos pesos ou dos volumes ultrapassa a tara/volume do caminhão // então filtra as entregas por data, dando prioridade para as mais antigas // a busca no banco de dados já traz as entregas ordenadas pela data // mais antiga primeiro $entregas_selecionadas = array(); $soma_peso = 0; $soma_volume = 0; // Filtra as entregas retornadas, selecionando apenas aquelas que cabem no // peso especificado for ($i = 0; $i < count($entregas); $i++) // Verifica se cabe no peso e volume if (($soma_peso + $entregas[$i]['peso'] <= $caminhao['tara']) && ($soma_volume + $entregas[$i]['volume'] <= $caminhao['volume'])) { $soma_peso += $entregas[$i]['peso']; $soma_volume += $entregas[$i]['volume']; array_push($entregas_selecionadas, $entregas[$i]); } } else { // Ainda há espaço no caminhão... // então busca outras entregas para caber no caminhão $entregas_outras = BuscaEntregasPorPeso($localidade, $caminhao['tara'] - $soma_pesos, $caminhao['volume'] - $soma_volumes);
65
$entregas_selecionadas = array_merge($entregas, $entregas_outras); }
Figura 32. Terceiro passo do Algoritmo
As entregas selecionadas são gerenciadas dentro de um vetor. Após buscar as entregas para a
cidade de destino, a função ordena as entregas em relação à cidade de origem. Após ordenar as
entregas, o algoritmo efetua a inserção dos registros no banco de dados conforme mostra a Figura
33.
if (count($entregas_selecionadas) > 0) { // Ordena as entregas pela distância menor em relação à cidade de origem $entregas_selecionadas = OrdenarEntregas($entregas_selecionadas); // Efetua a inserção do registro do roteiro no banco de dados Consulta('insert into tbl_roteiro ' . ' (cidade, caminhao, motorista, data, cavalo) values (' . $localidade . ',' . $caminhao['codigo'] . ',' . $motorista . ', CURRENT_DATE, ' . $cavalo . ')'); // Busca o código do último roteiro inserido $registro = mysql_fetch_array( Consulta('select max(codigo) from tbl_roteiro')); $roteiro = $registro[0]; // Efetua a inserção do vínculo entre roteiro e entregas no banco de dados foreach ($entregas_selecionadas as $entrega) { Consulta('insert into tbl_roteiro_entrega (roteiro, entrega, ordem) ' . ' values(' . $roteiro . ',' . $entrega['codigo'] . ', ' . $entrega['distancia'] . ')'); Consulta('update tbl_entrega set ativo=0 where (codigo = ' . $entrega['codigo'] . ')'); } header('location: roteiros_visualizar.php?id=' . $roteiro); } else echo('Não foram encontradas entregas para a localidade, ou proximidades, ' . ' que caibam no caminhão selecionado!');
Figura 33. Quarto passo do Algoritmo
A Figura 34, apresenta a tela com o roteiro inicial sem melhorias. É apresentado as notas
fiscais que serão embarcadas bem como os dados do caminhão.
66
Figura 34. Tela para visualização do roteiro gerado
Após gerar o roteiro, é possível efetuar o cálculo k-opt no mesmo, afim de verificar se existe
melhoras, ou seja, se o trajeto a ser percorrido pelo caminhão pode ser reduzido.
Na tela de visualização do roteiro, existe um botão para calcular pelo método k-opt. Se este
botão for acionado o sistema busca o roteiro em questão no banco de dados. Os dados iniciais de
distâncias percorridas e quantidades de cidades que o caminhão passa são armazenadas através do
trecho de código conforme Figura 35:
// Atribui o trajeto e a kilometragem original como sendo os melhores $menor_trajeto = $trajeto_original; $menor_km = $km_original; $trajeto_calculado = $trajeto_original; // qtde possui número de cidades do trajeto $qtde = count($trajeto_original);
Figura 35. Primeiro passo k-opt
Obtendo as informações, o sistema faz todas as trocas de ordem entre as cidades e calcula a
quilometragem final de cada troca. Caso a distância percorrida for menor que a distância original
obtida o sistema toma como melhor roteiro e o salva no banco de dados. Este processo é realizado
através do código apresentado na Figura 36.
67
// Faz a troca das cidades para achar o menor caminho do { $i = 0; // Inverte todas as posições entre as cidades while ($i < ($qtde - 1)){ // Inverte a posição $aux = $trajeto_calculado[$i]; $trajeto_calculado[$i] = $trajeto_calculado[$i + 1]; $trajeto_calculado[$i + 1] = $aux; $i++; // Calcula a distãncia entre as cidades após cada inversão $km_calculado = Calcula_km($trajeto_calculado); // Se a kilometragem calculada for menor que a kilometragem original, assume a kilometragem calculada como o menor trajeto if ( $km_calculado < $menor_km){ $menor_trajeto = $trajeto_calculado;
$menor_km = $km_calculado; } } // A função executa enquanto o trajeto calculado seja diferente ao trajeto original } while ($trajeto_calculado != $trajeto_original);
Figura 36. Segundo passo k-opt
Após efetuado o cálculo, é mostrado o roteiro resultante, sendo informado também a
quilometragem do roteiro original, a quilometragem do roteiro após o cálculo k-opt e a economia
resultante.
A Figura 37, apresenta a tela após o calculo de melhoria k-opt informando o roteiro final e
se após este cálculo houve ou não alguma melhora
68
Figura 37. Tela do roteiro gerado com melhoria
3.7. INSERÇÃO DE DADOS E SIMULAÇÃO DO SOFTWARE
O banco de dados foi inicialmente carregado com informações reais extraídas do sistema da
empresa Expresso Joacaba Ltda em Itajai – SC. A empresa se prontificou a informar e auxiliar nas
informações, pois a Expresso Joacaba não dispõe de um sistema parecido com o proposto para
otimização de recursos, uso racional dos bens e agilidade na carga e descarga dos caminhões. As
informações foram redigitadas para o novo banco de dados.
A única informação alterada para os dias atuais foi a data das entregas, pois as mesmas
foram extraídas do período de janeiro do ano de dois mil e quatro até dezembro do ano de dois mil e
cinco.
As simulações foram realizadas semanalmente conforme iria progredindo a implementação
do código, ou seja, a cada implementação de uma opção do arquivo, como motoristas, clientes,
entregas, caminhões e cidades, foram sendo realizadas simulações de cadastramento, exclusão e
alteração dos dados.
69
Ao final, o software foi submetido a uma simulação total na empresa Expresso Joaçaba Ltda
pelo usuário Kleber Erivelto Fulgêncio. Outro usuário, Rayon Loch, fez algumas simulações e
comentou sobre a facilidade de uso para quem trabalha na área de transportes. As simulações foram
realizadas com um banco de dados com aproximadamente setenta entregas cadastradas.
O teste completo com sua documentação não foi executado devido a ferramenta ter ficado
pronta próxima a data de entrega do TCC.
Após simulações efetuadas, os roteiros gerados foram submetidos a uma análise minuciosa
para verificar sua exatidão. Conforme Figura 38, Figura 39 e Figura 40 os itinerários de entregas
criados tiveram uma saída ideal para uso em uma transportadora ou operador logístico, pois, se
fosse mudado a ordem das entregas, a distância percorrida pelo caminhão seria maior do que a
obtida através do software. Portanto, o método de melhoria k-opt também não conseguirá melhorar
o roteiro.
A Figura 38, apresenta um roteiro gerado para a cidade destino de Chapecó no Estado de
Santa Catarina. A distância total percorrida foi 588 quilômetros, pois, conforme Tabela de
Distâncias (Anexo), a cidade de Itajaí (ponto inicial) à Caçador é 326 quilômetros, a cidade de
Caçador até a segunda cidade do roteiro Joaçaba é 93 quilômetros, Joaçaba até Xanxerê é 125
quilômetros e por último Xanxerê até Chapecó 44 quilômetros, totalizando 588 quilômetros.
Caso o roteiro fosse modificado, conforme exemplos a seguir, a distância percorrida seria
maior que a distância do roteiro criado pelo Software.
• Mudança 1: Itajaí, Caçador, Xanxerê, Joaçaba, Chapecó: 784 quilômetros;
• Mudança 2: Itajaí, Joaçaba, Caçador, Xanxerê, Chapecó: 690 quilômetros;
• Mudança 3: Itajaí, Joaçaba, Xanxerê, Caçador, Chapecó: 923 quilômetros;
• Mudança 4: Itajaí, Xanxerê, Caçador, Joaçaba, Chapecó: 916 quilômetros; e
• Mudança 5: Itajaí, Xanxerê, Joaçaba, Caçador, Chapecó: 953 quilômetros;
70
Figura 38. Roteiro gerado para Chapecó
A Figura 39, demonstra um roteiro para a cidade de Cascavel no Estado do Paraná. O
itinerário criado tem distância total de 869 quilômetros. Modificando o roteiro teremos a seguinte
quilometragem:
• Mudança 1: Itajaí, Curitiba, Francisco Beltrão, Pato Branco, Cascavel: 934
quilômetros;
• Mudança 2: Itajaí, Francisco Beltrão, Curitiba, Pato Branco, Cascavel: 1671
quilômetros;
• Mudança 3: Itajaí, Francisco Beltrão, Pato Branco, Curitiba, Cascavel: 1542
quilômetros;
• Mudança 4: Itajaí, Pato Branco, Curitiba, Francisco Beltrão, Cascavel: 1583
quilômetros; e
• Mudança 5: Itajaí, Pato Branco, Francisco Beltrão, Curitiba, Cascavel: 1519
quilômetros;
71
Figura 39. Roteiro gerado para Cascavel
Foi realizado também, uma simulação para a cidade de Porto Alegre, cidade pertencente ao
Estado do Rio Grande do Sul. A Figura 40, mostra o roteiro gerado com distância total de 686
quilômetros. Modificando o roteiro tem-se as seguintes quilometragens finais:
• Mudança 1: Itajaí, Blumenau, Florianópolis, Criciúma, Tubarão, Porto Alegre: 797
quilômetros;
• Mudança 2: Itajaí, Blumenau, Tubarão, Criciúma, Florianópolis, Porto Alegre: 1026
quilômetros;
• Mudança 3: Itajaí, Blumenau, Tubarão, Florianópolis, Criciúma, Porto Alegre: 957
quilômetros;
• Mudança 4: Itajaí, Blumenau, Criciúma, Tubarão, Florianópolis, Porto Alegre: 1023
quilômetros;
• Mudança 5: Itajaí, Blumenau, Criciúma, Florianópolis, Tubarão, Porto Alegre: 1065
quilômetros;
72
• Mudança 6: Itajaí, Florianópolis, Blumenau, Tubarão, Criciúma, Porto Alegre: 857
quilômetros;
• Mudança 7: Itajaí, Florianópolis, Blumenau, Criciúma, Tubarão, Porto Alegre: 965
quilômetros;
• Mudança 8: Itajaí, Florianópolis, Tubarão, Blumenau, Criciúma, Porto Alegre: 1125
quilômetros;
• Mudança 9: Itajaí, Florianópolis, Tubarão, Criciúma, Blumenau, Porto Alegre: 1091
quilômetros;
• Mudança 10: Itajaí, Florianópolis, Criciúma, Tubarão, Blumenau, Porto Alegre:
1094 quilômetros;
• Mudança 11: Itajaí, Florianópolis, Criciúma, Blumenau, Tubarão, Porto Alegre:
1236 quilômetros;
• Mudança 12: Itajaí, Tubarão, Florianópolis, Blumenau, Criciúma, Porto Alegre:
1114 quilômetros;
• Mudança 13: Itajaí, Tubarão, Florianópolis, Criciúma, Blumenau, Porto Alegre:
1351 quilômetros;
• Mudança 14: Itajaí, Tubarão, Blumenau, Criciúma, Florianópolis, Porto Alegre:
1454 quilômetros;
• Mudança 15: Itajaí, Tubarão, Blumenau, Florianópolis, Criciúma, Porto Alegre:
1117 quilômetros;
• Mudança 16: Itajaí, Tubarão, Criciúma, Florianópolis, Blumenau, Porto Alegre:
1083 quilômetros;
• Mudança 17: Itajaí, Tubarão, Criciúma, Blumenau, Florianópolis, Porto Alegre:
1183 quilômetros;
73
• Mudança 18: Itajaí, Criciúma, Tubarão, Blumenau, Florianópolis, Porto Alegre:
1182 quilômetros;
• Mudança 19: Itajaí, Criciúma, Tubarão, Florianópolis, Blumenau, Porto Alegre:
1079 quilômetros;
• Mudança 20: Itajaí, Criciúma, Blumenau, Florianópolis, Tubarão, Porto Alegre:
1221 quilômetros;
• Mudança 21: Itajaí, Criciúma, Blumenau, Tubarão, Florianópolis, Porto Alegre:
1450 quilômetros;
• Mudança 22: Itajaí, Criciúma, Florianópolis, Blumenau, Tubarão, Porto Alegre:
1224 quilômetros;
• Mudança 23: Itajaí, Criciúma, Florianópolis, Tubarão, Blumenau, Porto Alegre:
1350 quilômetros;
Figura 40. Roteiro gerado para Porto Alegre
[FIM DE SEÇÃO. Não remova esta quebra de seção]
4. CONCLUSÕES
Este trabalho reuniu conceitos de logística, conceitos de heurística e sistemas
computacionais. O resultado foi uma ferramenta computacional para roteirizar as estregas de
mercadorias. A ferramenta elaborada baseou-se na Busca Heurística da área de Inteligência
Artificial.
A respeito de heurística, para se obter uma solução viável, existem várias propostas na
literatura. Porém, nenhuma pode garantir uma solução ótima. O método das economias e o método
k-opt utilizado neste trabalho, têm o intuito de aprimorar e otimizar o planejamento de transporte
com o auxílio da ferramenta criada denominada SISROTEN.
Os métodos utilizados tiveram que ser readequados para a prática. O método de economia de
Clarke e Wright, trabalha com a criação de roteiros para diversas cidades sem importar-se com o
destino que o motorista deseja ir e a disponibilidade de caminhão para determinado lugar. Já o
método k-opt realiza as trocas de entregas, com o objetivo da obtenção de alguma melhora, em
roteiros circulares. Porém, na prática muitas vezes a empresa não utiliza caminhão de sua frota
própria, sendo que são contratados freteiros, também chamados de terceiros, para realizar o
carregamento sem voltar para a filial de origem. Para resolver esta situação o usuário do sistema já
informa o destino do caminhão. Quanto ao método k-opt, ao invés de realizar trocas de entregas,
começando e terminando o roteiro no ponto de partida, a cidade origem, no caso Itajaí, e destino,
informada pelo usuário, são fixas, ou seja, não sofrem alteração no roteiro. Somente as entregas
intermediárias fazem as trocas.
Para simular o funcionamento do sistema, foi gerado um banco de dados e inseridos
arquivos e dados pertinentes ao software em um servidor americano gratuito. Nas simulações o
método k-opt muitas vezes não traz resultado positivo, visto que o roteiro gerado no método das
economias já esta muito próximo do ideal e não pode ser melhorado. Para roteiros com mais de
onze entregas, não foi possível utilizar o método k-opt devido às inúmeras trocas de posições entre
as entregas na tentativa de se chegar a um melhor roteiro, a pagina web expira gerando erro. Para o
uso real do sistema em um empresa com servidor próprio, poderão ser efetuadas melhorias de
quilometragem com o método k-opt com mais de onze entregas pois o tempo de espera poderá ser
maior que o utilizado para as simulações realizadas. Pôde-se observar que o software retorna um
75
roteiro muito próximo ao ideal, não mostrando como saída, itinerários com erros de alocação de
entregas.
Para o cálculo de distâncias entre as cidades foi utilizado uma Matriz de Distâncias (Anexo).
A partir desta, obtêm-se a quilometragem exata da origem até o destino sem cálculos de latitude e
longitude em tempo real. A não utilização de mapas ou bases cartográficas vetorizadas deve-se ao
conhecimento antecipado dos pontos de entregas das mercadorias, não implementando entregas na
malha viária municipal, somente de cidade para cidade dentro dos estados da região sul do Brasil.
Esta é a limitação da ferramenta. Caso seja necessário ampliar o número de cidades, deve-se
elaborar outra Matriz de Distâncias, com as novas quilometragens da cidade acrescentada.
O software em questão destina-se ao uso de empresas de transporte ou operadores logísticos
com grande movimentação de entregas.Caso contrário, numa base de dados pequena, o caminhão
terá sua capacidade totalizada, porém percorrerá os três estados da região sul, não trazendo
benefícios à empresa. No caso da empresa em que foi realizado as simulações, com movimento
superior a 90 coletas diárias, um sistema deste padrão seria de grande utilidade.
Na fase de implantação e simulações na empresa Expresso Joacaba Ltda, houve uma
pequena explicação da pretensão do software e um rápido treinamento identificando as
funcionalidades. Os usuários Kleber Erivelto Fulgêncio e Rayon Loch, comentaram sobre a
facilidade de uso da ferramenta, porém certa resistência a mudanças, já que os dados teriam de ser
recadastrados manualmente na nova ferramenta.
Para sugestões de trabalhos futuros pode-se citar a expansão do sistema com módulos
comerciais e módulos voltados ao controle de custos dos bens em questão. O módulo comercial
engloba desde o cálculo do frete referente as entregas cadastradas até o faturamento dos
conhecimentos de transporte. O módulo comercial é caracterizado por relatórios comparativos de
faturamento, manutenção de tabelas de fretes dados para empresas de marketing. O módulo voltado
ao controle de custo está relacionado ao Custo X Benefício de cada viagem, contabilizando desgaste
do caminhão, óleo diesel, motorista, diárias e pneu. Este módulo é caracterizado principalmente
pelo detalhamento minucioso dos gastos da empresa.
Um aprimoramento do sistema, poderia ser feito em relação à utilização de mapas para
geração do roteiro prevendo inclusive catástrofes naturais (queda de ponte, rodovias paradas em
manutenção) hoje não implementadas nas restrições. Outro aprimoramento poderia estar na
76
obtenção dos dados para cadastramento no banco de dados sem que estes sejam redigitados
manualmente, ou seja, importando as informações automaticamente.
O Problema de Roteirização de Veículos é uma generalização do Problema do Caixeiro
Viajante. Podem ser resolvidos por muitos métodos, pois são modelos tradicionais. Neste trabalho
foram utilizados o Método das Melhorias e o Método K-opt. Para sugestão de próximos trabalhos
pode-se utilizar a Teoria dos Grafos e o Algoritmo de Dijkstra para resolução do problema.
Para a realização deste projeto foram utilizados conceitos adquiridos durante o curso de
Ciência da Computação nas áreas de Engenharia de Software, Inteligência Artificial, Algoritmos e
Banco de dados. Como o software destina-se ao ramo de transportes foram incorporados alguns
conhecimentos adquiridos na prática e com o curso superior de Logística.
[FIM DE SEÇÃO. Não remova esta quebra de seção]
REFERÊNCIAS BIBLIOGRÁFICAS
ABCR. Associação Brasileira de Concessionárias de Rodovias. 2006. Disponível em: <www.abcr.org.br>. Acesso em: 06 março 2006.
ANDRADE, Carlos Eduardo; BATISTA, Flavio Lucio Nogueira; TOSO, Rodrigo Franco. Modelo de Otimização para Transporte de Cargas em Ambientes Reduzidos. 2004. Disponível em: <www.ic.unicamp.br/~ra038508/trabalhos/monografia.pdf>. Acesso em: 10 maio 2005.
CUNHA, Cláudio Barbieri da; BONASSER, Ulisses de Oliveira; ABRAHÃO, Fernando Teixeira Mendes. Experimentos Computacionais com Heurísticas de Melhorias para o Problema do Caixeiro Viajante. 2002. Disponível em: <www.ptr.poli.usp.br/ptr/docentes/cbcunha/files/2-opt_TSP_Anpet_2002_CBC.pdf>. Acesso em 02 maio 2005.
CUSTODIO, Ana Luisa da Graça Batista. Um Sistema de Gestão Logística Integrando Gestão de Inventário e Construção de Rotas. 2001. Disponível em: <ferrari.dmat.fct.unl..pt/personal/alcustodio/Tese.pdf>. Acesso 18 abril 2005.
GOLDBARG, Marco César; LUNA Henrique Pacca L. Otimização Combinatória e Programação Linear: modelos e algoritmos. Rio de Janeiro: Campus, 2000. ISBN 85-352-0541-1.
GUIAQUATRORODAS. Rodoviário 2005. São Paulo: Editora Abril, 2005.
MINETTO, Elton Luís. Ajax – Criando aplicações que aparentam estar sendo executadas localmente na máquina do usuário e não em um ambiente Web. Disponível em: <www.linhadecodigo.com.br/dicas.asp?id_dica=1253&sub=46>. Acesso em: 24 maio 2006.
NARCISO, Marcelo Gonçalves; LORENA, Luiz Antonio Nogueira. Novos Algoritmos para Resolução do Problema de Roteamento. 2003. Disponível em: <www.cnptia.embrapa.br/modules/tinycontent3/content/2003/comtec52.pdf>. Acesso 02 maio 2005.
NEVES, Tiago Araújo. Resolução do Problema de Roteamento de Veículos com Frota Heterogênea e Janelas de Tempo. 2004. Disponível em: <www.decom.ufop.br/prof/marcone/Orientacoes/PRVFHJTviaSimulatedAnnealing.pdf>. Acesso 24 abril 2005.
PELIZARO, Claudia. Avaliação de Desempenho do Algoritmo de um Programa Comercial para Roteirização de Veículos. 2000. Disponível em: <www.teses.usp.br/teses/disponiveis/18/18137/tde-09102001-143129/publico/Pelizaro.pdf>. Acesso em: 20 abril 2005.
PIMENTA, Daniel Jose. Algoritmo de Otimização para o Problema de Roteamento de Veículos no Transporte Conjunto de Cargas e de Passageiros. 2001. Disponível em: <www.cpdee.ufmg.br/~joao/TesesOrientadas/VAS2001_1.pdf>. Acesso em: 05 maio 2005
SILVA, Vinicius da. Logística e Transporte na Indústria Brasileira de Laticínios: Estudo de Casos. 2003. Disponível em <www.em.ufop.br/em/DEPRO/monografias/2003vinicius.pdf>. Acesso em: 29 maio 2005.
78
SIMAS, Etiene Pozzobom Lazzeris. Uma Solução para o Problema de Roteamento de Veículos através de Pesquisa Tabu. 2004. Disponível em <www.inf.unisinos.br/alunos/arquivos/Tc_EtieneSimas.pdf >. Acesso em: 02 junho 2005.
WEISZFLOG, Walter (Ed.). Michaelis: moderno dicionário da língua portuguesa. São Paulo: Melhoramentos, 1998. ISBN: 85-06-02759-4.
[FIM DE SEÇÃO. Não remova esta quebra de seção
ANEXOS
[FIM DE SEÇÃO. Não remova esta quebra de seção
No anexo foram colocados os códigos em PHP da ferramenta desenvolvida. A divisão foi
realizada seguindo a funcionalidade do sistema.
I. Matriz de Distâncias
II. Banco.txt
Arquivo para inicializar o Banco de Dados. Cria as tabelas e os campos inserindo a base de
dados inicial
-- -- Banco de Dados: `toigo_bd` -- -- -------------------------------------------------------- -- -- Estrutura da tabela `tbl_caminhao` -- CREATE TABLE `tbl_caminhao` ( `codigo` int(11) NOT NULL auto_increment, `placa` varchar(7) NOT NULL default '', `chassis` varchar(20) NOT NULL default '', `tara` int(11) NOT NULL default '0', `cor` varchar(20) default NULL, `marca` varchar(20) default NULL, `ano` varchar(4) default NULL, `volume` int(11) NOT NULL default '0', `tipo` int(11) NOT NULL default '0', PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; -- -- Estrutura da tabela `tbl_caminhao_tipo` -- CREATE TABLE `tbl_caminhao_tipo` ( `codigo` int(11) NOT NULL auto_increment, `descricao` varchar(20) NOT NULL default '', PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ; -- -- Estrutura da tabela `tbl_cidade` -- CREATE TABLE `tbl_cidade` ( `codigo` int(11) NOT NULL auto_increment, `nome` varchar(50) NOT NULL default '', `estado` int(11) default NULL, PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=53 ; -- -- Extraindo dados da tabela `tbl_cidade` -- INSERT INTO `tbl_cidade` VALUES (1, 'CHAPECO', 24); INSERT INTO `tbl_cidade` VALUES (2, 'XANXERE', 24); INSERT INTO `tbl_cidade` VALUES (3, 'JOACABA', 24); INSERT INTO `tbl_cidade` VALUES (4, 'CACADOR', 24); INSERT INTO `tbl_cidade` VALUES (5, 'CONCORDIA', 24); INSERT INTO `tbl_cidade` VALUES (6, 'MAFRA', 24); INSERT INTO `tbl_cidade` VALUES (7, 'JOINVILLE', 24); INSERT INTO `tbl_cidade` VALUES (8, 'JARAGUA DO SUL', 24); INSERT INTO `tbl_cidade` VALUES (9, 'BLUMENAU', 24); INSERT INTO `tbl_cidade` VALUES (10, 'ITAJAI', 24); INSERT INTO `tbl_cidade` VALUES (11, 'LAGES', 24); INSERT INTO `tbl_cidade` VALUES (12, 'RIO DO SUL', 24); INSERT INTO `tbl_cidade` VALUES (13, 'FLORIANOPOLIS', 24); INSERT INTO `tbl_cidade` VALUES (14, 'CRICIUMA', 24); INSERT INTO `tbl_cidade` VALUES (15, 'SÃO MIGUEL DO OESTE', 24); INSERT INTO `tbl_cidade` VALUES (16, 'SÃO BENTO DO SUL', 24); INSERT INTO `tbl_cidade` VALUES (17, 'BRUSQUE', 24); INSERT INTO `tbl_cidade` VALUES (18, 'TUBARAO', 24); INSERT INTO `tbl_cidade` VALUES (19, 'FREDERICO WESTPHALEN', 23); INSERT INTO `tbl_cidade` VALUES (20, 'ERECHIM', 23); INSERT INTO `tbl_cidade` VALUES (21, 'SANTA ROSA', 23); INSERT INTO `tbl_cidade` VALUES (22, 'PASSO FUNDO', 23); INSERT INTO `tbl_cidade` VALUES (23, 'BENTO GONCALVES', 23); INSERT INTO `tbl_cidade` VALUES (24, 'CAXIAS DO SUL', 23); INSERT INTO `tbl_cidade` VALUES (25, 'IJUI', 23); INSERT INTO `tbl_cidade` VALUES (26, 'LAJEADO', 23);
INSERT INTO `tbl_cidade` VALUES (27, 'PORTO ALEGRE', 23); INSERT INTO `tbl_cidade` VALUES (28, 'SANTA MARIA', 23); INSERT INTO `tbl_cidade` VALUES (29, 'SANTA CRUZ DO SUL', 23); INSERT INTO `tbl_cidade` VALUES (30, 'CAMAQUA', 23); INSERT INTO `tbl_cidade` VALUES (31, 'URUGUAIANA', 23); INSERT INTO `tbl_cidade` VALUES (32, 'ALEGRETE', 23); INSERT INTO `tbl_cidade` VALUES (33, 'SANTANA DO LIVRAMENTO', 23); INSERT INTO `tbl_cidade` VALUES (34, 'BAGE', 23); INSERT INTO `tbl_cidade` VALUES (35, 'PELOTAS', 23); INSERT INTO `tbl_cidade` VALUES (36, 'SÃO BORJA', 23); INSERT INTO `tbl_cidade` VALUES (37, 'SANTIAGO', 23); INSERT INTO `tbl_cidade` VALUES (38, 'CURITIBA', 18); INSERT INTO `tbl_cidade` VALUES (39, 'PONTO GROSSA', 18); INSERT INTO `tbl_cidade` VALUES (40, 'CIANORTE', 18); INSERT INTO `tbl_cidade` VALUES (41, 'LONDRINA', 18); INSERT INTO `tbl_cidade` VALUES (42, 'GUARAPUAVA', 18); INSERT INTO `tbl_cidade` VALUES (43, 'MARINGA', 18); INSERT INTO `tbl_cidade` VALUES (44, 'UMUARAMA', 18); INSERT INTO `tbl_cidade` VALUES (45, 'CASCAVEL', 18); INSERT INTO `tbl_cidade` VALUES (46, 'FOZ DO IGUACU', 18); INSERT INTO `tbl_cidade` VALUES (47, 'FRANCISCO BELTRAO', 18); INSERT INTO `tbl_cidade` VALUES (48, 'PATO BRANCO', 18); -- -------------------------------------------------------- -- -- Estrutura da tabela `tbl_cliente` -- CREATE TABLE `tbl_cliente` ( `codigo` int(11) NOT NULL auto_increment, `nome` varchar(40) NOT NULL default '', `endereco` varchar(40) NOT NULL default '', `telefone_area` char(2) default NULL, `telefone` varchar(8) NOT NULL default '', `cidade` int(11) NOT NULL default '0', `cnpj_cpf` varchar(14) NOT NULL default '', `email` varchar(40) default NULL, `inscricao` varchar(18) default NULL, PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=66 ; -- -- Estrutura da tabela `tbl_distancia` -- CREATE TABLE `tbl_distancia` ( `origem` int(11) NOT NULL default '0', `destino` int(11) NOT NULL default '0', `distancia` int(11) NOT NULL default '0', PRIMARY KEY (`origem`,`destino`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -- -- Extraindo dados da tabela `tbl_distancia` -- INSERT INTO `tbl_distancia` VALUES (1, 1, 0); INSERT INTO `tbl_distancia` VALUES (1, 2, 44); INSERT INTO `tbl_distancia` VALUES (1, 3, 153); INSERT INTO `tbl_distancia` VALUES (1, 4, 245); INSERT INTO `tbl_distancia` VALUES (1, 5, 84); INSERT INTO `tbl_distancia` VALUES (1, 6, 419); INSERT INTO `tbl_distancia` VALUES (1, 7, 536); INSERT INTO `tbl_distancia` VALUES (1, 8, 516); INSERT INTO `tbl_distancia` VALUES (1, 9, 471); INSERT INTO `tbl_distancia` VALUES (1, 10, 518); INSERT INTO `tbl_distancia` VALUES (1, 11, 353); INSERT INTO `tbl_distancia` VALUES (1, 12, 386); INSERT INTO `tbl_distancia` VALUES (1, 13, 576); INSERT INTO `tbl_distancia` VALUES (1, 14, 573); INSERT INTO `tbl_distancia` VALUES (1, 15, 130); INSERT INTO `tbl_distancia` VALUES (1, 16, 474); INSERT INTO `tbl_distancia` VALUES (1, 17, 511); INSERT INTO `tbl_distancia` VALUES (1, 18, 579); INSERT INTO `tbl_distancia` VALUES (1, 19, 108); INSERT INTO `tbl_distancia` VALUES (1, 20, 84); INSERT INTO `tbl_distancia` VALUES (1, 21, 254); INSERT INTO `tbl_distancia` VALUES (1, 22, 142); INSERT INTO `tbl_distancia` VALUES (1, 23, 296); INSERT INTO `tbl_distancia` VALUES (1, 24, 318); INSERT INTO `tbl_distancia` VALUES (1, 25, 231); INSERT INTO `tbl_distancia` VALUES (1, 26, 310); INSERT INTO `tbl_distancia` VALUES (1, 27, 409); INSERT INTO `tbl_distancia` VALUES (1, 28, 359);
INSERT INTO `tbl_distancia` VALUES (1, 29, 331); INSERT INTO `tbl_distancia` VALUES (1, 30, 470); INSERT INTO `tbl_distancia` VALUES (1, 31, 705); INSERT INTO `tbl_distancia` VALUES (1, 32, 509); INSERT INTO `tbl_distancia` VALUES (1, 33, 587); INSERT INTO `tbl_distancia` VALUES (1, 34, 551); INSERT INTO `tbl_distancia` VALUES (1, 35, 575); INSERT INTO `tbl_distancia` VALUES (1, 36, 457); INSERT INTO `tbl_distancia` VALUES (1, 37, 387); INSERT INTO `tbl_distancia` VALUES (1, 38, 458); INSERT INTO `tbl_distancia` VALUES (1, 39, 399); INSERT INTO `tbl_distancia` VALUES (1, 40, 420); INSERT INTO `tbl_distancia` VALUES (1, 41, 496); INSERT INTO `tbl_distancia` VALUES (1, 42, 259); INSERT INTO `tbl_distancia` VALUES (1, 43, 457); INSERT INTO `tbl_distancia` VALUES (1, 44, 417); INSERT INTO `tbl_distancia` VALUES (1, 45, 290); INSERT INTO `tbl_distancia` VALUES (1, 46, 316); INSERT INTO `tbl_distancia` VALUES (1, 47, 133); INSERT INTO `tbl_distancia` VALUES (1, 48, 104); INSERT INTO `tbl_distancia` VALUES (2, 1, 44); INSERT INTO `tbl_distancia` VALUES (2, 2, 0); INSERT INTO `tbl_distancia` VALUES (2, 3, 125); . . . INSERT INTO `tbl_distancia` VALUES (48, 22, 258); INSERT INTO `tbl_distancia` VALUES (48, 23, 398); INSERT INTO `tbl_distancia` VALUES (48, 24, 415); INSERT INTO `tbl_distancia` VALUES (48, 25, 314); INSERT INTO `tbl_distancia` VALUES (48, 26, 418); INSERT INTO `tbl_distancia` VALUES (48, 27, 498); INSERT INTO `tbl_distancia` VALUES (48, 28, 445); INSERT INTO `tbl_distancia` VALUES (48, 29, 428); INSERT INTO `tbl_distancia` VALUES (48, 30, 577); INSERT INTO `tbl_distancia` VALUES (48, 31, 766); INSERT INTO `tbl_distancia` VALUES (48, 32, 581); INSERT INTO `tbl_distancia` VALUES (48, 33, 742); INSERT INTO `tbl_distancia` VALUES (48, 34, 719); INSERT INTO `tbl_distancia` VALUES (48, 35, 753); INSERT INTO `tbl_distancia` VALUES (48, 36, 505); INSERT INTO `tbl_distancia` VALUES (48, 37, 451); INSERT INTO `tbl_distancia` VALUES (48, 38, 437); INSERT INTO `tbl_distancia` VALUES (48, 39, 346); INSERT INTO `tbl_distancia` VALUES (48, 40, 323); INSERT INTO `tbl_distancia` VALUES (48, 41, 488); INSERT INTO `tbl_distancia` VALUES (48, 42, 180); INSERT INTO `tbl_distancia` VALUES (48, 43, 462); INSERT INTO `tbl_distancia` VALUES (48, 44, 398); INSERT INTO `tbl_distancia` VALUES (48, 45, 220); INSERT INTO `tbl_distancia` VALUES (48, 46, 343); INSERT INTO `tbl_distancia` VALUES (48, 47, 57); INSERT INTO `tbl_distancia` VALUES (48, 48, 0); -- -------------------------------------------------------- -- -- Estrutura da tabela `tbl_entrega` -- CREATE TABLE `tbl_entrega` ( `codigo` int(11) NOT NULL auto_increment, `numero_nota` varchar(50) NOT NULL default '', `cnpj_remetente` varchar(14) NOT NULL default '', `cnpj_destinatario` varchar(14) NOT NULL default '', `peso` decimal(10,2) NOT NULL default '0.00', `qtde_volume` decimal(10,2) NOT NULL default '0.00', `volume_m3_carga` decimal(10,2) NOT NULL default '0.00', `data` date NOT NULL default '0000-00-00', `ativo` tinyint(1) NOT NULL default '1', PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=70 ; -- -- Estrutura da tabela `tbl_estado` -- CREATE TABLE `tbl_estado` ( `codigo` int(11) NOT NULL auto_increment, `sigla` char(2) NOT NULL default '', `nome` varchar(50) NOT NULL default '', PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=28 ; --
-- Extraindo dados da tabela `tbl_estado` -- INSERT INTO `tbl_estado` VALUES (1, 'AC', 'Acre'); INSERT INTO `tbl_estado` VALUES (2, 'AL', 'Alagoas'); INSERT INTO `tbl_estado` VALUES (3, 'AM', 'Amazonas'); INSERT INTO `tbl_estado` VALUES (4, 'AP', 'Amapá'); INSERT INTO `tbl_estado` VALUES (5, 'BA', 'Bahia'); INSERT INTO `tbl_estado` VALUES (6, 'CE', 'Ceará'); INSERT INTO `tbl_estado` VALUES (7, 'DF', 'Distrito Federal'); INSERT INTO `tbl_estado` VALUES (8, 'ES', 'Espírito Santo'); INSERT INTO `tbl_estado` VALUES (9, 'GO', 'Goiás'); INSERT INTO `tbl_estado` VALUES (10, 'MA', 'Maranhão'); INSERT INTO `tbl_estado` VALUES (11, 'MG', 'Minas Gerais'); INSERT INTO `tbl_estado` VALUES (12, 'MS', 'Mato Grosso do Sul'); INSERT INTO `tbl_estado` VALUES (13, 'MT', 'Mato Grosso'); INSERT INTO `tbl_estado` VALUES (14, 'PA', 'Pará'); INSERT INTO `tbl_estado` VALUES (15, 'PB', 'Paraíba'); INSERT INTO `tbl_estado` VALUES (16, 'PE', 'Pernambuco'); INSERT INTO `tbl_estado` VALUES (17, 'PI', 'Piauí'); INSERT INTO `tbl_estado` VALUES (18, 'PR', 'Paraná'); INSERT INTO `tbl_estado` VALUES (19, 'RJ', 'Rio de Janeiro'); INSERT INTO `tbl_estado` VALUES (20, 'RN', 'Rio Grande do Norte'); INSERT INTO `tbl_estado` VALUES (21, 'RO', 'Rondônia'); INSERT INTO `tbl_estado` VALUES (22, 'RR', 'Raraima'); INSERT INTO `tbl_estado` VALUES (23, 'RS', 'Rio Grande do Sul'); INSERT INTO `tbl_estado` VALUES (24, 'SC', 'Santa Catarina'); INSERT INTO `tbl_estado` VALUES (25, 'SE', 'Sergipe'); INSERT INTO `tbl_estado` VALUES (26, 'SP', 'São Paulo'); INSERT INTO `tbl_estado` VALUES (27, 'TO', 'Tocantins'); -- -------------------------------------------------------- -- -- Estrutura da tabela `tbl_motorista` -- CREATE TABLE `tbl_motorista` ( `codigo` int(11) NOT NULL auto_increment, `nome` varchar(40) NOT NULL default '', `endereco` varchar(40) NOT NULL default '', `telefone_area` char(2) default NULL, `telefone` varchar(15) NOT NULL default '', `cidade` int(11) NOT NULL default '0', `cpf` varchar(11) NOT NULL default '', `cnh` varchar(16) NOT NULL default '', `cnh_vencimento` date default NULL, `categoria` char(2) NOT NULL default '', PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ; -- -- Estrutura da tabela `tbl_roteiro` -- CREATE TABLE `tbl_roteiro` ( `codigo` int(11) NOT NULL auto_increment, `cidade` int(11) NOT NULL default '0', `caminhao` int(11) NOT NULL default '0', `motorista` int(11) NOT NULL default '0', `data` date NOT NULL default '0000-00-00', `cavalo` int(11) default NULL, PRIMARY KEY (`codigo`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=40 ; -- -- Estrutura da tabela `tbl_roteiro_entrega` -- CREATE TABLE `tbl_roteiro_entrega` ( `roteiro` int(11) NOT NULL default '0', `entrega` int(11) NOT NULL default '0', `ordem` int(11) NOT NULL default '0', PRIMARY KEY (`roteiro`,`entrega`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; -- -- Estrutura da tabela `tbl_usuario` -- CREATE TABLE `tbl_usuario` ( `codigo` int(11) NOT NULL auto_increment, `login` varchar(20) NOT NULL default '', `senha` varchar(20) NOT NULL default '', PRIMARY KEY (`codigo`),
UNIQUE KEY `login` (`login`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; -- -- Extraindo dados da tabela `tbl_usuario` -- INSERT INTO `tbl_usuario` VALUES (1, 'toigo', '123');
III. bd.php
O arquivo bd.php refere-se ao codigo que faz consultas no banco de dados
<?php function Consulta($consulta) { // $conn = mysql_connect('localhost', 'root', '12345'); $conn = mysql_connect('db1.awardspace.com', 'toigo_bd', '12345'); // mysql_select_db('bd_toigo', $conn); mysql_select_db('toigo_bd', $conn); $query = mysql_query($consulta, $conn); mysql_close($conn); return $query; } ?>
IV. roteiros_salvar.php
O código referente este arquivo é utilizado para salvar o roteiro depois de selecionadas as
entregas conforme dados do caminhão informados pelo usuário na tela.
<?php require_once('bd.php'); require_once('roteiros_busca.php'); // Recebe os dados do formulário da tela de emissão de roteiro $localidade = $_POST['rot_localidade']; $motorista = $_POST['rot_motorista']; $caminhao = BuscaCaminhao($_POST['rot_caminhao']); if ($caminhao['tipo'] == 3) $cavalo = $_POST['rot_cavalo']; else $cavalo = 0; // Busca as entregas que estão à espera para a localidade de destino $entregas = BuscaEntregasPorCidade($localidade); $soma_pesos = 0; $soma_volumes = 0; // Contabiliza a soma dos pesos e volumes das entregas para a localidade (se houver) foreach ($entregas as $entrega) { $soma_pesos += $entrega['peso']; $soma_volumes += $entrega['volume']; } if (($soma_pesos > $caminhao['tara']) || ($soma_volumes > $caminhao['volume'])) { // A soma dos pesos ou dos volumes ultrapassa a tara/volume do caminhão // ... então filtra as entregas por data, dando prioridade para as mais antigas // ... a busca no banco de dados já traz as entregas ordenadas pela data mais antiga primeiro $entregas_selecionadas = array(); $soma_peso = 0; $soma_volume = 0;
// Filtra as entregas retornadas, selecionando apenas aquelas que cabem no peso especificado for ($i = 0; $i < count($entregas); $i++) // Verifica se cabe no peso e volume if (($soma_peso + $entregas[$i]['peso'] <= $caminhao['tara']) && ($soma_volume + $entregas[$i]['volume'] <= $caminhao['volume'])) { $soma_peso += $entregas[$i]['peso']; $soma_volume += $entregas[$i]['volume']; array_push($entregas_selecionadas, $entregas[$i]); } } else { // Ainda há espaço no caminhão... // ... então busca outras entregas para caber no caminhão $entregas_outras = BuscaEntregasPorPeso($localidade, $caminhao['tara'] - $soma_pesos, $caminhao['volume'] - $soma_volumes); $entregas_selecionadas = array_merge($entregas, $entregas_outras); } // Verifica se há entregas selecionadas para a localidade if (count($entregas_selecionadas) > 0) { // Ordena as entregas pela distância menor em relação à cidade de origem $entregas_selecionadas = OrdenarEntregas($entregas_selecionadas); // Efetua a inserção do registro do roteiro no banco de dados Consulta('insert into tbl_roteiro (cidade, caminhao, motorista, data, cavalo) values (' . $localidade . ',' . $caminhao['codigo'] . ',' . $motorista . ', CURRENT_DATE, ' . $cavalo . ')'); // Busca o código do último roteiro inserido $registro = mysql_fetch_array(Consulta('select max(codigo) from tbl_roteiro')); $roteiro = $registro[0]; // Efetua a inserção do vínculo entre roteiro e entregas no banco de dados foreach ($entregas_selecionadas as $entrega) { Consulta('insert into tbl_roteiro_entrega (roteiro, entrega, ordem) ' . ' values(' . $roteiro . ',' . $entrega['codigo'] . ', ' . $entrega['distancia'] . ')'); Consulta('update tbl_entrega set ativo=0 where (codigo = ' . $entrega['codigo'] . ')'); } header('location: roteiros_visualizar.php?id=' . $roteiro); } else echo('Não foram encontradas entregas para a localidade, ou proximidades, que caibam no caminhão selecionado!'); ?>
V. roteiros_kopt.php
Nesta parte de código o roteiro inicialmente criado passa por um processo de trocas de
ordem entre as entregas para tentar ser melhorado.
<?php require_once('bd.php'); require_once('roteiros_busca.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); $roteiro = $_POST['roteiro']; // Query que traz as entregas do roteiro $query = Consulta('SELECT c.cidade, re.entrega, re.ordem FROM tbl_roteiro_entrega re INNER JOIN tbl_entrega e ON (re.entrega=e.codigo) INNER JOIN tbl_cliente c ON (e.cnpj_destinatario=c.cnpj_cpf) INNER JOIN tbl_cidade cid ON (c.cidade=cid.codigo) WHERE re.roteiro = '. $roteiro .' ORDER BY re.ordem
'); /* print "<pre>"; print_r($query); print "</pre>"; */ $menor_trajeto = array(); $trajeto_original = array(); $trajeto_calculado = array(); //variável que contém a kilometragem percorrida pelo caminhão na sequência original $km_original = 0; $i = 0; // Monta uma matriz com o id das cidades de destino das entregas while ($registro = mysql_fetch_array($query)) { //$km_original += $registro['ordem']; $trajeto_original[$i]['cidade_id'] = $registro['cidade']; $trajeto_original[$i]['entrega_id'] = $registro['entrega']; $i++; } /* print "<pre>"; echo "<br><br>trajeto original<br>"; print_r($trajeto_original); print "</pre>"; */ // Adiciona a quilometragem da cidade de Itajaí até a primeira cidade a ser percorrida //$km_original += BuscaDistancia(10, $trajeto_original[0]['cidade_id']); $km_original = Calcula_km($trajeto_original); // echo "<br><br>Km original: $km_original<br><br>"; // Atribui o trajeto e a kilometragem original como sendo os melhores $menor_trajeto = $trajeto_original; $menor_km = $km_original; $trajeto_calculado = $trajeto_original; $qtde = count($trajeto_original); // echo "<br><br>Vai começar a calcular<br><br>"; // Faz a troca das cidades para achar o menor caminho do { $i = 0; // Inverte todas as posições entre as cidades while ($i < ($qtde - 1)){ //inverte a posição $aux = $trajeto_calculado[$i]; $trajeto_calculado[$i] = $trajeto_calculado[$i + 1]; $trajeto_calculado[$i + 1] = $aux; $i++; // Calcula a distãncia entre as cidades após cada inversão $km_calculado = Calcula_km($trajeto_calculado); /* echo "<br> $i - inverteu uma posiçao<br>"; print "<pre>"; print_r($trajeto_calculado); print "</pre>"; */ // Se a kilometragem calculada for menor que a kilometragem original, assume como o menor trajeto if ( $km_calculado < $menor_km){ // echo "<br><br>A quilometragem calculada é menor $km_calculado < $menor_km<br><br>"; unset($menor_trajeto); $menor_trajeto = $trajeto_calculado; $menor_km = $km_calculado; /* print "<pre>"; print_r($menor_trajeto); print_r($menor_km); print "</pre>"; */ }else{ // echo "<br><br>A quilometragem calculada nao é menor $km_calculado > $menor_km<br><br>"; } } } while ($trajeto_calculado != $trajeto_original); // Fez o calculo K-opt e vai mostrar o roteiro melhorado na tela // Busca os dados do roteiro $query = Consulta('select r.codigo, r.data, d.nome, c.placa, c.marca, c.tara, c.volume, ' . ' t.descricao, m.nome as motorista, m.cnh, v.placa as cavalo, v.marca as cavalo_marca ' .
'from tbl_cidade d, tbl_caminhao c, tbl_caminhao_tipo t, tbl_motorista m, tbl_roteiro r '. ' left outer join tbl_caminhao v on (v.codigo=r.cavalo) ' . 'where (r.codigo=' . $roteiro . ') and (r.cidade=d.codigo) and ' . ' (r.caminhao=c.codigo) and (t.codigo=c.tipo) and (m.codigo=r.motorista)'); $roteiro = mysql_fetch_array($query); // Coloca a data de emissão do roteiro no formato correto $data = substr($roteiro['data'], 8, 2) . '/' . substr($roteiro['data'], 5, 2) . '/' . substr($roteiro['data'], 0, 4); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="roteiros_kopt.php" name="form_roteiro"> <table width="630" cellspacing="0" cellpadding="3"> <tr height="22"> <td colspan="6"><font face="Arial" size="2" color="#DD0000"><b> VISUALIZAR ROTEIRO </b></font></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="120"><font face="Arial" size="2"><b>Data emissão:</b></font></td> <td colspan="3"><font face="Arial" size="2"><?php echo $data ?></font></td> </tr> <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Destino:</b></font></td> <td colspan="3"><font face="Arial" size="2"><?php echo($roteiro['nome']) ?></font></td> </tr> <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Caminhão:</b></font></td> <td colspan="3"><font face="Arial" size="2"> <?php echo($roteiro['marca'] . ' - Placa: ' . $roteiro['placa'] . ' - Capacidade: ' . $roteiro['tara'] . ' kg e ' . $roteiro['volume'] . 'm<sup>3</sup>'); ?> </font> </td> </tr> <?php if ($roteiro['cavalo'] != '') echo(' <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Cav. mecânico:</b></font></td> <td colspan="3"><font face="Arial" size="2"> ' . $roteiro['cavalo_marca'] . ' - Placa: ' . $roteiro['cavalo'] . ' </font> </td> </tr>'); ?> <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Motorista:</b></font></td> <td colspan="3"><font face="Arial" size="2"><?php echo($roteiro['motorista'] . ' - CNH: ' . $roteiro['cnh']) ?></font></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="120"><font face="Arial" size="2"><b><u>Destino</u></b></font></td> <td nowrap><font face="Arial" size="2"><b><u>Nº Nota </u></b></font></td> <td width="170"><font face="Arial" size="2"><b><u>Remetente</u></b></font></td> <td width="160"><font face="Arial" size="2"><b><u>Destinatário</u></b></font></td> <td nowrap><font face="Arial" size="2"><b><u>Peso (Kg) </u></b></font></td> <td nowrap><font face="Arial" size="2"><b><u>Vol. (m</u><sup>3</sup>)</b></font></td> </tr> <?php $cor = false; $soma_peso = 0; $soma_volume = 0; $qtde = count($menor_trajeto);
/*echo"<br><br>Vai imprimir na tela o menor trajeto<br><br>"; print "<pre>"; print_r($menor_trajeto); print "</pre>"; */ // Percorre o array com o menor trajeto e busca a entrega no Banco para mostrar na tela for ($i = 0; $i < $qtde; $i++){ // Busca a entrega no Banco de Dados $query = Consulta('select e.numero_nota, e.peso, e.volume_m3_carga, ' . ' rem.nome as remetente, dest.nome as destinatario, c.nome as destino ' . 'from tbl_entrega e ' . 'inner join tbl_cliente rem on (rem.cnpj_cpf=e.cnpj_remetente) ' . 'inner join (tbl_cliente dest inner join tbl_cidade c on (c.codigo=dest.cidade)) on (dest.cnpj_cpf=e.cnpj_destinatario) ' . 'inner join tbl_roteiro_entrega ent on (ent.entrega=e.codigo) ' . 'where (e.codigo = ' . $menor_trajeto[$i]['entrega_id'] . ') ' . 'order by ent.ordem'); $registro = mysql_fetch_array($query); $volume = $registro['volume_m3_carga']; $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td nowrap><font face="Arial" size="2">' . $registro['destino'] . '</font></td>'); echo('<td nowrap><font face="Arial" size="2">' . $registro['numero_nota'] . '</font></td>'); echo('<td nowrap><font face="Arial" size="2">' . $registro['remetente'] . '</font></td>'); echo('<td nowrap><font face="Arial" size="2">' . $registro['destinatario'] . '</font></td>'); echo('<td nowrap align="right"><font face="Arial" size="2">' . round($registro['peso']) . '</font></td>'); echo('<td nowrap align="right"><font face="Arial" size="2">' . $volume . '</font></td>'); echo('</tr>'); $soma_peso += $registro['peso']; $soma_volume += $volume; } ?> <tr> <td colspan="4" align="right"> <font face="Arial" size="2"><b>Total:</b></font> </td> <td align="right"><font face="Arial" size="2"><b><?php echo $soma_peso ?></b></font></td> <td align="right"><font face="Arial" size="2"><b><?php echo $soma_volume ?></b></font></td> </tr> <tr> <td bgcolor="#DD0000" height="1" colspan="6"></td> </tr> <tr height="22"> <td colspan="6" align="left"><br><?php $diferenca = $km_original - $menor_km; if ($menor_trajeto == $trajeto_original){ echo '<font face="Arial" size="2"><b>Não houve melhoria no roteiro</b></font><br><br>'; }else{ echo '<font face="Arial" size="2"><b>Houve melhoria no roteiro</b></font><br><br>'; } echo '<font face="Arial" size="2"><b>KM original: ' . $km_original . '</b></font><br>'; echo '<font face="Arial" size="2"><b>KM melhorado: ' . $menor_km . '</b></font><br>'; echo '<font face="Arial" size="2"><b>KM de economia: </b></font>'; echo '<font face="Arial" color="#DD0000" size="2"><b>' . $diferenca . '</b></font> '; ?><br><br></td> </tr> <tr> <td bgcolor="#DD0000" height="1" colspan="6"></td> </tr> </table> </form> </body> </html>
VI. roteiros_ visualizar.php
Neste arquivo consta o código que visualiza os roteiros criados.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); $roteiro = $_GET['id']; $codigo = $roteiro; // Busca os dados do roteiro $query = Consulta('select r.codigo, r.data, d.nome, c.placa, c.marca, c.tara, c.volume, ' . ' t.descricao, m.nome as motorista, m.cnh, v.placa as cavalo, v.marca as cavalo_marca ' . 'from tbl_cidade d, tbl_caminhao c, tbl_caminhao_tipo t, tbl_motorista m, tbl_roteiro r '. ' left outer join tbl_caminhao v on (v.codigo=r.cavalo) ' . 'where (r.codigo=' . $roteiro . ') and (r.cidade=d.codigo) and ' . ' (r.caminhao=c.codigo) and (t.codigo=c.tipo) and (m.codigo=r.motorista)'); $roteiro = mysql_fetch_array($query); // Busca as entregas do roteiro $query = Consulta('select e.numero_nota, e.peso, e.volume_m3_carga, ' . ' rem.nome as remetente, dest.nome as destinatario, c.nome as destino ' . 'from tbl_entrega e ' . 'inner join tbl_cliente rem on (rem.cnpj_cpf=e.cnpj_remetente) ' . 'inner join (tbl_cliente dest inner join tbl_cidade c on (c.codigo=dest.cidade)) on (dest.cnpj_cpf=e.cnpj_destinatario) ' . 'inner join tbl_roteiro_entrega ent on (ent.entrega=e.codigo) ' . 'where (ent.roteiro = ' . $roteiro['codigo'] . ') ' . 'order by ent.ordem'); // Coloca a data de emissão do roteiro no formato correto $data = substr($roteiro['data'], 8, 2) . '/' . substr($roteiro['data'], 5, 2) . '/' . substr($roteiro['data'], 0, 4); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="roteiros_kopt.php" name="form_roteiro" onSubmit="return valida();"> <input type="hidden" name="roteiro" value="<?php echo ($_GET['id']) ?>"> <table width="630" cellspacing="0" cellpadding="3"> <tr height="22"> <td colspan="6"><font face="Arial" size="2" color="#DD0000"><b> VISUALIZAR ROTEIRO </b></font></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="120"><font face="Arial" size="2"><b>Data emissão:</b></font></td> <td colspan="3"><font face="Arial" size="2"><?php echo $data ?></font></td> </tr> <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Destino:</b></font></td> <td colspan="3"><font face="Arial" size="2"><?php echo($roteiro['nome']) ?></font></td> </tr> <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Caminhão:</b></font></td> <td colspan="3"><font face="Arial" size="2"> <?php echo($roteiro['marca'] . ' - Placa: ' . $roteiro['placa'] . ' - Capacidade: ' . $roteiro['tara'] . ' kg e ' . $roteiro['volume'] . 'm<sup>3</sup>'); ?> </font> </td> </tr> <?php if ($roteiro['cavalo'] != '') echo(' <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Cav. mecânico:</b></font></td> <td colspan="3"><font face="Arial" size="2"> ' . $roteiro['cavalo_marca'] . ' - Placa: ' . $roteiro['cavalo'] . ' </font> </td>
</tr>'); ?> <tr height="22"> <td width="100"><font face="Arial" size="2"><b>Motorista:</b></font></td> <td colspan="3"><font face="Arial" size="2"><?php echo($roteiro['motorista'] . ' - CNH: ' . $roteiro['cnh']) ?></font></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="120"><font face="Arial" size="2"><b><u>Destino</u></b></font></td> <td nowrap><font face="Arial" size="2"><b><u>Nº Nota </u></b></font></td> <td width="170"><font face="Arial" size="2"><b><u>Remetente</u></b></font></td> <td width="160"><font face="Arial" size="2"><b><u>Destinatário</u></b></font></td> <td nowrap><font face="Arial" size="2"><b><u>Peso (Kg) </u></b></font></td> <td nowrap><font face="Arial" size="2"><b><u>Vol. (m</u><sup>3</sup>)</b></font></td> </tr> <?php $cor = false; $soma_peso = 0; $soma_volume = 0; while ($registro = mysql_fetch_array($query)) { $volume = $registro['volume_m3_carga']; $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td nowrap><font face="Arial" size="2">' . $registro['destino'] . '</font></td>'); echo('<td nowrap><font face="Arial" size="2">' . $registro['numero_nota'] . '</font></td>'); echo('<td nowrap><font face="Arial" size="2">' . $registro['remetente'] . '</font></td>'); echo('<td nowrap><font face="Arial" size="2">' . $registro['destinatario'] . '</font></td>'); echo('<td nowrap align="right"><font face="Arial" size="2">' . round($registro['peso']) . '</font></td>'); echo('<td nowrap align="right"><font face="Arial" size="2">' . $volume . '</font></td>'); echo('</tr>'); $soma_peso += $registro['peso']; $soma_volume += $volume; } ?> <tr> <td colspan="4" align="right"> <font face="Arial" size="2"><b>Total:</b></font> </td> <td align="right"><font face="Arial" size="2"><b><?php echo $soma_peso ?></b></font></td> <td align="right"><font face="Arial" size="2"><b><?php echo $soma_volume ?></b></font></td> </tr> <tr> <td bgcolor="#DD0000" height="1" colspan="6"></td> </tr> <tr height="22"> <td colspan="6" align="center"><br><input type="submit" value=" K-opt "> <input type="button" value="Excluir" onClick="location='roteiros_excluir.php?id=<?php echo $codigo ?>';"><br><br></td> </tr> <tr> <td bgcolor="#DD0000" height="1" colspan="6"></td> </tr> </table> <script> function valida(){ if ( confirm ("O método K-opt pode demorar para ser calculado, deseja continuar?") ){ return true; }else{ return false; } } </script> </form> </body> </html>
VII. roteiros_excluir.php
Código para excluir um roteiro.
<?php require_once('bd.php'); $codigo = $_GET['id']; if ($codigo > 0) { // Busca as entregas do roteiro $query = Consulta('select * from tbl_roteiro_entrega where roteiro = ' . $codigo); // Habilita as entregas como ativas novamente while ($registro = mysql_fetch_array($query)) Consulta('update tbl_entrega set ativo=1 where (codigo = ' . $registro['entrega'] . ')'); Consulta('delete from tbl_roteiro_entrega where roteiro = ' . $codigo); Consulta('delete from tbl_roteiro where codigo = ' . $codigo); } header('location: roteiros.php'); ?>
VIII. roteiros_ emitir.php
Código fonte para o preenchimento dos dados pelo usuário na tela de emissão de roteiros.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca os caminhões cadastrados $query_caminhoes = Consulta('select c.codigo, c.placa, c.marca, ' . ' t.descricao, t.codigo as tipo from tbl_caminhao c, tbl_caminhao_tipo t ' . ' where (c.tipo = t.codigo) order by t.descricao, c.placa '); // Busca os motoristas cadastrados $query_motoristas = Consulta('select * from tbl_motorista order by nome, categoria '); // Busca as cidades que tem registro na tabela de distância $query_localidades = Consulta('select distinct c.codigo, c.nome from tbl_cidade c, tbl_distancia d ' . ' where (c.codigo = d.origem) order by c.nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0" onLoad="verificaRoteiroCaminhao()"> <br> <form method="post" action="roteiros_salvar.php" name="form_roteiro"> <table width="550"> <tr><td height="22" colspan="4"><font face="Arial" size="2" color="#DD0000"><b> EMISSÃO DE ROTEIRO</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr><td colspan="7"> </td></tr>
<tr height="22"> <td width="100" align="right"><font face="Arial" size="2">Localidade</font></td> <td> <select name="rot_localidade"> <?php while ($tipo = mysql_fetch_array($query_localidades)) echo('<option value="' . $tipo['codigo'] . '">' . $tipo['nome'] . '</option>'); ?> </select> </td> </tr> <tr height="22"> <td width="100" align="right"><font face="Arial" size="2">Caminhão</font></td> <td> <select name="rot_caminhao" onChange="verificaRoteiroCaminhao()"> <?php while ($tipo = mysql_fetch_array($query_caminhoes)) if ($tipo['tipo'] != 4) echo('<option value="' . $tipo['codigo'] . '" id="' . $tipo['tipo'] . '">' . $tipo['marca'] . ' - Placa: ' . $tipo['placa'] . '</option>'); ?> </select> </td> </tr> <tr height="22"> <td width="100" align="right"><font face="Arial" size="2">Cavalo Mecânico</font></td> <td> <select name="rot_cavalo"> <?php mysql_data_seek($query_caminhoes, 0); while ($tipo = mysql_fetch_array($query_caminhoes)) if ($tipo['tipo'] == 4) echo('<option value="' . $tipo['codigo'] . '">' . $tipo['marca'] . ' - Placa: ' . $tipo['placa'] . '</option>'); ?> </select> </td> </tr> <tr height="22"> <td width="100" align="right"><font face="Arial" size="2">Motorista</font></td> <td> <select name="rot_motorista"> <?php while ($tipo = mysql_fetch_array($query_motoristas)) echo('<option value="' . $tipo['codigo'] . '">' . $tipo['nome'] . ' - Categoria ' . $tipo['categoria'] . '</option>'); ?> </select> </td> </tr> <tr height="22"> <td width="100"></td> <td><br><input type="submit" value=" Emitir Roteiro "><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
IX. roteiros_ busca.php
Código fonte responsável pela busca de entregas para montar o roteiro.
<?php require_once('bd.php'); // Busca os dados de um caminhão, segundo o seu código
function BuscaCaminhao($codigo) { $query = Consulta('select codigo, tara, volume, tipo from tbl_caminhao where codigo = ' . $codigo); return mysql_fetch_array($query); } // Busca a distância entre duas cidades function BuscaDistancia($origem, $destino) { $query = Consulta('select distancia from tbl_distancia where origem = ' . $origem . ' and destino = ' . $destino); $registro = mysql_fetch_array($query); return $registro['distancia']; } // Busca as entregas que estão à espera para uma determinada cidade function BuscaEntregasPorCidade($codigo_cidade) { $query = Consulta('select e.codigo, e.numero_nota, e.data, e.peso, e.volume_m3_carga, ' . ' origem.codigo as cidade, origem.nome ' . 'from tbl_entrega e ' . ' inner join tbl_cliente dest on (dest.cnpj_cpf = e.cnpj_destinatario) ' . ' inner join (tbl_cliente rem ' . ' inner join tbl_cidade origem on (origem.codigo=rem.cidade)) on (rem.cnpj_cpf = e.cnpj_remetente) ' . 'where (dest.cidade = ' . $codigo_cidade . ') and (ativo=1) ' . 'order by e.data asc'); $entregas = array(); // Monta uma matriz com os dados das entregas while ($registro = mysql_fetch_array($query)) { $entrega = array(); $entrega['distancia'] = BuscaDistancia($registro['cidade'], $codigo_cidade); $entrega['codigo'] = $registro['codigo']; $entrega['numero_nota'] = $registro['numero_nota']; $entrega['peso'] = $registro['peso']; $entrega['volume'] = $registro['volume_m3_carga']; $entrega['data'] = $registro['data']; $entrega['origem_codigo'] = $registro['cidade']; $entrega['origem_nome'] = $registro['nome']; $entrega['destino_codigo'] = $codigo_cidade; $entrega['destino_nome'] = ''; array_Push($entregas, $entrega); } return $entregas; } // Busca as entregas que estão próximas a uma determinada cidade, e dentro de um determinado peso function BuscaEntregasPorPeso($codigo_cidade, $peso, $volume) { // Busca as entregas que possuem peso e volume abaixo do procurado // Não adianta trazer as entregas que estão no banco de dados, e que sejam maior do que o caminhão tem espaço $query = Consulta('select e.codigo, e.numero_nota, e.peso, e.volume_m3_carga, ' . ' origem.codigo as origem_cod, origem.nome as origem_nome, ' . ' destino.codigo as destino_cod, destino.nome as destino_nome ' . 'from tbl_entrega e ' . ' inner join (tbl_cliente dest ' . ' inner join tbl_cidade destino on (destino.codigo=dest.cidade)) on (dest.cnpj_cpf = e.cnpj_destinatario) ' . ' inner join (tbl_cliente rem ' . ' inner join tbl_cidade origem on (origem.codigo=rem.cidade)) on (rem.cnpj_cpf = e.cnpj_remetente) ' . 'where (e.peso < ' . $peso . ') and (volume_m3_carga < ' . $volume . ') ' . ' and (dest.cidade != ' . $codigo_cidade . ') and (e.ativo=1)'); $entregas = array(); // Monta uma matriz com os dados das entregas while ($registro = mysql_fetch_array($query)) { $entrega = array(); $entrega['distancia'] = BuscaDistancia($codigo_cidade, $registro['destino_cod']); $entrega['codigo'] = $registro['codigo']; $entrega['numero_nota'] = $registro['numero_nota']; $entrega['peso'] = $registro['peso']; $entrega['volume'] = $registro['volume_m3_carga'];
$entrega['data'] = 0; $entrega['origem_codigo'] = $registro['origem_cod']; $entrega['origem_nome'] = $registro['origem_nome']; $entrega['destino_codigo'] = $registro['destino_cod']; $entrega['destino_nome'] = $registro['destino_nome']; array_push($entregas, $entrega); } // Ordena o vetor, deixando primeiro as entregas mais próximas da cidade de destino sort($entregas); $soma_peso = 0; $soma_volume = 0; $selecionadas = array(); // Filtra as entregas retornadas, selecionando apenas aquelas que cabem no peso e volume especificado for ($i = 0; $i < count($entregas); $i++) // Verifica se cabe no peso e volume if (($soma_peso + $entregas[$i]['peso'] <= $peso) && ($soma_volume + $entregas[$i]['volume'] <= $volume)) { $soma_peso += $entregas[$i]['peso']; $soma_volume += $entregas[$i]['volume']; array_push($selecionadas, $entregas[$i]); } return $selecionadas; } // Ordena o vetor de entregas pela distância function OrdenarEntregas($entregas) { for ($i =0; $i < count($entregas); $i++) $entregas[$i]['distancia'] = BuscaDistancia($entregas[$i]['origem_codigo'], $entregas[$i]['destino_codigo']); sort($entregas); return $entregas; } // Calcula a Kilometragem entre a sequência de cidades passadas no array function Calcula_km($trajeto){ $qtde = count($trajeto); $i = 0; $km = 0; // Soma a distância entre as cidades while ($i < ($qtde - 1)){ $km += BuscaDistancia($trajeto[$i]['cidade_id'], $trajeto[$i + 1]['cidade_id']); $i++; } // Soma a distância de Itajaí até a primeira cidade do trajeto $km += BuscaDistancia(10, $trajeto[0]['cidade_id']); return $km; } ?>
X. roteiros.php
Exibe a lista de roteiros já criados a partir da escolha da opção Roteiros no menu principal.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca os roteiros emitidos no banco de dados
$query = Consulta('select r.codigo, r.data, d.nome, c.placa, c.marca, v.placa as cavalo, v.marca as cavalo_marca ' . 'from tbl_cidade d, tbl_caminhao_tipo t, tbl_caminhao c, tbl_roteiro r '. ' left outer join tbl_caminhao v on (v.codigo=r.cavalo) ' . 'where (r.cidade=d.codigo) and (r.caminhao=c.codigo) and (t.codigo=c.tipo) order by r.data desc, r.codigo desc'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <table width="570" cellspacing="0" cellpadding="3"> <tr height="22"> <td colspan="3"><font face="Arial" size="2" color="#DD0000"><b> ROTEIROS </b></font></td> <td colspan="2" align="right"><a href="roteiros_emitir.php"><font face="Arial" size="2" color="#0000FF">Novo Roteiro</font></a></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="70"><font face="Arial" size="2"><b><u>Data</u></b></font></td> <td width="120"><font face="Arial" size="2"><b><u>Destino</u></b></font></td> <td width="250"><font face="Arial" size="2"><b><u>Caminhão</u></b></font></td> <td width="80" colspan="2" align="right"><font face="Arial" size="2"><b><u>Opções</u></b></font></td> </tr> <?php $cor = false; while ($registro = mysql_fetch_array($query)) { $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); $data = substr($registro['data'], 8, 2) . '/' . substr($registro['data'], 5, 2) . '/' . substr($registro['data'], 0, 4); echo('<td valign=top><font face="Arial" size="2">' . $data . '</font></td>'); echo('<td valign=top><font face="Arial" size="2">' . $registro['nome'] . '</font></td>'); if ($registro['cavalo'] != '') echo('<td><font face="Arial" size="2">' . $registro['marca'] . ' - ' . $registro['placa'] . '<br> (Cavalo: ' . $registro['cavalo_marca'] . ' - ' . $registro['cavalo'] . ')' . '</font></td>'); else echo('<td><font face="Arial" size="2">' . $registro['marca'] . ' - ' . $registro['placa'] . '</font></td>'); echo('<td colspan="2" align="center" valign=top><a href="roteiros_visualizar.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Visualizar</font></a></td>'); //echo('<td align="center" valign=top><a href="roteiros_excluir.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Excluir</font></a></td>'); echo('</tr>'); } ?> <tr><td bgcolor="#DD0000" height="1" colspan="5"></td></tr> </table> </body> </html>
XI. motoristas_ salvar.php
O código referente este arquivo é utilizado para salvar um motorista no banco de dados.
<?php require_once('bd.php'); $codigo = $_POST['mot_codigo']; $nome = $_POST['mot_nome']; $endereco = $_POST['mot_endereco']; $telefone_area = $_POST['mot_telefone_area']; $telefone = $_POST['mot_telefone']; $cidade = $_POST['mot_cidade']; $cpf = $_POST['mot_cpf']; $cnh = $_POST['mot_cnh']; $cnh_dia = $_POST['mot_cnh_dia']; $cnh_mes = $_POST['mot_cnh_mes']; $cnh_ano = $_POST['mot_cnh_ano']; $categoria = strtoupper($_POST['mot_categoria']); $cnh_vencimento = $cnh_ano . '/' . $cnh_mes . '/' . $cnh_dia; if ((strlen($nome) < 3) || (strlen($endereco) < 3) || (strlen($telefone) < 7) || (strlen($cpf) < 11) || (strlen($cnh) < 16) || (strlen($categoria) < 1)) exit('<h3>Erro!<br>Os dados não foram informados corretamente!</h3>'); if ($codigo > 0) Consulta('update tbl_motorista set ' . 'nome = \'' . $nome . '\', ' . 'endereco = \'' . $endereco . '\', ' . 'telefone_area = \'' . $telefone_area . '\', ' . 'telefone = \'' . $telefone . '\', ' . 'cidade = ' . $cidade . ', ' . 'cpf = \'' . $cpf . '\', ' . 'cnh = \'' . $cnh . '\', ' . 'cnh_vencimento = \'' . $cnh_vencimento . '\', ' . 'categoria = \'' . $categoria . '\'' . 'where codigo = ' . $codigo); else Consulta('insert into tbl_motorista (nome,endereco,telefone_area,telefone,cidade,cpf,cnh,cnh_vencimento,categoria) values (' . '\'' . $nome . '\', ' . '\'' . $endereco . '\', ' . '\'' . $telefone_area . '\', ' . '\'' . $telefone . '\', ' . '' . $cidade . ', ' . '\'' . $cpf . '\', ' . '\'' . $cnh . '\', ' . '\'' . $cnh_vencimento . '\', ' . '\'' . $categoria . '\')'); header('location: motoristas.php'); ?>
XII. motoristas_ excluir.php
Código para excluir um motorista.
<?php require_once('bd.php'); $codigo = $_GET['id']; if ($codigo > 0) Consulta('delete from tbl_motorista ' . 'where codigo = ' . $codigo); header('location: motoristas.php'); ?>
XIII. motoristas_ cadastro.php
Código para cadastrar um novo motorista.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código do motorista da página de caminhões $codigo = $_GET['id']; // Busca os dados do motorista, de acordo com o código $query = Consulta('select * from tbl_motorista where codigo = ' . $codigo); // Pega os dados do motorista, que resultou da busca $registro = mysql_fetch_array($query); // Busca as cidade no banco de dados $cidades = Consulta('select * from tbl_cidade order by nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="motoristas_salvar.php" name="form_motorista"> <input type="hidden" name="mot_codigo" value="<?php echo $registro['codigo']?>"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE MOTORISTA</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr><td height="22" colspan="7"><font face="Arial" size="2"><br>Os campos marcados com asterisco (*) são obrigatórios.</font></td></tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><br>Nome*</font></td> <td><br><input type="text" name="mot_nome" value="<?php echo $registro['nome']?>" size="50" maxlength="40"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Telefone*</font></td> <td><input type="text" name="mot_telefone_area" value="<?php echo $registro['telefone_area']?>" size="3" maxlength="2" onkeypress="return isNumero(event)"> <input type="text" name="mot_telefone" value="<?php echo $registro['telefone']?>" size="22" maxlength="8" onkeypress="return isNumero(event)"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Endereço*</font></td> <td><input type="text" name="mot_endereco" value="<?php echo $registro['endereco']?>" size="50" maxlength="40"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Cidade*</font></td> <td> <select name="mot_cidade"> <?php while ($cidade = mysql_fetch_array($cidades)) if ($cidade['codigo'] == $registro['cidade']) echo('<option value="' . $cidade['codigo'] . '" selected>' . $cidade['nome'] . '</option>'); else echo('<option value="' . $cidade['codigo'] . '">' . $cidade['nome'] . '</option>'); ?> </select> </td> </tr> <tr height="22">
<td width="110" align="right"><font face="Arial" size="2">CPF*</font></td> <td><input type="text" name="mot_cpf" value="<?php echo $registro['cpf']?>" size="30" maxlength="11" onkeypress="return isNumero(event)"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">CNH*</font></td> <td><input type="text" name="mot_cnh" value="<?php echo $registro['cnh']?>" size="30" maxlength="16" onkeypress="return isNumero(event)"></td> </tr> <?php if (strlen($registro['cnh_vencimento']) > 0) { $partes = split('-', $registro['cnh_vencimento']); $cnh_dia = $partes[2]; $cnh_mes = $partes[1]; $cnh_ano = $partes[0]; } else { $cnh_dia = 01; $cnh_mes = 01; $cnh_ano = 2006; } ?> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">CNH Vencimento</font></td> <td><input type="text" name="mot_cnh_dia" value="<?php echo $cnh_dia?>" size="2" maxlength="2" onkeypress="return isNumero(event)"> / <input type="text" name="mot_cnh_mes" value="<?php echo $cnh_mes?>" size="2" maxlength="2" onkeypress="return isNumero(event)"> / <input type="text" name="mot_cnh_ano" value="<?php echo $cnh_ano?>" size="5" maxlength="4" onkeypress="return isNumero(event)"> (dd/mm/aaaa)</td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Categoria*</font></td> <td><input type="text" name="mot_categoria" value="<?php echo $registro['categoria']?>" size="3" maxlength="2"></td> </tr> <tr height="22"> <td width="110"></td> <td><br><input type="submit" value="Salvar"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
XIV. motoristas_visualizar.php
Visualiza um motorista já cadastrado.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código do motorista da página de caminhões $codigo = $_GET['id']; // Busca os dados do motorista, de acordo com o código $query = Consulta('select m.*, c.nome as nome_cidade from tbl_motorista m left join tbl_cidade c on (m.cidade=c.codigo) where m.codigo = ' . $codigo);
// Pega os dados do motorista, que resultou da busca $registro = mysql_fetch_array($query); // Busca as cidade no banco de dados // $cidades = Consulta('select * from tbl_cidade order by nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="motoristas_salvar.php" name="form_motorista"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE MOTORISTA</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><br><b>Nome:</b> </font></td> <td><font face="Arial" size="2"><br><?php echo $registro['nome']?></font></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>Telefone:</b> </font></td> <td><font face="Arial" size="2">(<?php echo $registro['telefone_area']?>) - <?php echo $registro['telefone']?></font></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>Endereço:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['endereco']?></font></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>Cidade:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['nome_cidade']?></font></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>CPF:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['cpf']?></font></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>CNH:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['cnh']?></font></td> </tr> <?php if (strlen($registro['cnh_vencimento']) > 0) { $partes = split('-', $registro['cnh_vencimento']); $cnh_dia = $partes[2]; $cnh_mes = $partes[1]; $cnh_ano = $partes[0]; } else { $cnh_dia = 01; $cnh_mes = 01; $cnh_ano = 2006; } ?> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>CNH Vencimento:</b> </font></td> <td><font face="Arial" size="2"><?php echo $cnh_dia?>/<?php echo $cnh_mes?>/<?php echo $cnh_ano?></font></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><b>Categoria:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['categoria']?></font></td> </tr> <tr height="22"> <td width="110"></td> <td><br><input type="button" value="Editar" onClick="location='motoristas_cadastro.php?id=<?php echo $codigo ?>';"><input type="button"
value="Excluir" onClick="location='motoristas_excluir.php?id=<?php echo $codigo ?>';"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
XV. motoristas.php
Exibe a lista de motoristas já cadastrados a partir da escolha da opção Motoristas no menu
principal.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca os motoristas cadastrados no banco de dados $query = Consulta('select m.codigo, m.nome, m.telefone_area, m.telefone, ' . ' c.nome as cidade, m.categoria from tbl_motorista m, tbl_cidade c where c.codigo = m.cidade order by m.nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <table width="570" cellspacing="0" cellpadding="3"> <tr height="22"> <td colspan="3"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE MOTORISTAS</b></font></td> <td colspan="3" align="right"><a href="motoristas_cadastro.php?id=0"><font face="Arial" size="2" color="#0000FF">Novo Motorista</font></a></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="210"><font face="Arial" size="2"><b><u>Nome</u></b></font></td> <td width="90"><font face="Arial" size="2"><b><u>Telefone</u></b></font></td> <td width="110"><font face="Arial" size="2"><b><u>Cidade</u></b></font></td> <td width="50"><font face="Arial" size="2"><b><u>Categoria</u></b></font></td> <td width="60" colspan="2" align="right"><font face="Arial" size="2"><b><u>Opções</u></b></font></td> </tr> <?php $cor = false; while ($registro = mysql_fetch_array($query)) { $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td><font face="Arial" size="2">' . $registro['nome'] . '</font></td>');
if (strlen($registro['telefone_area']) == 0) echo('<td><font face="Arial" size="2">' . $registro['telefone'] . '</font></td>'); else echo('<td><font face="Arial" size="2">(' . $registro['telefone_area'] . ') ' . $registro['telefone'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['cidade'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['categoria'] . '</font></td>'); //echo('<td align="center"><a href="motoristas_cadastro.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Detalhes</font></a></td>'); echo('<td colspan="2" align="center"><a href="motoristas_visualizar.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Visualizar</font></a></td>'); //echo('<td align="center"><a href="motoristas_cadastro.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Editar</font></a></td>'); //echo('<td align="center"><a href="motoristas_excluir.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Excluir</font></a></td>'); echo('</tr>'); } ?> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </body> </html>
XVI. menu.php
Código que exibe o menu principal a partir do usuário se logar ao sistema.
<?php // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="0" topmargin="0"> <br> <table height="100%" width="100%"> <tr><td bgcolor="#DD0000" height="22"><font face="Arial" size="2" color="#FFFFFF"><b> ARQUIVO</b></font></td></tr> <tr><td height="22"><a href="caminhoes.php" target="frame"><font face="Arial" size="2" color="#DD0000"><b>Caminhões</b></font></a></td></tr> <tr><td height="22"><a href="clientes.php" target="frame"><font face="Arial" size="2" color="#DD0000"><b>Clientes</b></font></a></td></tr> <tr><td height="22"><a href="motoristas.php" target="frame"><font face="Arial" size="2" color="#DD0000"><b>Motoristas</b></font></a></td></tr> <tr><td height="22"><a href="cidades.php" target="frame"><font face="Arial" size="2" color="#DD0000"><b>Cidades</b></font></a></td></tr> <tr><td height="22"><a href="entregas.php" target="frame"><font face="Arial" size="2" color="#DD0000"><b>Entregas</b></font></a></td></tr> <tr><td> </td></tr> <tr><td bgcolor="#DD0000" height="22"><font face="Arial" size="2" color="#FFFFFF"><b>OPÇÕES</b></font></td></tr> <tr><td height="22"><a href="roteiros.php" target="frame"><font face="Arial" size="2" color="#DD0000"><b>Roteiros</b></font></a></td></tr> <tr><td height="22"><a href="logout.php" target="_self"><font face="Arial" size="2" color="#DD0000"><b>Sair</b></font></a></td></tr> <tr><td height="99%"></td></tr> </table>
</body> </html>
XVII. main.php
Código principal que a partir deste exibe o menu.
<?php session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) header('location: index.php'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" scroll="no" leftmargin="0" topmargin="0"> <table height="100%" width="100%"> <tr> <td width="150"> <?php include_once('menu.php'); ?> </td> <td> <iframe name="frame" height="100%" width="100%" frameborder="0"> </td> </tr> </table> </body> </html>
XVIII. logout.php
Código para sair do sistema.
<?php session_start(); session_unregister('usuario'); session_destroy(); header('location: index.php'); ?>
XIX. login.php
Código para se logar ao sistema.
<?php require_once('bd.php'); session_start(); session_destroy(); $login = $_POST['usu_login']; $senha = $_POST['usu_senha'];
$query = Consulta('select * from tbl_usuario where login = \'' . $login . '\' and senha = \'' . $senha . '\''); if (mysql_num_rows($query) > 0) { $usuario = array(); $usuario['codigo'] = $query['codigo']; $usuario['login'] = $query['login']; $usuario['senha'] = $query['senha']; session_register('usuario'); header('location: main.php'); } else header('location: index.php?erro=1'); ?>
XX. index.php
Código para a primeira tela, para a partir dela, o usuario se logar.
<?php session_start(); session_destroy(); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA"> <center> <br><br><br> <table cellpadding="15" style="border: solid 1px gray"> <tr><td align="center"> <form action="login.php" method="post"> <br><br> <font face="Arial" size="5" color="#DD0000"> <b><u>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</u></b> </font> <br><br><br> <font face="Arial" size="3" color="#DD0000"> <b>Acesso Restrito</b> </font> <?php if (isset($_GET['erro'])) if ($_GET['erro'] == 1) { echo('<font face="Arial" size="3" color="#0000FF">'); echo('<br><b>Login ou senha inválidos!</b><br>'); echo('</font>'); } ?> <table> <tr> <td><font face="Arial" size="2">Login:</font></td> <td><input type="text" size="25" name="usu_login" maxlength="20"></td> </tr> <tr> <td><font face="Arial" size="2">Senha:</font></td> <td><input type="password" size="25" name="usu_senha" maxlength="20"></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" value="Entrar"></td> </tr>
</table> </center> </form> </td></tr> </table> </body> </html>
XXI. entregas_salvar.php
O código referente este arquivo é utilizado para salvar uma entrega no banco de dados.
<?php require_once('bd.php'); $codigo = $_POST['ent_codigo']; $numero_nota = $_POST['ent_numero_nota']; $cnpj_remetente = $_POST['ent_cnpj_rem']; $cnpj_destinatario = $_POST['ent_cnpj_dest']; $peso = $_POST['ent_peso']; $qtde_volume = $_POST['ent_qtde_vol']; $volume_m3_carga = $_POST['ent_vol_m3_carga']; $data_dia = $_POST['ent_data_dia']; $data_mes = $_POST['ent_data_mes']; $data_ano = $_POST['ent_data_ano']; $data = $data_ano . '/' . $data_mes . '/' . $data_dia; //echo "<script>alert('".$codigo."')</script>"; if ((strlen($numero_nota) < 3) || (strlen($cnpj_remetente) < 14) || (strlen($cnpj_destinatario) < 14) || (strlen($peso) < 1) || (strlen($qtde_volume) < 1) || (strlen($volume_m3_carga) < 1)) exit('<h3>Erro!<br>Os dados não foram informados corretamente!</h3>'); if ($codigo > 0) Consulta('update tbl_entrega set ' . 'numero_nota = \'' . $numero_nota . '\', ' . 'cnpj_remetente = \'' . $cnpj_remetente . '\', ' . 'cnpj_destinatario = \'' . $cnpj_destinatario . '\', ' . 'peso = \'' . $peso . '\', ' . 'qtde_volume = \'' . $qtde_volume . '\', ' . 'data = \'' . $data . '\', ' . 'volume_m3_carga = \'' . $volume_m3_carga . '\'' . 'where codigo = ' . $codigo); else Consulta('insert into tbl_entrega (numero_nota, cnpj_remetente, cnpj_destinatario, peso, qtde_volume, data, volume_m3_carga) values (' . '\'' . $numero_nota . '\', ' . '\'' . $cnpj_remetente . '\', ' . '\'' . $cnpj_destinatario . '\', ' . '\'' . $peso . '\', ' . '\'' . $qtde_volume . '\', ' . '\'' . $data . '\', ' . '\'' . $volume_m3_carga . '\')'); header('location: entregas.php'); ?>
XXII. entregas_excluir.php
Código para excluir uma entrega.
<?php require_once('bd.php'); $codigo = $_GET['id']; if ($codigo > 0) Consulta('delete from tbl_entrega ' . 'where codigo = ' . $codigo);
header('location: entregas.php'); ?>
XXIII. entregas_cadastro.php
Código para cadastrar uma nova entrega.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); //Frame que localiza os Projeto if ( $_GET["frame_busca"] ){ $cnpj = $_GET['cnpj']; $campo = $_GET['campo']; $query = Consulta('select * from tbl_cliente where cnpj_cpf = \'' . $cnpj . '\''); $registro = mysql_fetch_array($query); // $qtde = count($registro); if ( !$registro ) { /* print "<pre>"; print_r($_GET); print "</pre>"; print "<pre>"; print_r($registro); print "</pre>"; */ if ( $campo == 'r' ){ $limpa = " parent.form_entrega.ent_cnpj_rem.value = ''; parent.form_entrega.ent_cnpj_rem.focus();"; }else{ $limpa = " parent.form_entrega.ent_cnpj_dest.value = ''; parent.form_entrega.ent_cnpj_dest.focus();"; } echo "<script> alert('O cliente referente à este CNPJ ainda não está cadastrado, efetue o cadastro para continuar'); $limpa window.open('clientes_cadastro.php?id=0','','resizable=no,toolbar=no,status=no,menubar=no,scrollbars=yes,width=640,height=400'); </script>\n"; } exit; } // Recebe o código da entrega da página de entregas $codigo = $_GET['id']; // Busca os dados da entrega, de acordo com o código $query = Consulta('select * from tbl_entrega where ativo = 1 and codigo = ' . $codigo); // Pega os dados da entrega, que resultou da busca $registro = mysql_fetch_array($query); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title>
<script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="entregas_salvar.php" name="form_entrega"> <input type="hidden" name="ent_codigo" value="<?php echo $registro['codigo']?>"> <iframe name="i_localiza" width="0" height="0" border="0"></iframe> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE ENTREGA</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr><td height="22" colspan="7"><font face="Arial" size="2"><br>Os campos marcados com asterisco (*) são obrigatórios.</font></td></tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><br>Número Nota*:</font></td> <td><br><input type="text" name="ent_numero_nota" value="<?php echo $registro['numero_nota']?>" size="30" maxlength="50"></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2">CNPJ Remetente*:</font></td> <td><input type="text" name="ent_cnpj_rem" value="<?php echo $registro['cnpj_remetente']?>" size="30" OnChange="busca_cliente(this.value, 'r');" maxlength="14"></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2">CNPJ Destinatário*:</font></td> <td><input type="text" name="ent_cnpj_dest" value="<?php echo $registro['cnpj_destinatario']?>" size="30" OnChange="busca_cliente(this.value, 'd');" maxlength="14"></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2">Peso*:</font></td> <td><input type="text" name="ent_peso" value="<?php echo $registro['peso']?>" size="30" maxlength="30"></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2">Qtde Volume*:</font></td> <td><input type="text" name="ent_qtde_vol" value="<?php echo $registro['qtde_volume']?>" size="30" maxlength="30"></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2">Volume em m3*:</font></td> <td><input type="text" name="ent_vol_m3_carga" value="<?php echo $registro['volume_m3_carga']?>" size="30" maxlength="30"></td> </tr> <?php if (strlen($registro['data']) > 0) { $partes = split('-', $registro['data']); $data_dia = $partes[2]; $data_mes = $partes[1]; $data_ano = $partes[0]; } else { $data_dia = 01; $data_mes = 01; $data_ano = 2006; } ?> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2">Data*:</font></td> <td> <input type="text" name="ent_data_dia" value="<?php echo $data_dia?>" size="2" maxlength="2" onkeypress="return isNumero(event)"> / <input type="text" name="ent_data_mes" value="<?php echo $data_mes?>" size="2" maxlength="2" onkeypress="return isNumero(event)"> / <input type="text" name="ent_data_ano" value="<?php echo $data_ano?>" size="5" maxlength="4" onkeypress="return isNumero(event)"> (dd/mm/aaaa) </td> </tr> <tr height="22"> <td width="120"></td> <td><br><input type="submit" value="Salvar"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td>
</tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> <script> function busca_cliente(valor, campo){ if ( valor != '' ){ i_localiza.location="entregas_cadastro.php?frame_busca=sim&cnpj="+valor+"&campo="+campo; } } </script> </body> </html>
XXIV. entregas_visualizar.php
Visualiza uma entrega já cadastrada.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código da entrega da página de entregas $codigo = $_GET['id']; // Busca os dados da entrega, de acordo com o código $query = Consulta('select * from tbl_entrega where ativo = 1 and codigo = ' . $codigo); // Pega os dados da entrega, que resultou da busca $registro = mysql_fetch_array($query); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="entregas_salvar.php" name="form_entrega"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE ENTREGA</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><br><b>Número Nota:</b> </font></td> <td><font face="Arial" size="2"><br><?php echo $registro['numero_nota']?></font></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><b>CNPJ Remetente:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['cnpj_remetente']?></font></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><b>CNPJ Destinatário:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['cnpj_destinatario']?></font></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><b>Peso:</b></font></td> <td><font face="Arial" size="2"><?php echo $registro['peso']?></font></td>
</tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><b>Qtde Volume:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['qtde_volume']?></font></td> </tr> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><b>Volume em m3:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['volume_m3_carga']?></font></td> </tr> <?php if (strlen($registro['data']) > 0) { $partes = split('-', $registro['data']); $data_dia = $partes[2]; $data_mes = $partes[1]; $data_ano = $partes[0]; } else { $data_dia = 01; $data_mes = 01; $data_ano = 2006; } ?> <tr height="22"> <td width="120" align="right"><font face="Arial" size="2"><b>Data:</b> </font></td> <td><font face="Arial" size="2"><?php echo $data_dia?>/<?php echo $data_mes?>/<?php echo $data_ano?></font></td> </tr> <tr height="22"> <td width="120"></td> <td><br><input type="button" value="Editar" onClick="location='entregas_cadastro.php?id=<?php echo $codigo ?>';"><input type="button" value="Excluir" onClick="location='entregas_excluir.php?id=<?php echo $codigo ?>';"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
XXV. entregas.php
Exibe a lista de entregas já cadastradas a partir da escolha da opção Entergas no menu
principal.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca as cidade no banco de dados $query = Consulta('select * from tbl_entrega where ativo = 1 order by numero_nota'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0">
<br> <table width="550"> <tr height="22"> <td colspan="3"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE ENTREGAS</b></font></td> <td colspan="3" align="right"><a href="entregas_cadastro.php?id=0"><font face="Arial" size="2" color="#0000FF">Nova Entrega</font></a></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="150"><font face="Arial" size="2"><b><u>Número Nota</u></b></font></td> <td width="145"><font face="Arial" size="2"><b><u>CNPJ Remetente</u></b></font></td> <td width="145"><font face="Arial" size="2"><b><u>CNPJ Destinatário</u></b></font></td> <td width="60" colspan="3" align="right"><font face="Arial" size="2"><b><u>Opções</u></b></font></td> </tr> <?php $cor = false; while ($registro = mysql_fetch_array($query)) { $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td><font face="Arial" size="2">' . $registro['numero_nota'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['cnpj_remetente'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['cnpj_destinatario'] . '</font></td>'); //echo('<td align="center"><a href="entregas_cadastro.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Detalhes</font></a></td>'); //echo('<td align="center"><a href="entregas_excluir.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Excluir</font></a></td>'); echo('<td colspan="2" align="center"><a href="entregas_visualizar.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Visualizar</font></a></td>'); echo('</tr>'); } ?> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </body> </html>
XXVI. clientes_salvar.php
O código referente este arquivo é utilizado para salvar um cliente no banco de dados.
<?php require_once('bd.php'); $codigo = $_POST['cli_codigo']; $nome = $_POST['cli_nome']; $endereco = $_POST['cli_endereco']; $telefone_area = $_POST['cli_telefone_area']; $telefone = $_POST['cli_telefone']; $cidade = $_POST['cli_cidade']; $cnpj = $_POST['cli_cnpj']; $inscricao = $_POST['cli_inscricao']; $email = $_POST['cli_email']; if ((strlen($nome) < 3) || (strlen($endereco) < 3) || (strlen($telefone) < 7) || (strlen($cnpj) < 11)) exit('<h3>Erro!<br>Os dados não foram informados corretamente!</h3>'); if ($codigo > 0) Consulta('update tbl_cliente set ' .
'nome = \'' . $nome . '\', ' . 'endereco = \'' . $endereco . '\', ' . 'telefone_area = \'' . $telefone_area . '\', ' . 'telefone = \'' . $telefone . '\', ' . 'cidade = ' . $cidade . ', ' . 'cnpj_cpf = \'' . $cnpj . '\', ' . 'inscricao = \'' . $inscricao . '\', ' . 'email = \'' . $email . '\'' . 'where codigo = ' . $codigo); else Consulta('insert into tbl_cliente (nome,endereco,telefone_area,telefone,cidade,cnpj_cpf,inscricao,email) values (' . '\'' . $nome . '\', ' . '\'' . $endereco . '\', ' . '\'' . $telefone_area . '\', ' . '\'' . $telefone . '\', ' . '' . $cidade . ', ' . '\'' . $cnpj . '\', ' . '\'' . $inscricao . '\', ' . '\'' . $email . '\')'); header('location: clientes.php'); ?>
XXVII. clientes_excluir.php
Código para excluir um cliente.
<?php require_once('bd.php'); $codigo = $_GET['id']; if ($codigo > 0) Consulta('delete from tbl_cliente ' . 'where codigo = ' . $codigo); header('location: clientes.php'); ?>
XXVIII. clientes_cadastro.php
Código para cadastrar um novo cliente.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código do cliente da página de clientes $codigo = $_GET['id']; // Busca os dados do cliente, de acordo com o código $query = Consulta('select * from tbl_cliente where codigo = ' . $codigo); // Pega os dados do cliente, que resultou da busca $registro = mysql_fetch_array($query); // Busca as cidade no banco de dados $cidades = Consulta('select * from tbl_cidade order by nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title>
<script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="clientes_salvar.php" name="form_cliente"> <input type="hidden" name="cli_codigo" value="<?php echo $registro['codigo']?>"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CLIENTE</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr><td height="22" colspan="7"><font face="Arial" size="2"><br>Os campos marcados com asterisco (*) são obrigatórios.</font></td></tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2"><br>Nome*</font></td> <td><br><input type="text" name="cli_nome" value="<?php echo $registro['nome']?>" size="50" maxlength="40"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Telefone*</font></td> <td><input type="text" name="cli_telefone_area" value="<?php echo $registro['telefone_area']?>" size="3" maxlength="2" onkeypress="return isNumero(event)"> <input type="text" name="cli_telefone" value="<?php echo $registro['telefone']?>" size="22" maxlength="8" onkeypress="return isNumero(event)"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Endereço*</font></td> <td><input type="text" name="cli_endereco" value="<?php echo $registro['endereco']?>" size="50" maxlength="40"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">Cidade*</font></td> <td> <select name="cli_cidade"> <?php while ($cidade = mysql_fetch_array($cidades)) if ($cidade['codigo'] == $registro['cidade']) echo('<option value="' . $cidade['codigo'] . '" selected>' . $cidade['nome'] . '</option>'); else echo('<option value="' . $cidade['codigo'] . '">' . $cidade['nome'] . '</option>'); ?> </select> </td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">CNPJ/CPF*</font></td> <td><input type="text" name="cli_cnpj" value="<?php echo $registro['cnpj_cpf']?>" size="30" maxlength="14" onkeypress="return isNumero(event)"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2" nowrap>Inscrição Estadual</font></td> <td><input type="text" name="cli_inscricao" value="<?php echo $registro['inscricao']?>" size="30" maxlength="18" onkeypress="return isNumero(event)"></td> </tr> <tr height="22"> <td width="110" align="right"><font face="Arial" size="2">E-mail</font></td> <td><input type="text" name="cli_email" value="<?php echo $registro['email']?>" size="50" maxlength="40"></td> </tr> <tr height="22"> <td width="110"></td> <td><br><input type="submit" value="Salvar"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
XXIX. clientes_visualizar.php
Visualiza um cliente já cadastrado.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código do cliente da página de clientes $codigo = $_GET['id']; // Busca os dados do cliente, de acordo com o código $query = Consulta('select p.*, c.nome as nome_cidade from tbl_cliente p left join tbl_cidade c on (p.cidade=c.codigo) where p.codigo = ' . $codigo); // Pega os dados do cliente, que resultou da busca $registro = mysql_fetch_array($query); // Busca as cidade no banco de dados // $cidades = Consulta('select * from tbl_cidade order by nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="clientes_salvar.php" name="form_cliente"> <input type="hidden" name="cli_codigo" value="<?php echo $registro['codigo']?>"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CLIENTE</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2"><br><b>Nome:</b></font></td> <td><br><font face="Arial" size="2"><?php echo $registro['nome']?></td> </tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2"><b>Telefone:</b></font></td> <td><font face="Arial" size="2">(<?php echo $registro['telefone_area']?>) <?php echo $registro['telefone']?></td> </tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2"><b>Endereço:</b></font></td> <td><font face="Arial" size="2"><?php echo $registro['endereco']?></td> </tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2"><b>Cidade:</b></font></td> <td><font face="Arial" size="2"><?php echo $registro['nome_cidade']?></td> </td> </tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2"><b>CNPJ/CPF:</b></font></td> <td><font face="Arial" size="2"><?php echo $registro['cnpj_cpf']?></td> </tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2" nowrap><b>Inscrição Estadual:</b></font></td> <td><font face="Arial" size="2"><?php echo $registro['inscricao']?></td> </tr> <tr height="22"> <td width="140" align="right"><font face="Arial" size="2"><b>E-mail:</b></font></td> <td><font face="Arial" size="2"><?php echo $registro['email']?></td>
</tr> <tr height="22"> <td width="110"></td> <td><br><input type="button" value="Editar" onClick="location='clientes_cadastro.php?id=<?php echo $codigo ?>';"> <input type="button" value="Excluir" onClick="location='clientes_excluir.php?id=<?php echo $codigo ?>';"> <input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
XXX. clientes.php
Exibe a lista de clientes já criados a partir da escolha da opção Clientes no menu principal.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca os clientes cadastrados no banco de dados $query = Consulta('select p.codigo, p.nome, p.telefone_area, p.telefone, ' . ' c.nome as cidade from tbl_cliente p, tbl_cidade c where c.codigo = p.cidade order by p.nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <table width="570" cellspacing="0" cellpadding="3"> <tr height="22"> <td colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CLIENTES</b></font></td> <td colspan="3" align="right"><a href="clientes_cadastro.php?id=0"><font face="Arial" size="2" color="#0000FF">Novo Cliente</font></a></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="4"></td></tr> <tr height="22"> <td width="210"><font face="Arial" size="2"><b><u>Nome</u></b></font></td> <td width="100"><font face="Arial" size="2"><b><u>Telefone</u></b></font></td> <td width="160"><font face="Arial" size="2"><b><u>Cidade</u></b></font></td> <td width="60" align="right"><font face="Arial" size="2"><b><u>Opções</u></b></font></td> </tr> <?php $cor = false; while ($registro = mysql_fetch_array($query)) { $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td><font face="Arial" size="2">' . $registro['nome'] . '</font></td>');
if (strlen($registro['telefone_area']) == 0) echo('<td><font face="Arial" size="2">' . $registro['telefone'] . '</font></td>'); else echo('<td><font face="Arial" size="2">(' . $registro['telefone_area'] . ') ' . $registro['telefone'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['cidade'] . '</font></td>'); echo('<td align="center"><a href="clientes_visualizar.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Visualizar</font></a></td>'); // echo('<td align="center"><a href="clientes_cadastro.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Detalhes</font></a></td>'); // echo('<td align="center"><a href="clientes_excluir.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Excluir</font></a></td>'); echo('</tr>'); } ?> <tr><td bgcolor="#DD0000" height="1" colspan="4"></td></tr> </table> </body> </html>
XXXI. cidades.php
Exibe a lista de cidades que a empresa engloba a partir da escolha da opção Cidades no
menu principal.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca as cidade no banco de dados $query = Consulta('select c.nome, c.codigo, e.sigla from tbl_cidade c left join tbl_estado e on (c.estado=e.codigo) order by c.nome'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <table width="550"> <tr height="22"> <td ><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CIDADES</b></font></td> <td colspan="3" align="right"><a href="cidades_cadastro.php?id=0"><font face="Arial" size="2" color="#0000FF">Nova Cidade</font></a></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> <tr height="22"> <td width="340"><font face="Arial" size="2"><b><u>Nome</u></b></font></td> <td width="100"><font face="Arial" size="2"><b><u>Estado</u></b></font></td> <td width="60" colspan="2" align="right"><font face="Arial" size="2"><b><u>Opções</u></b></font></td> </tr> <?php $cor = false;
while ($registro = mysql_fetch_array($query)) { $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td><font face="Arial" size="2">' . $registro['nome'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['sigla'] . '</font></td>'); //echo('<td align="center"><a href="cidades_cadastro.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Detalhes</font></a></td>'); //echo('<td align="center"><a href="cidades_excluir.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Excluir</font></a></td>'); echo('<td colspan="2" align="center"><a href="cidades_visualizar.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Visualizar</font></a></td>'); echo('</tr>'); } ?> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </body> </html>
XXXII. cidades_salvar.php
O código referente este arquivo é utilizado para salvar uma cidade no banco de dados.
<?php require_once('bd.php'); $codigo = $_POST['cid_codigo']; $nome = $_POST['cid_nome']; $estado = $_POST['cid_estado']; //echo "<script>alert('".$codigo."')</script>"; if ((strlen($nome) < 3)) exit('<h3>Erro!<br>Os dados não foram informados corretamente!</h3>'); if ($codigo > 0) Consulta('update tbl_cidade set ' . 'nome = \'' . $nome . '\', ' . 'estado = \'' . $estado . '\'' . 'where codigo = ' . $codigo); else Consulta('insert into tbl_cidade (nome,estado) values (' . '\'' . $nome . '\', ' . '\'' . $estado . '\')'); header('location: cidades.php'); ?>
XXXIII. cidades_excluir.php
Código para excluir uma cidade.
<?php require_once('bd.php'); $codigo = $_GET['id']; if ($codigo > 0) Consulta('delete from tbl_cidade ' . 'where codigo = ' . $codigo);
header('location: cidades.php'); ?>
XXXIV. cidades_cadastro.php
Código para cadastrar uma nova cidade.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código da cidade da página de cidades $codigo = $_GET['id']; // Busca os dados da cidade, de acordo com o código $query = Consulta('select * from tbl_cidade where codigo = ' . $codigo); // Pega os dados da cidade, que resultou da busca $registro = mysql_fetch_array($query); // Busca as cidade no banco de dados $estados = Consulta('select * from tbl_estado order by sigla'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="cidades_salvar.php" name="form_cidade"> <input type="hidden" name="cid_codigo" value="<?php echo $registro['codigo']?>"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CIDADE</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr><td height="22" colspan="7"><font face="Arial" size="2"><br>Os campos marcados com asterisco (*) são obrigatórios.</font></td></tr> <tr height="22"> <td width="80" align="right"><font face="Arial" size="2"><br>Nome*:</font></td> <td><br><input type="text" name="cid_nome" value="<?php echo $registro['nome']?>" size="50" maxlength="50"></td> </tr> <tr height="22"> <td width="80" align="right"><font face="Arial" size="2">Estado*:</font></td> <td> <select name="cid_estado"> <?php while ($estado = mysql_fetch_array($estados)) if ($estado['codigo'] == $registro['estado']) echo('<option value="' . $estado['codigo'] . '" selected>' . $estado['sigla'] . '</option>'); else echo('<option value="' . $estado['codigo'] . '">' . $estado['sigla'] . '</option>'); ?> </select> </td> </tr> <tr height="22"> <td width="80"></td> <td><br><input type="submit" value="Salvar"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr>
<tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
XXXV. cidades_visualizar.php
Visualiza uma cidade cadastrada.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código da cidade da página de cidades $codigo = $_GET['id']; // Busca os dados da cidade, de acordo com o código //$query = Consulta('select * from tbl_cidade where codigo = ' . $codigo); $query = Consulta('select c.*, e.sigla from tbl_cidade c inner join tbl_estado e on (c.estado=e.codigo) where c.codigo = ' . $codigo); // Pega os dados da cidade, que resultou da busca $registro = mysql_fetch_array($query); // Busca as cidade no banco de dados $estados = Consulta('select * from tbl_estado order by sigla'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <form method="post" action="cidades_salvar.php" name="form_cidade"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CIDADE</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr height="22"> <td width="80" align="right"><font face="Arial" size="2"><br><b>Nome:</b> </font></td> <td><font face="Arial" size="2"><br><?php echo $registro['nome']?></font></td> </tr> <tr height="22"> <td width="80" align="right"><font face="Arial" size="2"><b>Estado:</b> </font></td> <td><font face="Arial" size="2"><?php echo $registro['sigla']?></font></td> </tr> <tr height="22"> <td width="80"></td> <td><br><input type="button" value="Editar" onClick="location='cidades_cadastro.php?id=<?php echo $codigo ?>';"><input type="button" value="Excluir" onClick="location='cidades_excluir.php?id=<?php echo $codigo ?>';"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body>
</html>
XXXVI. caminhoes.php
Exibe a lista de caminhões já cadastrados a partir da escolha da opção Caminhões no menu
principal.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Busca os caminhões cadastrados no banco de dados $query = Consulta('select cam.codigo, cam.placa, cam.tara, cam.volume, tipo.codigo AS tipo, tipo.descricao ' . ' from tbl_caminhao cam, tbl_caminhao_tipo tipo where (tipo.codigo=cam.tipo) ' . ' order by cam.placa'); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0"> <br> <table width="570" cellspacing="0" cellpadding="3"> <tr height="22"> <td colspan="3"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CAMINHÕES </b></font></td> <td colspan="3" align="right"><a href="caminhoes_cadastro.php?id=0&tipo_caminhao=5"><font face="Arial" size="2" color="#0000FF">Novo Caminhão</font></a></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="5"></td></tr> <tr height="22"> <td width="100"><font face="Arial" size="2"><b><u>Placa</u></b></font></td> <td width="90"><font face="Arial" size="2"><b><u>Tara (Kg)</u></b></font></td> <td width="150"><font face="Arial" size="2"><b><u>Volume Baú (m3)</u></b></font></td> <td width="120"><font face="Arial" size="2"><b><u>Tipo</u></b></font></td> <td width="60" colspan="2" align="right"><font face="Arial" size="2"><b><u>Opções</u></b></font></td> </tr> <?php $cor = false; while ($registro = mysql_fetch_array($query)) { $cor = !$cor; if ($cor) echo('<tr height="22" valign="top" bgcolor="#EAEAEA">'); else echo('<tr height="22" valign="top">'); echo('<td><font face="Arial" size="2">' . $registro['placa'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['tara'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['volume'] . '</font></td>'); echo('<td><font face="Arial" size="2">' . $registro['descricao'] . '</font></td>'); echo('<td align="center"><a href="caminhoes_visualizar.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Visualizar</font></a></td>'); // echo('<td align="center"><a href="caminhoes_cadastro.php?id=' . $registro['codigo'] . '&tipo_caminhao=' . $registro['tipo'] . '"><font face="Arial" size="2" color="#0000FF">Detalhes</font></a></td>'); // echo('<td align="center"><a href="caminhoes_excluir.php?id=' . $registro['codigo'] . '"><font face="Arial" size="2" color="#0000FF">Excluir</font></a></td>');
echo('</tr>'); } ?> <tr><td bgcolor="#DD0000" height="1" colspan="5"></td></tr> </table> </body> </html>
XXXVII. caminhoes_salvar.php
O código referente este arquivo é utilizado para salvar um caminhão no banco de dados.
<?php require_once('bd.php'); $codigo = $_POST['cam_codigo']; $placa = strtoupper($_POST['cam_placa']); $chassis = strtoupper($_POST['cam_chassis']); $tara = $_POST['cam_tara']; $volume = $_POST['cam_volume']; $tipo = $_POST['cam_tipo']; $marca = $_POST['cam_marca']; $ano = $_POST['cam_ano']; $cor = $_POST['cam_cor']; if ((strlen($placa) < 7) || (strlen($chassis) < 1) || (!is_numeric($tara)) || (!is_numeric($volume))) exit('<h3>Erro!<br>Os dados não foram informados corretamente!</h3>'); if ($codigo > 0) Consulta('update tbl_caminhao set ' . 'placa = \'' . $placa . '\', ' . 'chassis = \'' . $chassis . '\', ' . 'tara = \'' . $tara . '\', ' . 'volume = \'' . $volume . '\', ' . 'tipo = \'' . $tipo . '\', ' . 'marca = \'' . $marca . '\', ' . 'ano = \'' . $ano . '\', ' . 'cor = \'' . $cor . '\'' . 'where codigo = ' . $codigo); else Consulta('insert into tbl_caminhao (placa,chassis,tara,volume,tipo,marca,ano,cor) values (' . '\'' . $placa . '\', ' . '\'' . $chassis . '\', ' . '\'' . $tara . '\', ' . '\'' . $volume . '\', ' . '\'' . $tipo . '\', ' . '\'' . $marca . '\', ' . '\'' . $ano . '\', ' . '\'' . $cor . '\')'); header('location: caminhoes.php'); ?>
XXXVIII. caminhoes_excluir.php
Código para excluir um caminhão.
<?php require_once('bd.php'); $codigo = $_GET['id']; if ($codigo > 0) Consulta('delete from tbl_caminhao ' . 'where codigo = ' . $codigo);
header('location: caminhoes.php'); ?>
XXXIX. caminhoes_cadastro.php
Código para cadastrar um novo caminhão.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código do caminhão da página de caminhões $codigo = $_GET['id']; // Busca os dados do caminhão, de acordo com o código $query = Consulta('select * from tbl_caminhao where codigo = ' . $codigo); // Busca os tipos de caminhão disponíveis $tipos_caminhao = Consulta('select * from tbl_caminhao_tipo order by descricao '); // Pega os dados do caminhão, que resultou da busca $registro = mysql_fetch_array($query); if ($_GET['tipo_caminhao'] && $_GET['carregar']) { $pesos = array(0, 0); switch ($_GET['tipo_caminhao']) { case 1: $pesos = array(10000, 17000); break; case 2: $pesos = array(4500, 6000); break; case 3: $pesos = array(25000, 30000); break; case 4: $pesos = array(0, 0); break; case 5: $pesos = array(3000, 4000); break; } $html = "<select name=\"cam_tara\">"; for ($index = $pesos[0]; $index <= $pesos[1]; $index += 500) if ($index == $registro['tara']) $html .= "<option value=\"$index\" selected>$index</option>"; else $html .= "<option value=\"$index\">$index</option>"; $html .= "</select>"; echo "<script> parent.divPeso.innerHTML = '$html'; </script>\n"; exit; } ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> <script> function atualiza_pesos(valor) { if (!isNaN(valor)) i_localiza.location="caminhoes_cadastro.php?id=<?php echo $_GET['id'] ?>&tipo_caminhao=" + valor + "&carregar=1";
} </script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0" onLoad="atualiza_pesos( <?php echo $_GET['tipo_caminhao'] ?> )"> <br> <iframe name="i_localiza" width="0" height="0" border="0"></iframe> <form method="post" action="caminhoes_salvar.php" name="form_caminhao"> <input type="hidden" name="cam_codigo" value="<?php echo $registro['codigo']?>"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CAMINHÃO</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr><td height="22" colspan="2"><font face="Arial" size="2"><br>Os campos marcados com asterisco (*) são obrigatórios.<br><br></font></td></tr> <tr> <td align="right"><font face="Arial" size="2">Tipo*</font></td> <td> <select name="cam_tipo" onChange="atualiza_pesos(this.value);"> <?php while ($tipo = mysql_fetch_array($tipos_caminhao)) if ($tipo['codigo'] == $registro['tipo']) echo('<option value="' . $tipo['codigo'] . '" selected>' . $tipo['descricao'] . '</option>'); else echo('<option value="' . $tipo['codigo'] . '">' . $tipo['descricao'] . '</option>'); ?> </select> </td> </tr> <tr> <td align="right"><font face="Arial" size="2">Placa*</font></td> <td><input type="text" name="cam_placa" value="<?php echo $registro['placa']?>" size="10" maxlength="7"></td> </tr> <tr> <td align="right"><font face="Arial" size="2">Chassis*</font></td> <td><input type="text" name="cam_chassis" value="<?php echo $registro['chassis']?>" size="25" maxlength="20"></td> </tr> <tr> <td align="right"><font face="Arial" size="2">Tara (Kg)*</font></td> <td> <div id="divPeso"> Selecione o tipo de caminhão </div> </td> </tr> <tr> <td align="right" nowrap><font face="Arial" size="2">Volume Baú (m3)*</font></td> <td><input type="text" name="cam_volume" value="<?php echo $registro['volume']?>" size="8" maxlength="3" onKeyPress="return isNumero(event)"></td> </tr> <tr> <td align="right"><font face="Arial" size="2">Marca</font></td> <td><input type="text" name="cam_marca" value="<?php echo $registro['marca']?>" size="25" maxlength="20"></td> </tr> <tr> <td align="right"><font face="Arial" size="2">Ano</font></td> <td><input type="text" name="cam_ano" value="<?php echo $registro['ano']?>" size="10" maxlength="4" onKeyPress="return isNumero(event)"></td> </tr> <tr> <td align="right"><font face="Arial" size="2">Cor</font></td> <td><input type="text" name="cam_cor" value="<?php echo $registro['cor']?>" size="25" maxlength="20"></td> </tr> <tr> <td ></td> <td><br><input type="submit" value="Salvar"><input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html>
<?php ?>
XL. caminhões_visualizar.php
Visualiza um caminhão cadastrado.
<?php require_once('bd.php'); session_start(); // Verifica se o usuário está logado no sistema if (!session_is_registered('usuario')) exit('Erro, a página não pode ser carregada!'); // Recebe o código do caminhão da página de caminhões $codigo = $_GET['id']; // Busca os dados do caminhão, de acordo com o código $query = Consulta('select c.*, t.descricao from tbl_caminhao c left join tbl_caminhao_tipo t on (c.tipo=t.codigo) where c.codigo = ' . $codigo); // Busca os tipos de caminhão disponíveis // $tipos_caminhao = Consulta('select * from tbl_caminhao_tipo order by descricao '); // Pega os dados do caminhão, que resultou da busca $registro = mysql_fetch_array($query); ?> <html encoding="ISO-8859-1"> <head> <title>SISTEMA DE ROTEIRIZAÇÃO DE ENTREGAS</title> <script type="text/javascript" src="scripts.js"></script> </head> <body bgcolor="#FAFAFA" leftmargin="30" topmargin="0" onLoad="atualiza_pesos( <?php echo $_GET['tipo_caminhao'] ?> )"> <br> <iframe name="i_localiza" width="0" height="0" border="0"></iframe> <form method="post" action="caminhoes_salvar.php" name="form_caminhao"> <input type="hidden" name="cam_codigo" value="<?php echo $registro['codigo']?>"> <table width="550"> <tr><td height="22" colspan="2"><font face="Arial" size="2" color="#DD0000"><b> CADASTRO DE CAMINHÃO</b></font></td></tr> <tr><td bgcolor="#DD0000" height="1" colspan="7"></td></tr> <tr> <td align="right"><font face="Arial" size="2"><br><b>Tipo:</font></td> <td><font face="Arial" size="2"><br><?php echo $registro['descricao']?></td> </tr> <tr> <td align="right"><font face="Arial" size="2"><b>Placa:</font></td> <td><font face="Arial" size="2"><?php echo $registro['placa']?></td> </tr> <tr> <td align="right"><font face="Arial" size="2"><b>Chassis:</font></td> <td><font face="Arial" size="2"><?php echo $registro['chassis']?></td> </tr> <tr> <td align="right"><font face="Arial" size="2"><b>Tara (Kg):</font></td> <td><font face="Arial" size="2"><?php echo $registro['tara']?></td> </tr> <tr> <td align="right" nowrap><font face="Arial" size="2"><b>Volume Baú (m3):</font></td> <td><font face="Arial" size="2"><?php echo $registro['volume']?></td> </tr> <tr> <td align="right"><font face="Arial" size="2"><b>Marca:</font></td> <td><font face="Arial" size="2"><?php echo $registro['marca']?></td>
</tr> <tr> <td align="right"><font face="Arial" size="2"><b>Ano:</font></td> <td><font face="Arial" size="2"><?php echo $registro['ano']?></td> </tr> <tr> <td align="right"><font face="Arial" size="2"><b>Cor:</font></td> <td><font face="Arial" size="2"><?php echo $registro['cor']?></td> </tr> <tr height="22"> <td width="110"></td> <td><br><input type="button" value="Editar" onClick="location='caminhoes_cadastro.php?id=<?php echo $codigo ?>&tipo_caminhao=<?php echo $registro['tipo'] ?>'"> <input type="button" value="Excluir" onClick="location='caminhoes_excluir.php?id=<?php echo $codigo ?>';"> <input type="button" value="Cancelar" onClick="javascript:window.history.go(-1);"><br><br></td> </tr> <tr><td bgcolor="#DD0000" height="1" colspan="6"></td></tr> </table> </form> </body> </html> <?php ?>
XLI. scripts.js
Valida os campos CNPJ, Tara e CPF para que os mesmos sejam somente numéricos.
function isNumero(tecla) { var charCode = (tecla.which) ? tecla.which : event.keyCode if (charCode > 31 && (charCode < 48 || charCode > 57)) return false; return true; } function verificaRoteiroCaminhao() { var tipo_caminhao = document.forms[0].rot_caminhao.options[document.forms[0].rot_caminhao.selectedIndex].id; // Só habilita o campo de Cavalo Mecânico se for carreta var cavalo = document.forms[0].rot_cavalo; cavalo.disabled = (tipo_caminhao != 3); }
Top Related