import tkinter as tk
from tkinter import tk, messagebox
import mysql.connector
from mysql.connector
import Error
# configuracao do banco
DB_CONFIG = {
'host': 'localhost',
'user': 'root',
'password': '',
'database': 'loja_conserto'
}
# -dabse ullitarios
def create_database_and_tables():
"""Create the database and tables if they do not exist."""
try:
conn = mysql.connector.connect(
host=DB_CONFIG['host'],
user=DB_CONFIG['user'],
password=DB_CONFIG['password'])
cursor = conn.cursor()
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {DB_CONFIG['database']}")
conn.close()
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS clientes (
id INT AUTO_INCREMENT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
telefone VARCHAR(20),
email VARCHAR(100)
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS servicos (
id INT AUTO_INCREMENT PRIMARY KEY,
cliente_id INT NOT NULL,
descricao TEXT NOT NULL,
valor DECIMAL(10,2) NOT NULL,
status VARCHAR(50) NOT NULL,
FOREIGN KEY (cliente_id) REFERENCES clientes(id)
ON DELETE CASCADE ON UPDATE CASCADE
)
""")
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Database Error", f"Error creating database or tables:\n{e}")
# --- Cliente CRUD ---
def add_cliente(nome, telefone, email):
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("INSERT INTO clientes (nome, telefone, email) VALUES (%s, %s, %s)",
(nome, telefone, email))
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Cliente", f"Erro ao adicionar cliente:\n{e}")
def update_cliente(cliente_id, nome, telefone, email):
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("UPDATE clientes SET nome=%s, telefone=%s, email=%s WHERE id=%s",
(nome, telefone, email, cliente_id))
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Cliente", f"Erro ao atualizar cliente:\n{e}")
def delete_cliente(cliente_id):
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("DELETE FROM clientes WHERE id=%s", (cliente_id,))
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Cliente", f"Erro ao deletar cliente:\n{e}")
def get_clientes():
clientes = []
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("SELECT id, nome, telefone, email FROM clientes ORDER BY nome")
clientes = cursor.fetchall()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Cliente", f"Erro ao carregar clientes:\n{e}")
return clientes
# --- Servico CRUD ---
def add_servico(cliente_id, descricao, valor, status):
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute(
"INSERT INTO servicos (cliente_id, descricao, valor, status) VALUES (%s, %s, %s, %s)",
(cliente_id, descricao, valor, status))
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Serviço", f"Erro ao adicionar serviço:\n{e}")
def update_servico(servico_id, cliente_id, descricao, valor, status):
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute(
"UPDATE servicos SET cliente_id=%s, descricao=%s, valor=%s, status=%s WHERE id=%s",
(cliente_id, descricao, valor, status, servico_id))
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Serviço", f"Erro ao atualizar serviço:\n{e}")
def delete_servico(servico_id):
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute("DELETE FROM servicos WHERE id=%s", (servico_id,))
conn.commit()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Serviço", f"Erro ao deletar serviço:\n{e}")
def get_servicos():
servicos = []
try:
conn = mysql.connector.connect(**DB_CONFIG)
cursor = conn.cursor()
# juntar clientes
cursor.execute("""
SELECT s.id, s.cliente_id, c.nome, s.descricao, s.valor, s.status
FROM servicos s
JOIN clientes c ON s.cliente_id = c.id
ORDER BY s.id DESC
""")
servicos = cursor.fetchall()
cursor.close()
conn.close()
except Error as e:
messagebox.showerror("Erro Serviço", f"Erro ao carregar serviços:\n{e}")
return servicos
# --- GUI ---
class LojaConsertoApp:
def __init__(self, master):
self.master = master
master.title("Loja de Conserto de Computadores")
master.geometry("900x600")
master.configure(bg="#f0f0f0")
style = tk.Style()
style.theme_use('clam')
style.configure('TNotebook.Tab', font=('Segoe UI', 12, 'bold'), padding=[10,5])
# Notebook tabs
self.notebook = tk.Notebook(master)
self.notebook.pack(fill='both', expand=True, padx=10, pady=10)
self.frame_clientes = tk.Frame(self.notebook)
self.frame_servicos = tk.Frame(self.notebook)
self.notebook.add(self.frame_clientes, text="Clientes")
self.notebook.add(self.frame_servicos, text="Serviços")
self.create_cliente_tab()
self.create_servico_tab()
# ------------ Clientes Tab ------------
def create_cliente_tab(self):
frame = self.frame_clientes
# Form fields
form_frame = tk.LabelFrame(frame, text="Cadastro / Edição de Cliente", padding=10)
form_frame.pack(fill='x', padx=10, pady=10)
tk.Label(form_frame, text="Nome *:").grid(row=0, column=0, sticky='w')
self.cliente_nome_var = tk.StringVar()
self.entry_cliente_nome = tk.Entry(form_frame, textvariable=self.cliente_nome_var,
width=40)
self.entry_cliente_nome.grid(row=0, column=1, sticky='w')
tk.Label(form_frame, text="Telefone:").grid(row=1, column=0, sticky='w')
self.cliente_telefone_var = tk.StringVar()
self.entry_cliente_telefone = tk.Entry(form_frame, textvariable=self.cliente_telefone_var,
width=40)
self.entry_cliente_telefone.grid(row=1, column=1, sticky='w')
tk.Label(form_frame, text="Email:").grid(row=2, column=0, sticky='w')
self.cliente_email_var = tk.StringVar()
self.entry_cliente_email = tk.Entry(form_frame, textvariable=self.cliente_email_var,
width=40)
self.entry_cliente_email.grid(row=2, column=1, sticky='w')
# Butons
btn_frame = tk.Frame(form_frame)
btn_frame.grid(row=3, column=0, columnspan=2, pady=10)
self.btn_add_cliente = tk.Buton(btn_frame, text="Adicionar", command=self.add_cliente)
self.btn_add_cliente.grid(row=0, column=0, padx=5)
self.btn_update_cliente = tk.Buton(btn_frame, text="Atualizar",
command=self.update_cliente)
self.btn_update_cliente.grid(row=0, column=1, padx=5)
self.btn_update_cliente.state(['disabled'])
self.btn_delete_cliente = tk.Buton(btn_frame, text="Excluir",
command=self.delete_cliente)
self.btn_delete_cliente.grid(row=0, column=2, padx=5)
self.btn_delete_cliente.state(['disabled'])
self.btn_clear_cliente = tk.Buton(btn_frame, text="Limpar",
command=self.clear_cliente_form)
self.btn_clear_cliente.grid(row=0, column=3, padx=5)
# Treeview lis�ng clientes
list_frame = tk.LabelFrame(frame, text="Clientes Cadastrados", padding=10)
list_frame.pack(fill='both', expand=True, padx=10, pady=10)
columns = ("id", "nome", "telefone", "email")
self.tree_clientes = tk.Treeview(list_frame, columns=columns, show='headings',
selectmode='browse')
for col in columns:
self.tree_clientes.heading(col, text=col.capitalize())
self.tree_clientes.column(col, anchor='center')
self.tree_clientes.pack(fill='both', expand=True)
self.tree_clientes.bind('<<TreeviewSelect>>', self.on_cliente_select)
self.load_clientes()
def load_clientes(self):
for i in self.tree_clientes.get_children():
self.tree_clientes.delete(i)
for cliente in get_clientes():
self.tree_clientes.insert('', 'end', values=cliente)
self.clear_cliente_form()
def add_cliente(self):
nome = self.cliente_nome_var.get().strip()
telefone = self.cliente_telefone_var.get().strip()
email = self.cliente_email_var.get().strip()
if not nome:
messagebox.showwarning("Validação", "O campo Nome é obrigatório.")
return
add_cliente(nome, telefone, email)
messagebox.showinfo("Sucesso", "Cliente adicionado com sucesso.")
self.load_clientes()
self.load_cliente_combobox() # refresh clients combo in services tab
def on_cliente_select(self, event):
selected = self.tree_clientes.focus()
if not selected:
return
values = self.tree_clientes.item(selected, 'values')
self.selected_cliente_id = values[0]
self.cliente_nome_var.set(values[1])
self.cliente_telefone_var.set(values[2])
self.cliente_email_var.set(values[3])
self.btn_update_cliente.state(['!disabled'])
self.btn_delete_cliente.state(['!disabled'])
self.btn_add_cliente.state(['disabled'])
def update_cliente(self):
if not hasattr(self, 'selected_cliente_id'):
return
nome = self.cliente_nome_var.get().strip()
telefone = self.cliente_telefone_var.get().strip()
email = self.cliente_email_var.get().strip()
if not nome:
messagebox.showwarning("Validação", "O campo Nome é obrigatório.")
return
update_cliente(self.selected_cliente_id, nome, telefone, email)
messagebox.showinfo("Sucesso", "Cliente atualizado com sucesso.")
self.load_clientes()
self.load_cliente_combobox() # refresh clients combo in services tab
def delete_cliente(self):
if not hasattr(self, 'selected_cliente_id'):
return
confirm = messagebox.askyesno("Confirmação","Deseja realmente excluir este cliente? Isso também removerá os serviços vinculados.")
if confirm:
delete_cliente(self.selected_cliente_id)
messagebox.showinfo("Sucesso", "Cliente excluÃdo com sucesso.")
self.load_clientes()
self.load_cliente_combobox() # f5
def clear_cliente_form(self):
self.cliente_nome_var.set("")
self.cliente_telefone_var.set("")
self.cliente_email_var.set("")
self.btn_update_cliente.state(['disabled'])
self.btn_delete_cliente.state(['disabled'])
self.btn_add_cliente.state(['!disabled'])
if hasattr(self, 'selected_cliente_id'):
del self.selected_cliente_id
# Also reset selecion in tree
self.tree_clientes.selection_remove(self.tree_clientes.selection())
# ------------ Serviços Tab ------------
def create_servico_tab(self):
frame = self.frame_servicos
# Form fields
form_frame = tk.LabelFrame(frame, text="Cadastro / Edição de Serviço", padding=10)
form_frame.pack(fill='x', padx=10, pady=10)
tk.Label(form_frame, text="Cliente *:").grid(row=0, column=0, sticky='w')
self.servico_cliente_var = tk.StringVar()
self.combo_servico_cliente = tk.Combobox(form_frame,
textvariable=self.servico_cliente_var, state='readonly', width=38)
self.combo_servico_cliente.grid(row=0, column=1, sticky='w')
tk.Label(form_frame, text="Descrição *:").grid(row=1, column=0, sticky='w')
self.servico_descricao_var = tk.StringVar()
self.entry_servico_descricao = tk.Entry(form_frame,
textvariable=self.servico_descricao_var, width=40)
self.entry_servico_descricao.grid(row=1, column=1, sticky='w')
tk.Label(form_frame, text="Valor (R$) *:").grid(row=2, column=0, sticky='w')
self.servico_valor_var = tk.StringVar()
self.entry_servico_valor = tk.Entry(form_frame, textvariable=self.servico_valor_var,
width=40)
self.entry_servico_valor.grid(row=2, column=1, sticky='w')
tk.Label(form_frame, text="Status *:").grid(row=3, column=0, sticky='w')
self.servico_status_var = tk.StringVar()
self.combo_servico_status = tk.Combobox(form_frame,
textvariable=self.servico_status_var, state='readonly',
values=["Recebido", "Em andamento", "ConcluÃdo", "Entregue",
"Cancelado"], width=37)
self.combo_servico_status.grid(row=3, column=1, sticky='w')
self.combo_servico_status.current(0)
# Butons
btn_frame = tk.Frame(form_frame)
btn_frame.grid(row=4, column=0, columnspan=2, pady=10)
self.btn_add_servico = tk.Buton(btn_frame, text="Adicionar",
command=self.add_servico)
self.btn_add_servico.grid(row=0, column=0, padx=5)
self.btn_update_servico = tk.Buton(btn_frame, text="Atualizar",
command=self.update_servico)
self.btn_update_servico.grid(row=0, column=1, padx=5)
self.btn_update_servico.state(['disabled'])
self.btn_delete_servico = tk.Buton(btn_frame, text="Excluir",
command=self.delete_servico)
self.btn_delete_servico.grid(row=0, column=2, padx=5)
self.btn_delete_servico.state(['disabled'])
self.btn_clear_servico = tk.Buton(btn_frame, text="Limpar",
command=self.clear_servico_form)
self.btn_clear_servico.grid(row=0, column=3, padx=5)
# Treeview listing serviços
list_frame = tk.LabelFrame(frame, text="Serviços Cadastrados", padding=10)
list_frame.pack(fill='both', expand=True, padx=10, pady=10)
columns = ("id", "cliente_id", "cliente_nome", "descricao", "valor", "status")
# adding cliente_id as a hidden column (for mapping and selecting)
self.tree_servicos = tk.Treeview(list_frame, columns=columns, show='headings',
selectmode='browse')
self.tree_servicos.heading("id", text="ID")
self.tree_servicos.column("id", width=40, anchor='center')
self.tree_servicos.heading("cliente_nome", text="Cliente")
self.tree_servicos.column("cliente_nome", width=200)
self.tree_servicos.heading("descricao", text="Descrição")
self.tree_servicos.column("descricao", width=300)
self.tree_servicos.heading("valor", text="Valor (R$)")
self.tree_servicos.column("valor", width=80, anchor='center')
self.tree_servicos.heading("status", text="Status")
self.tree_servicos.column("status", width=120, anchor='center')
# Hide cliente_id column
self.tree_servicos.column("cliente_id", width=0, stretch=False)
self.tree_servicos.heading("cliente_id", text="cliente_id", anchor='center')
self.tree_servicos.pack(fill='both', expand=True)
self.tree_servicos.bind('<<TreeviewSelect>>', self.on_servico_select)
self.load_cliente_combobox()
self.load_servicos()
def load_cliente_combobox(self):
clientes = get_clientes()
self.clientes_map = {f"{nome} (ID: {cid})": cid for cid, nome, _, _ in clientes}
self.combo_servico_cliente['values'] = list(self.clientes_map.keys())
self.servico_cliente_var.set('') # Reset combobox
def load_servicos(self):
for i in self.tree_servicos.get_children():
self.tree_servicos.delete(i)
for servico in get_servicos():
sid, cliente_id, cliente_nome, descricao, valor, status = servico
valor_str = f"{valor:.2f}"
# inserir clientes em arvore galera
self.tree_servicos.insert('', 'end', values=(sid, cliente_id, cliente_nome, descricao,
valor_str, status))
self.clear_servico_form()
def add_servico(self):
cliente_str = self.servico_cliente_var.get()
descricao = self.servico_descricao_var.get().strip()
valor_str = self.servico_valor_var.get().strip()
status = self.servico_status_var.get()
if not cliente_str or not descricao or not valor_str or not status:
messagebox.showwarning("Validação", "Todos os campos com * são obrigatórios.")
return
try:
valor = float(valor_str.replace(',', '.'))
except ValueError:
messagebox.showwarning("Validação", "Valor inválido. Por favor, insira um número válido.")
return
cliente_id = self.clientes_map.get(cliente_str)
add_servico(cliente_id, descricao, valor, status)
messagebox.showinfo("Sucesso", "Serviço adicionado com sucesso.")
self.load_servicos()
def on_servico_select(self, event):
selected = self.tree_servicos.focus()
if not selected:
return
values = self.tree_servicos.item(selected, 'values')
self.selected_servico_id = values[0]
cliente_id = values[1]
cliente_nome = values[2]
descricao = values[3]
valor = values[4]
status = values[5]
# Set form fields
# Find cliente string key by cliente_id using reverse lookup
for k, v in self.clientes_map.items():
if v == cliente_id:
self.servico_cliente_var.set(k)
break
self.servico_descricao_var.set(descricao)
self.servico_valor_var.set(valor)
self.servico_status_var.set(status)
self.btn_update_servico.state(['!disabled'])
self.btn_delete_servico.state(['!disabled'])
self.btn_add_servico.state(['disabled'])
def update_servico(self):
if not hasattr(self, 'selected_servico_id'):
return
cliente_str = self.servico_cliente_var.get()
descricao = self.servico_descricao_var.get().strip()
valor_str = self.servico_valor_var.get().strip()
status = self.servico_status_var.get()
if not cliente_str or not descricao or not valor_str or not status:
messagebox.showwarning("Validação", "Todos os campos com * são obrigatórios.")
return
try:
valor = float(valor_str.replace(',', '.'))
except ValueError:
messagebox.showwarning("Validação", "Valor inválido. Por favor, insira um número válido.")
return
cliente_id = self.clientes_map.get(cliente_str)
update_servico(self.selected_servico_id, cliente_id, descricao, valor, status)
messagebox.showinfo("Sucesso", "Serviço atualizado com sucesso.")
self.load_servicos()
def delete_servico(self):
if not hasattr(self, 'selected_servico_id'):
return
confirm = messagebox.askyesno("Confirmação", "Deseja realmente excluir este serviço?")
if confirm:
delete_servico(self.selected_servico_id)
messagebox.showinfo("Sucesso", "Serviço excluÃdo com sucesso.")
self.load_servicos()
def clear_servico_form(self):
self.servico_cliente_var.set('')
self.servico_descricao_var.set('')
self.servico_valor_var.set('')
self.servico_status_var.set("Recebido")
self.btn_update_servico.state(['disabled'])
self.btn_delete_servico.state(['disabled'])
self.btn_add_servico.state(['!disabled'])
if hasattr(self, 'selected_servico_id'):
del self.selected_servico_id
# Also reset selection in tree
self.tree_servicos.selection_remove(self.tree_servicos.selection())
def main(): create_database_and_tables()
root = tk.Tk()
app = LojaConsertoApp(root)
root.mainloop()
if __name__ == "__main__"
main()