Skip to content

Commit

Permalink
Adição da versão 3.0
Browse files Browse the repository at this point in the history
Programa e features da versão 3.0
  • Loading branch information
Gui25Reis committed Jun 22, 2021
1 parent da3a1ee commit 8bf26d7
Show file tree
Hide file tree
Showing 17 changed files with 1,155 additions and 331 deletions.
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,34 @@
Programa desenvolvido para a empresa Maria Cacau

## Features
v1.0
### v1.0
- Imagens com as informações entregas para motoboy
- Resumos das entregas do dia escolhido
- Simplificação dos dados da nota fiscal

v1.1
### v1.1
- Menu interação com usuário pelo terminal
- Organização do código

v1.2
### v1.2
- Adição de uma nova funcionalidade no menu: Melhor envio
- Organização do código

v2.0
### v2.0
- Nova funcionalidade: Resumo dos produtos
- Remoção das gerações das imagens de entrega
- Documentação interna no código
- Otimização do código
- Melhoria no Menu de interação


## OBS:
- Arquivo da planílha precisa estar na mesma pasta que o programa
- Arquivos `.txt` são gerados automaticamente
### v3.0
- Reestruturação completa do programa
- Implementação da Interface Gráfica
- Não precisa de dependência python, agora o programa é um executável
- Otimização do código
- Documentação interna do código
- Usuário escolhe a planílha dentro do computador (a partir do template)
- Resumos (pedidos e entregas) são gerados dentro da plataforma
- Dados de Nota Fiscal e Melhor Envio dentro da plataforma.
- Arquivo é usado apenas para leitura
- Tratamento de erros, tanto na planílha quanto na interação do usuário.
323 changes: 0 additions & 323 deletions _main/Contagem 2.0.py

This file was deleted.

31 changes: 31 additions & 0 deletions _main/_versao.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# UTF-8
#

VSVersionInfo(
ffi=FixedFileInfo(
filevers=(5, 0, 0, 0),
prodvers=(5, 0, 0, 0),
mask=0x3f,
flags=0x0,
OS=0x4,
fileType=0x1,
subtype=0x0,
),

kids=[
StringFileInfo([
StringTable(
u'040904B0',
[StringStruct(u'CompanyName', u'KINGS'),
StringStruct(u'FileDescription', u'Análise e filtragem dos dados.'),
StringStruct(u'FileVersion', u'5.0.0'),
StringStruct(u'InternalName', u'MC - Análise'),
StringStruct(u'LegalCopyright', u'COPYRIGHT © 2020 KINGS - MIT License'),
StringStruct(u'OriginalFilename', u'main.exe'),
StringStruct(u'ProductName', u'MC - Análise'),
StringStruct(u'ProductVersion', u'5.0.0')]
)
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]
)
105 changes: 105 additions & 0 deletions _main/analisePlan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
###### Gui Reis - guisreis25@gmail.com ###### COPYRIGHT © 2020 KINGS

# -*- coding: utf-8 -*-

## Classe responsável pela criação das planilhas

# Nessa classe é feita APENAS criação das planilha já com as filtragens necessessárias
# que serão usadas, mas não pe feita nenhuma anáise. Além disso é feito os tratamento de
# erros, sendo cada erro identificado com um código.

## Bibliotecas necessárias:

# Arquivo da análise da planilha
from pandas.core.frame import DataFrame
from pandas import read_excel

# Arquivo local:
from gui_PopUp import Gui_popup

class Analise:
def __init__(self) -> None:
super(Analise, self).__init__()

self.arq:DataFrame = None # Atributo: Guarda a tabela com todas as colunas que VÃO SER USADAS apenas.
self.arqUsados:dict = {} # Atributo: Guarda os Dataframes que já foram filtrados usados!

self.dtsPed:dict = {} # Atributo: Guarda as datas e a quantidade de pedidos

self.colsFiltro:dict = { # Atributo: Guarda as colunas que vão ser usadas no geral
"Sage":['PEDIDO','Modal','Destinatário','CPF','EMAIL','CEP','Rua','Compl.','Bairro','Cidade-UF','$FRETE','TOTAL','TEL','Evento'],
"Envio":['PEDIDO','Modal','NOME COMPRADOR','TEL','EMAIL','CEP','Rua','Compl.','Bairro','Cidade-UF','CPF','Evento'],
"Pula Modal":['MOTOBOY', 'GUARITA', 'FEIRA', 'FABRICA', 'ENTREGA'],
"Entrega":['PEDIDO','Destinatário','Modal','TEL','Quanto\nfalta\npagar?','DATA ENTREGA'],
"Produtos":['PEDIDO','DATA ENTREGA','Modal','TEL','Q1','Prod1','Q2','Prod2','Q3','Prod3','Q4','Prod4','Q5','Prod5','Q6','Prod6','Q7','Prod7','Outro\nEspec.'],
"Belga":['Prod1','Prod2','Prod3','Prod4','Prod5','Prod6','Prod7','Outro\nEspec.','Modal','Evento'],
"gSage":['Destinatário','CPF','EMAIL','CEP','Rua','Compl.','Bairro','Cidade-UF','$FRETE','TOTAL','Belga','PEDIDO','Modal','TEL'],
"gLbl":["NOME", "CPF", "EMAIL", "CEP", "RUA", "COMPL", "BAIRRO", "CIDADE", "FRETE", "TOTAL", "BELGA?", "PEDIDO", "ENTREGA","TEL"]
}
self.allColsFiltro:list = list(set(self.colsFiltro["Sage"] + self.colsFiltro["Envio"] + self.colsFiltro["Entrega"] + self.colsFiltro["Produtos"]))

## Obejto intanciado de da classe local
self.popUp:Gui_popup = Gui_popup() # Atributo: Cria os popUp

## Destruidor: Deleta os atributos
def __del__(self) -> None:
del self.dtsPed, self.colsFiltro, self.allColsFiltro # Deletas os atributos
del self.arq, self.arqUsados, self.popUp

## Método especial: Pega as colunas já filtradas
def getCol(self, k_:str) -> list: return self.colsFiltro[k_] # Retorna as colunas

## Método especial: Pega as colunas já filtradas
def getDts(self) -> dict: return self.dtsPed # Retorna as datas ordenadas

## Método especial: Faz a leitura do arquivo
def setArq(self, local_:str) -> bool:
if (local_ == ""): return False
if ((local_[-5:] != ".xlsx")):
txts = ["Erro na leitura do arquivo",'Arquivo não é ".xlsx"',
f'O arquivo escolhido não é compatível com o programa. Procure um arquivo Excel do tipo ".xlsx" \n\nCódigo do erro: A001']
self.popUp.show_PopUp(txts) # ERRO A001
return False

try:
arq = read_excel(local_) # Faz a leitura do arquivo
self.arq = arq[arq[arq.columns[0]].isnull() == False][self.allColsFiltro] # Tira as linhas em branco (no meio e no final)
except:
txts = ["Erro na leitura do arquivo",'Colunas não encontradas',
f'O arquivo escolhido não é compatível com o programa. Procure o arquivo padrão. \n\nCódigo do erro: A002']
self.popUp.show_PopUp(txts) # ERRO A002
return False

try:
qDts = self.arq["DATA ENTREGA"].value_counts() # Pega a quantidade de datas que tem
dts = qDts.index.tolist()
self.dtsPed = {str(dts[x])[:10]:int(qDts[x]) for x in range(len(dts))}
except:
txts = ["Erro na leitura do arquivo",'Coluna incompatível',
f'Houve um problema ao ler a coluna "DATA ENTREGA". Verifique os dados da coluna e tente novamente. \n\nCódigo do erro: A003']
self.popUp.show_PopUp(txts) # ERRO A003
return False

qLinhas = len(self.arq.index)
if (qLinhas == 0):
txts = ["Erro na leitura do arquivo",'Arquivo vazio',
f'O arquivo está vazio, não tem nenhuma linha para ser lida. \n\nCódigo do erro: A004']
self.popUp.show_PopUp(txts) # ERRO A004
return False

txts = ["Concluído",'Planilha lida com sucesso', f'Foi encontrada(s) {qLinhas} linhas.']
self.popUp.show_PopUp(txts, "I") # Mostra quantas linhas foram lidas

del arq, dts, qDts, txts, qLinhas # Deleta as variáveis locais
return True

## Método especial: Devolve a planilha filtrada
def getArq(self, l_:list, d_:str) -> DataFrame:
if (d_ in self.arqUsados.keys()): return self.arqUsados[d_][l_] # Memoization: verifica se essa tabela já foi filtrada
self.arqUsados[d_] = self.arq.loc[(self.arq['DATA ENTREGA'] == f"{d_} 00:00:00")].reset_index() .drop(columns=['index'])
return self.arqUsados[d_][l_] # Retorna a planilha com as colunas pedidas

## Método especial: Devolve a planilha filtrada com exceções a mais
def getArqDados(self, l_:list, d_:str) -> DataFrame:
arq = self.getArq(l_, d_)
return arq.loc[(arq['Modal'] != 'MOTOBOY') & (arq['Evento'] != 'Amostras')].reset_index() .drop(columns=['index','Evento'])
51 changes: 51 additions & 0 deletions _main/auxFrames.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
###### Gui Reis - guisreis25@gmail.com ###### COPYRIGHT © 2020 KINGS

# -*- coding: utf-8 -*-

## Classe responsável pela criação dos widgets usado na Interface Gráfica

# Nessa classe é criada frames com label, entrada de texto e botão. SSão
# usadas várias vezes dentro dá área de "Notas SAGE" e "Melhor Envio"


## Bibliotecas necessárias:
# Arquivo local:
from auxWidgets import AuxWidgets, QWidget

# GUI:
from PyQt5.QtWidgets import QFrame


class AuxFrame(QFrame, AuxWidgets):
## Construtor: define a super classe e também a janela principal
def __init__(self, wid_:QWidget, nLb_:str, y_:int) -> None:
super(AuxFrame, self).__init__()

self.setGeometry(10, y_, 450, 20)
self.setParent(wid_)

self.gui_Ui(nLb_)

## Destruidor: desaloca os atributos declarados
def __del__(self) -> None:
del self.but, self.txt

## Método: configura a frame
def gui_Ui(self, nLb_:str) -> None:
self.lbl(nLb_, 10, 10, 0, 70, 20, self) # Add label

self.txt = self.lineEdit(10, 80, 0, 330, 20, self) # Add entrada de texto

self.but = self.btsImg(420, 0, 20, 20, self) # Add botão
self.but.clicked.connect(self.bt_action) # Add ação do botão

## Método: ação do botão
def bt_action(self):
self.txt.selectAll() # Seleciona o texto
self.txt.copy() # Copia o texto

## Método especial: pega o texto
def getText(self) -> str: return self.txt.text() # Retorna o texto

## Método especial: define o texto
def setText(self, t_:str) -> None: self.txt.setText(t_) # Define o texto
105 changes: 105 additions & 0 deletions _main/auxWidgets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
###### Gui Reis - guisreis25@gmail.com ###### COPYRIGHT © 2020 KINGS

# -*- coding: utf-8 -*-

## Classe responsável pela criação dos widgets usado na Interface Gráfica

# Nessa classe é criada os widgets personalizados que serão usados em toda
# a interface: botão, etiquetas (labels), estrada de textos, áreas de vizualização
# de textos e gráficos.
# Por ser usados mais de uma vez passa a ser mais otimizado dessa forma.


## Bibliotecas necessárias:
# GUI:
from PyQt5.QtWidgets import QLabel, QPushButton, QGroupBox, QLineEdit, QTextBrowser, QGraphicsView, QWidget, QComboBox
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt


class AuxWidgets:
## Construtor:
def __init__(self) -> None: pass

## Destruidor:
def __del__(self) -> None: pass


## Método: Cria as labels
def lbl(self, txt_:str, tam_:int, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QLabel:
lb = QLabel(txt_, wid_) # Cria uma label
lb.setGeometry(p1_, p2_, p3_, p4_) # Define a posição
lb.setFont(QFont('Arial', tam_)) # Define a fonte
lb.setAlignment(Qt.AlignLeft|Qt.AlignVCenter) # Define o alinhamento
return lb


## Método: Cria botões
def bts(self, txt_:str, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QPushButton:
bt = QPushButton(txt_, wid_) # Cria o botão
bt.setGeometry(p1_, p2_, p3_, p4_) # Define a posição
bt.setFont(QFont('Arial', 10)) # Define a fonte
return bt

## Método: Cria botões com imagem
def btsImg(self, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QPushButton:
btI = QPushButton(parent=wid_) # Cria o botão
btI.setStyleSheet("image : url(images/salvar-icon.png);") # Define a imagem
btI.setGeometry(p1_, p2_, p3_, p4_) # Define a posição
btI.setFont(QFont('Arial', 10)) # Define a fonte
return btI

## Método: Cria a área onde é mostrado e colocado o texto
def lineEdit(self, tam_:int, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QLineEdit:
le = QLineEdit(wid_) # Cria uma entrada de texto
le.setGeometry(p1_, p2_, p3_, p4_) # Define a posição
le.setFont(QFont('Arial', tam_)) # Define a fonte
le.setStyleSheet("background-color: white") # Define a cor de fundo
le.setReadOnly(True) # Não poode editar o conteúdo
return le

## Método: Cria a área onde é mostrado textos grandes
def txtView(self, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QTextBrowser:
tv = QTextBrowser(wid_) # Cria uma vizualização de texto
tv.setGeometry(p1_, p2_, p3_, p4_) # Define a posição
tv.setFont(QFont('Consolas', 10)) # Define a fonte
return tv

## Método: Cria a área onde é mostrado os gráficos
def graphView(self, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QGraphicsView:
gv = QGraphicsView(wid_) # Cria uma vizualização de texto
gv.setGeometry(p1_, p2_, p3_, p4_) # Define a posição
gv.setEnabled(False) # Deixa inativo
return gv

## Método: Cria os "Group Box"
def gBox(self, n_:str, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QGroupBox:
gb = QGroupBox(n_, wid_) # Cria o Gruop Box
gb.setGeometry(p1_, p2_, p3_, p4_) # Define as proporções
gb.setFont(QFont('Arial', 12)) # Define a fonte
gb.setStyleSheet("QGroupBox {border: 1px solid brown;}") # Define a borda
return gb

## Método: Cria uma label e uma entrada de texto
def lblBt(self, n_:str, xLb_:int, xBt_:int, wid_:QWidget) -> QLineEdit:
self.lbl(n_, 11, xLb_, 30, 60, 20, wid_) # Cria a label
txt = self.lineEdit(11, xBt_, 30, 90, 20, wid_) # Cria a entrada de texto
txt.setReadOnly(False) # Permite o usuário digitar
return txt

## Método: Cria uma área de seleção
def cBox(self, p1_:int, p2_:int, p3_:int, p4_:int, wid_:QWidget) -> QComboBox:
gb = QComboBox(wid_) # Cria o Gruop Box
gb.setGeometry(p1_, p2_, p3_, p4_) # Define as proporções
gb.setFont(QFont('Arial', 10)) # Define a fonte
return gb

##### OUTRAS FUNÇÕES #####

## Método: Arruma a data de (aaaa-mm-dd) para (dd/mm/aaaa)
def fixDate(self, d_:str) -> str: return "/".join(reversed(d_.split("-")))

## Método: ação do botão de copiar
def btCopiar_action(self, w_:QTextBrowser):
w_.selectAll() # Seleciona o texto
w_.copy() # Copia o texto
46 changes: 46 additions & 0 deletions _main/guiConsulta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
###### Gui Reis - guisreis25@gmail.com ###### COPYRIGHT © 2020 KINGS

# -*- coding: utf-8 -*-

## Classe responsável pela criação da área de consulta de frete

# Essa classe é responsável pela interface gráfica + toda
# a parte lógica.


## Bibliotecas necessárias:
# Arquivo local:
from auxWidgets import AuxWidgets

# GUI:
from auxWidgets import QWidget


class Gui_ConsFrete(AuxWidgets):
## Construtor: define a super classe e também o grupo
def __init__(self, wid_:QWidget) -> None:
super(Gui_ConsFrete, self).__init__()

self.root = self.gBox("Consulta Frete", 990, 450, 360, 210, wid_) # Cria o Group Box
self.root.setEnabled(False) # v5.0: Deixa inativo

self.gui_Ui() # Chama o método de construção da GUI (Interface Gráfica)


## Destruidor: desaloca os atributos declarados
def __del__(self) -> None:
del self.root # Deleta os atributos
del self.btVeri, self.btCopi, self.resp,self.tOrigem, self.tDestino


## Método: cria e configura a janela
def gui_Ui(self) -> None:
self.tOrigem = self.lblBt("Origem:", 10, 80, self.root) # Cria a label e a entrada de texto

self.tDestino = self.lblBt("Destino:", 195, 260, self.root) # Cria a label e a entrada de texto

self.resp = self.txtView(10, 60, 340, 100, self.root) # Cria área de vizualização de texto

self.btVeri = self.bts("Verificar", 140, 173, 100, 23, self.root) # Cria o botão "Verificar"

self.btCopi = self.bts("Copiar", 250, 173, 100, 23, self.root) # Cria o botão "Copiar"
Loading

0 comments on commit 8bf26d7

Please sign in to comment.