add database management and fix some visual glitch
This commit is contained in:
parent
38cf8c2cfc
commit
8747d112f2
Binary file not shown.
Binary file not shown.
@ -339,7 +339,7 @@ class AuthManager:
|
||||
},
|
||||
{
|
||||
'name': 'Inventory Manager',
|
||||
'permissions': ['view_dashboard', 'view_inventory', 'adjust_inventory', 'view_stock_movements']
|
||||
'permissions': ['view_dashboard', 'view_inventory', 'manage_products', 'adjust_inventory', 'view_stock_movements']
|
||||
},
|
||||
{
|
||||
'name': 'Reports Viewer',
|
||||
|
||||
109
src/database.py
109
src/database.py
@ -125,6 +125,7 @@ class DatabaseManager:
|
||||
description TEXT,
|
||||
unit_price REAL DEFAULT 0,
|
||||
sku TEXT,
|
||||
min_stock INTEGER DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
''')
|
||||
@ -251,24 +252,13 @@ class DatabaseManager:
|
||||
)
|
||||
''')
|
||||
|
||||
# Create stock movements table
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS stock_movements (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
product_id INTEGER,
|
||||
movement_type TEXT, -- 'IN' for receipts, 'OUT' for issues
|
||||
quantity INTEGER,
|
||||
reference_type TEXT, -- 'PO', 'SO', 'MO', 'ADJUSTMENT'
|
||||
reference_id INTEGER, -- ID of the related document
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (product_id) REFERENCES products (id)
|
||||
)
|
||||
''')
|
||||
|
||||
self.connection.commit()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Database initialization error: {e}")
|
||||
if self.connection:
|
||||
self.connection.rollback()
|
||||
return False
|
||||
finally:
|
||||
self.disconnect()
|
||||
@ -283,8 +273,25 @@ class DatabaseManager:
|
||||
if self.db_type == 'sqlite':
|
||||
shutil.copy2(self.db_name, backup_path)
|
||||
return backup_path
|
||||
elif self.db_type == 'postgresql':
|
||||
# For PostgreSQL, we can use pg_dump
|
||||
import subprocess
|
||||
try:
|
||||
subprocess.run([
|
||||
'pg_dump',
|
||||
'-h', self.db_host,
|
||||
'-p', str(self.db_port),
|
||||
'-U', self.db_user,
|
||||
'-d', self.db_name,
|
||||
'-f', backup_path
|
||||
], check=True, env={'PGPASSWORD': self.db_password})
|
||||
return backup_path
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"PostgreSQL backup error: {e}")
|
||||
return None
|
||||
else:
|
||||
# For other databases, implement appropriate backup logic
|
||||
# For other databases, return None for now
|
||||
print(f"Backup not implemented for database type: {self.db_type}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Database backup error: {e}")
|
||||
@ -296,8 +303,59 @@ class DatabaseManager:
|
||||
if self.db_type == 'sqlite':
|
||||
shutil.copy2(backup_path, self.db_name)
|
||||
return True
|
||||
elif self.db_type == 'postgresql':
|
||||
# For PostgreSQL, we can use pg_restore or psql
|
||||
import subprocess
|
||||
try:
|
||||
# First, disconnect all users from the database
|
||||
disconnect_sql = f"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{self.db_name}';"
|
||||
|
||||
# Drop and recreate the database
|
||||
drop_sql = f"DROP DATABASE IF EXISTS {self.db_name};"
|
||||
create_sql = f"CREATE DATABASE {self.db_name};"
|
||||
|
||||
# Execute the commands
|
||||
subprocess.run([
|
||||
'psql',
|
||||
'-h', self.db_host,
|
||||
'-p', str(self.db_port),
|
||||
'-U', self.db_user,
|
||||
'-c', disconnect_sql
|
||||
], check=True, env={'PGPASSWORD': self.db_password})
|
||||
|
||||
subprocess.run([
|
||||
'psql',
|
||||
'-h', self.db_host,
|
||||
'-p', str(self.db_port),
|
||||
'-U', self.db_user,
|
||||
'-c', drop_sql
|
||||
], check=True, env={'PGPASSWORD': self.db_password})
|
||||
|
||||
subprocess.run([
|
||||
'psql',
|
||||
'-h', self.db_host,
|
||||
'-p', str(self.db_port),
|
||||
'-U', self.db_user,
|
||||
'-c', create_sql
|
||||
], check=True, env={'PGPASSWORD': self.db_password})
|
||||
|
||||
# Restore the backup
|
||||
subprocess.run([
|
||||
'psql',
|
||||
'-h', self.db_host,
|
||||
'-p', str(self.db_port),
|
||||
'-U', self.db_user,
|
||||
'-d', self.db_name,
|
||||
'-f', backup_path
|
||||
], check=True, env={'PGPASSWORD': self.db_password})
|
||||
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"PostgreSQL restore error: {e}")
|
||||
return False
|
||||
else:
|
||||
# For other databases, implement appropriate restore logic
|
||||
# For other databases, return False for now
|
||||
print(f"Restore not implemented for database type: {self.db_type}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"Database restore error: {e}")
|
||||
@ -323,3 +381,24 @@ class DatabaseManager:
|
||||
elif self.db_type == 'postgresql':
|
||||
return f"postgresql://{self.db_user}:{self.db_password}@{self.db_host}:{self.db_port}/{self.db_name}"
|
||||
return ""
|
||||
|
||||
def is_database_initialized(self):
|
||||
"""Check if the database is properly initialized"""
|
||||
if not self.connect():
|
||||
return False
|
||||
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
# Check if the users table exists
|
||||
if self.db_type == 'sqlite':
|
||||
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='users'")
|
||||
elif self.db_type == 'postgresql':
|
||||
cursor.execute("SELECT tablename FROM pg_tables WHERE tablename='users'")
|
||||
|
||||
result = cursor.fetchone()
|
||||
return result is not None
|
||||
except Exception as e:
|
||||
print(f"Database initialization check error: {e}")
|
||||
return False
|
||||
finally:
|
||||
self.disconnect()
|
||||
BIN
src/ui/__pycache__/database_management_dialog.cpython-312.pyc
Normal file
BIN
src/ui/__pycache__/database_management_dialog.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
148
src/ui/database_management_dialog.py
Normal file
148
src/ui/database_management_dialog.py
Normal file
@ -0,0 +1,148 @@
|
||||
import customtkinter as ctk
|
||||
from tkinter import messagebox, filedialog
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Add the project root to the path
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
|
||||
from src.database import DatabaseManager
|
||||
|
||||
|
||||
class DatabaseManagementDialog:
|
||||
def __init__(self, parent, db_manager):
|
||||
self.db_manager = db_manager
|
||||
|
||||
# Create the dialog window
|
||||
self.dialog = ctk.CTkToplevel(parent)
|
||||
self.dialog.title("Database Management")
|
||||
self.dialog.geometry("500x400")
|
||||
self.dialog.transient(parent)
|
||||
self.dialog.grab_set()
|
||||
|
||||
# Center the dialog
|
||||
self.dialog.update_idletasks()
|
||||
width = self.dialog.winfo_width()
|
||||
height = self.dialog.winfo_height()
|
||||
x = (self.dialog.winfo_screenwidth() // 2) - (width // 2)
|
||||
y = (self.dialog.winfo_screenheight() // 2) - (height // 2)
|
||||
self.dialog.geometry(f'{width}x{height}+{x}+{y}')
|
||||
|
||||
# Create UI elements
|
||||
self.create_widgets()
|
||||
|
||||
def create_widgets(self):
|
||||
"""Create the UI elements for the dialog"""
|
||||
# Title
|
||||
title_label = ctk.CTkLabel(self.dialog, text="Database Management",
|
||||
font=("Arial", 20, "bold"))
|
||||
title_label.pack(pady=20)
|
||||
|
||||
# Main frame
|
||||
main_frame = ctk.CTkFrame(self.dialog)
|
||||
main_frame.pack(fill="both", expand=True, padx=20, pady=10)
|
||||
|
||||
# Database info
|
||||
info_frame = ctk.CTkFrame(main_frame)
|
||||
info_frame.pack(fill="x", padx=10, pady=10)
|
||||
|
||||
ctk.CTkLabel(info_frame, text="Database Information",
|
||||
font=("Arial", 14, "bold")).pack(anchor="w", padx=10, pady=5)
|
||||
|
||||
ctk.CTkLabel(info_frame, text=f"Database Type: {self.db_manager.db_type}").pack(anchor="w", padx=20, pady=2)
|
||||
ctk.CTkLabel(info_frame, text=f"Database Name: {self.db_manager.db_name}").pack(anchor="w", padx=20, pady=2)
|
||||
|
||||
# Actions frame
|
||||
actions_frame = ctk.CTkFrame(main_frame)
|
||||
actions_frame.pack(fill="x", padx=10, pady=10)
|
||||
|
||||
ctk.CTkLabel(actions_frame, text="Database Actions",
|
||||
font=("Arial", 14, "bold")).pack(anchor="w", padx=10, pady=5)
|
||||
|
||||
# Buttons
|
||||
button_frame = ctk.CTkFrame(actions_frame, fg_color="transparent")
|
||||
button_frame.pack(fill="x", padx=20, pady=10)
|
||||
|
||||
ctk.CTkButton(button_frame, text="Backup Database",
|
||||
command=self.backup_database, width=150, height=32).pack(pady=5)
|
||||
|
||||
ctk.CTkButton(button_frame, text="Restore Database",
|
||||
command=self.restore_database, width=150, height=32).pack(pady=5)
|
||||
|
||||
ctk.CTkButton(button_frame, text="Initialize Database",
|
||||
command=self.initialize_database, width=150, height=32).pack(pady=5)
|
||||
|
||||
ctk.CTkButton(button_frame, text="Check Database Status",
|
||||
command=self.check_database_status, width=150, height=32).pack(pady=5)
|
||||
|
||||
# Close button
|
||||
close_button = ctk.CTkButton(self.dialog, text="Close",
|
||||
command=self.dialog.destroy, width=100, height=32)
|
||||
close_button.pack(pady=20)
|
||||
|
||||
def backup_database(self):
|
||||
"""Backup the database"""
|
||||
try:
|
||||
# Ask user for backup location
|
||||
backup_path = filedialog.asksaveasfilename(
|
||||
defaultextension=".db",
|
||||
filetypes=[("Database files", "*.db"), ("All files", "*.*")],
|
||||
title="Save Database Backup As"
|
||||
)
|
||||
|
||||
if backup_path:
|
||||
result = self.db_manager.backup_database(backup_path)
|
||||
if result:
|
||||
messagebox.showinfo("Success", f"Database backed up successfully to {result}")
|
||||
else:
|
||||
messagebox.showerror("Error", "Failed to backup database")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Failed to backup database: {str(e)}")
|
||||
|
||||
def restore_database(self):
|
||||
"""Restore the database from a backup"""
|
||||
try:
|
||||
# Ask user for backup file to restore
|
||||
backup_path = filedialog.askopenfilename(
|
||||
filetypes=[("Database files", "*.db"), ("All files", "*.*")],
|
||||
title="Select Database Backup File"
|
||||
)
|
||||
|
||||
if backup_path:
|
||||
# Confirm with user before restoring
|
||||
if messagebox.askyesno("Confirm Restore",
|
||||
"Are you sure you want to restore the database? "
|
||||
"This will overwrite the current database."):
|
||||
result = self.db_manager.restore_database(backup_path)
|
||||
if result:
|
||||
messagebox.showinfo("Success", "Database restored successfully")
|
||||
else:
|
||||
messagebox.showerror("Error", "Failed to restore database")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Failed to restore database: {str(e)}")
|
||||
|
||||
def initialize_database(self):
|
||||
"""Initialize the database"""
|
||||
try:
|
||||
# Confirm with user before initializing
|
||||
if messagebox.askyesno("Confirm Initialization",
|
||||
"Are you sure you want to initialize the database? "
|
||||
"This will create all necessary tables."):
|
||||
result = self.db_manager.initialize_database()
|
||||
if result:
|
||||
messagebox.showinfo("Success", "Database initialized successfully")
|
||||
else:
|
||||
messagebox.showerror("Error", "Failed to initialize database")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Failed to initialize database: {str(e)}")
|
||||
|
||||
def check_database_status(self):
|
||||
"""Check the database status"""
|
||||
try:
|
||||
is_initialized = self.db_manager.is_database_initialized()
|
||||
if is_initialized:
|
||||
messagebox.showinfo("Database Status", "Database is properly initialized")
|
||||
else:
|
||||
messagebox.showwarning("Database Status", "Database is not initialized")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Failed to check database status: {str(e)}")
|
||||
@ -17,6 +17,7 @@ from src.ui.manufacturing_order_dialog import ManufacturingOrderDialog
|
||||
from src.ui.sales_order_dialog import SalesOrderDialog
|
||||
from src.ui.customer_dialog import CustomerDialog
|
||||
from src.ui.supplier_dialog import SupplierDialog
|
||||
from src.ui.database_management_dialog import DatabaseManagementDialog
|
||||
|
||||
class MainWindow:
|
||||
def __init__(self, root, user, db_manager, app=None):
|
||||
@ -67,19 +68,27 @@ class MainWindow:
|
||||
menubar.add_cascade(label="Modules", menu=modules_menu)
|
||||
modules_menu.add_command(label="Dashboard", command=self.show_dashboard)
|
||||
modules_menu.add_separator()
|
||||
modules_menu.add_command(label="Purchase", command=self.show_purchase)
|
||||
modules_menu.add_command(label="Manufacture", command=self.show_manufacturing)
|
||||
modules_menu.add_command(label="Sales", command=self.show_sales)
|
||||
modules_menu.add_command(label="Inventory", command=self.show_inventory)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_purchase_orders') or self.user['is_admin']:
|
||||
modules_menu.add_command(label="Purchase", command=self.show_purchase)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_manufacturing_orders') or self.user['is_admin']:
|
||||
modules_menu.add_command(label="Manufacture", command=self.show_manufacturing)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_sales_orders') or self.user['is_admin']:
|
||||
modules_menu.add_command(label="Sales", command=self.show_sales)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_inventory') or self.user['is_admin']:
|
||||
modules_menu.add_command(label="Inventory", command=self.show_inventory)
|
||||
modules_menu.add_separator()
|
||||
modules_menu.add_command(label="Suppliers", command=self.show_supplier_list)
|
||||
modules_menu.add_command(label="Customers", command=self.show_customer_list)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']:
|
||||
modules_menu.add_command(label="Suppliers", command=self.show_supplier_list)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']:
|
||||
modules_menu.add_command(label="Customers", command=self.show_customer_list)
|
||||
|
||||
# Configuration menu (admin only)
|
||||
if self.user['is_admin']:
|
||||
config_menu = tk.Menu(menubar, tearoff=0, bg="#f0f0f0", fg="black")
|
||||
menubar.add_cascade(label="Configuration", menu=config_menu)
|
||||
config_menu.add_command(label="User Management", command=self.manage_users)
|
||||
config_menu.add_separator()
|
||||
config_menu.add_command(label="Database Management", command=self.manage_database)
|
||||
|
||||
# Reports menu
|
||||
has_report_permissions = (
|
||||
@ -114,14 +123,18 @@ class MainWindow:
|
||||
ctk.CTkButton(button_frame, text="Dashboard", command=self.show_dashboard,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
|
||||
ctk.CTkButton(button_frame, text="Purchase", command=self.show_purchase,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="Manufacture", command=self.show_manufacturing,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="Sales", command=self.show_sales,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="Inventory", command=self.show_inventory,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_purchase_orders') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Purchase", command=self.show_purchase,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_manufacturing_orders') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Manufacture", command=self.show_manufacturing,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_sales_orders') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Sales", command=self.show_sales,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'view_inventory') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Inventory", command=self.show_inventory,
|
||||
width=100, height=32).pack(side="left", padx=5)
|
||||
|
||||
# User info
|
||||
user_frame = ctk.CTkFrame(toolbar, fg_color="transparent")
|
||||
@ -269,6 +282,11 @@ class MainWindow:
|
||||
|
||||
def show_purchase(self):
|
||||
"""Show purchase management"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_purchase_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to access the purchase module")
|
||||
return
|
||||
|
||||
self.clear_content()
|
||||
self.status_bar.configure(text="Purchase Management")
|
||||
|
||||
@ -289,14 +307,20 @@ class MainWindow:
|
||||
command=self.new_purchase_order, width=150, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="View Purchase Orders",
|
||||
command=self.view_purchase_orders, width=150, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="Manage Suppliers",
|
||||
command=self.show_supplier_list, width=150, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Manage Suppliers",
|
||||
command=self.show_supplier_list, width=150, height=32).pack(side="left", padx=5)
|
||||
|
||||
# Show purchase orders by default
|
||||
self.show_purchase_orders()
|
||||
|
||||
def show_manufacturing(self):
|
||||
"""Show manufacturing management"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_manufacturing_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to access the manufacturing module")
|
||||
return
|
||||
|
||||
self.clear_content()
|
||||
self.status_bar.configure(text="Manufacturing Management")
|
||||
|
||||
@ -325,6 +349,11 @@ class MainWindow:
|
||||
|
||||
def show_sales(self):
|
||||
"""Show sales management"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_sales_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to access the sales module")
|
||||
return
|
||||
|
||||
self.clear_content()
|
||||
self.status_bar.configure(text="Sales Management")
|
||||
|
||||
@ -345,14 +374,20 @@ class MainWindow:
|
||||
command=self.new_sales_order, width=150, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="View Sales Orders",
|
||||
command=self.view_sales_orders, width=150, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="Manage Customers",
|
||||
command=self.show_customer_list, width=150, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Manage Customers",
|
||||
command=self.show_customer_list, width=150, height=32).pack(side="left", padx=5)
|
||||
|
||||
# Show sales orders by default
|
||||
self.show_sales_orders()
|
||||
|
||||
def show_inventory(self):
|
||||
"""Show inventory management"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_inventory') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to access the inventory module")
|
||||
return
|
||||
|
||||
self.clear_content()
|
||||
self.status_bar.configure(text="Inventory Management")
|
||||
|
||||
@ -371,8 +406,9 @@ class MainWindow:
|
||||
|
||||
ctk.CTkButton(button_frame, text="View Inventory",
|
||||
command=self.view_inventory, width=150, height=32).pack(side="left", padx=5)
|
||||
ctk.CTkButton(button_frame, text="Stock Adjustment",
|
||||
command=self.stock_adjustment, width=150, height=32).pack(side="left", padx=5)
|
||||
if self.auth_manager.user_has_permission(self.user['id'], 'adjust_inventory') or self.user['is_admin']:
|
||||
ctk.CTkButton(button_frame, text="Stock Adjustment",
|
||||
command=self.stock_adjustment, width=150, height=32).pack(side="left", padx=5)
|
||||
|
||||
# Show inventory by default
|
||||
self.show_inventory_management()
|
||||
@ -416,6 +452,11 @@ class MainWindow:
|
||||
# Module command methods
|
||||
def new_purchase_order(self):
|
||||
"""Create a new purchase order"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'edit_purchase_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to create purchase orders")
|
||||
return
|
||||
|
||||
dialog = PurchaseOrderDialog(self.root, self.purchase_service, self.product_service, self.supplier_service)
|
||||
dialog.grab_set()
|
||||
|
||||
@ -425,11 +466,21 @@ class MainWindow:
|
||||
|
||||
def manage_suppliers(self):
|
||||
"""Manage suppliers"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to manage suppliers")
|
||||
return
|
||||
|
||||
dialog = SupplierDialog(self.root, self.supplier_service)
|
||||
dialog.grab_set()
|
||||
|
||||
def new_manufacturing_order(self):
|
||||
"""Create a new manufacturing order"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'edit_manufacturing_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to create manufacturing orders")
|
||||
return
|
||||
|
||||
dialog = ManufacturingOrderDialog(self.root, self.manufacturing_service, self.product_service, self.inventory_service)
|
||||
dialog.grab_set()
|
||||
|
||||
@ -443,6 +494,11 @@ class MainWindow:
|
||||
|
||||
def new_sales_order(self):
|
||||
"""Create a new sales order"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'edit_sales_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to create sales orders")
|
||||
return
|
||||
|
||||
dialog = SalesOrderDialog(self.root, self.sales_service, self.product_service, self.customer_service)
|
||||
dialog.grab_set()
|
||||
|
||||
@ -452,6 +508,11 @@ class MainWindow:
|
||||
|
||||
def manage_customers(self):
|
||||
"""Manage customers"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to manage customers")
|
||||
return
|
||||
|
||||
dialog = CustomerDialog(self.root, self.customer_service)
|
||||
dialog.grab_set()
|
||||
|
||||
@ -517,7 +578,7 @@ class MainWindow:
|
||||
for idx, order in enumerate(orders):
|
||||
row_frame = ctk.CTkFrame(scroll_frame, height=24)
|
||||
row_frame.pack(fill="x", padx=5, pady=2)
|
||||
row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
#row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
|
||||
ctk.CTkLabel(row_frame, text=f"PO-{order.id}").grid(
|
||||
row=0, column=0, padx=5, pady=5, sticky="w")
|
||||
@ -535,11 +596,13 @@ class MainWindow:
|
||||
# Actions
|
||||
actions_frame = ctk.CTkFrame(row_frame, fg_color="transparent")
|
||||
actions_frame.grid(row=0, column=5, padx=5, pady=5, sticky="w")
|
||||
|
||||
ctk.CTkButton(actions_frame, text="",
|
||||
command=None,
|
||||
width=1, height=24).pack(side="left", padx=2)
|
||||
# Add status change button for pending orders
|
||||
if order.status == "pending":
|
||||
ctk.CTkButton(actions_frame, text="Complete",
|
||||
command=lambda o=order: self.complete_purchase_order(o),
|
||||
command=None,
|
||||
width=70, height=24, fg_color="green").pack(side="left", padx=2)
|
||||
|
||||
def show_manufacturing_orders(self):
|
||||
@ -604,7 +667,7 @@ class MainWindow:
|
||||
for idx, order in enumerate(orders):
|
||||
row_frame = ctk.CTkFrame(scroll_frame, height=24)
|
||||
row_frame.pack(fill="x", padx=5, pady=2)
|
||||
row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
#row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
|
||||
ctk.CTkLabel(row_frame, text=f"MO-{order.id}").grid(
|
||||
row=0, column=0, padx=5, pady=5, sticky="w")
|
||||
@ -622,6 +685,9 @@ class MainWindow:
|
||||
# Actions
|
||||
actions_frame = ctk.CTkFrame(row_frame, fg_color="transparent")
|
||||
actions_frame.grid(row=0, column=5, padx=5, pady=5, sticky="w")
|
||||
ctk.CTkButton(actions_frame, text="",
|
||||
command=None,
|
||||
width=1, height=24).pack(side="left", padx=2)
|
||||
|
||||
# Add status change button for pending orders
|
||||
if order.status == "pending":
|
||||
@ -691,7 +757,7 @@ class MainWindow:
|
||||
for idx, order in enumerate(orders):
|
||||
row_frame = ctk.CTkFrame(scroll_frame, height=24)
|
||||
row_frame.pack(fill="x", padx=5, pady=2)
|
||||
row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
#row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
|
||||
ctk.CTkLabel(row_frame, text=f"SO-{order.id}").grid(
|
||||
row=0, column=0, padx=5, pady=5, sticky="w")
|
||||
@ -709,6 +775,9 @@ class MainWindow:
|
||||
# Actions
|
||||
actions_frame = ctk.CTkFrame(row_frame, fg_color="transparent")
|
||||
actions_frame.grid(row=0, column=5, padx=5, pady=5, sticky="w")
|
||||
ctk.CTkButton(actions_frame, text="",
|
||||
command=None,
|
||||
width=1, height=24).pack(side="left", padx=2)
|
||||
|
||||
# Add status change button for pending orders
|
||||
if order.status == "pending":
|
||||
@ -734,6 +803,11 @@ class MainWindow:
|
||||
|
||||
def stock_adjustment(self):
|
||||
"""Adjust stock levels"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'adjust_inventory') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to adjust inventory")
|
||||
return
|
||||
|
||||
self.show_inventory_management()
|
||||
|
||||
def show_inventory_management(self):
|
||||
@ -796,7 +870,7 @@ class MainWindow:
|
||||
for idx, product in enumerate(products):
|
||||
row_frame = ctk.CTkFrame(scroll_frame, height=24)
|
||||
row_frame.pack(fill="x", padx=5, pady=2)
|
||||
row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
#row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
|
||||
# Product info
|
||||
ctk.CTkLabel(row_frame, text=product.name).grid(
|
||||
@ -831,6 +905,11 @@ class MainWindow:
|
||||
|
||||
def manage_products(self):
|
||||
"""Open product management dialog"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_products') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to manage products")
|
||||
return
|
||||
|
||||
dialog = ProductDialog(self.root, self.product_service)
|
||||
dialog.grab_set()
|
||||
|
||||
@ -840,11 +919,21 @@ class MainWindow:
|
||||
|
||||
def edit_product(self, product):
|
||||
"""Edit a specific product"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_products') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to edit products")
|
||||
return
|
||||
|
||||
dialog = ProductDialog(self.root, self.product_service, product)
|
||||
dialog.grab_set()
|
||||
|
||||
def adjust_product_stock(self, product):
|
||||
"""Adjust stock for a specific product"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'adjust_inventory') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to adjust inventory")
|
||||
return
|
||||
|
||||
# Create a simple stock adjustment dialog
|
||||
dialog = ctk.CTkToplevel(self.root)
|
||||
dialog.title(f"Adjust Stock - {product.name}")
|
||||
@ -879,8 +968,19 @@ class MainWindow:
|
||||
self.root.wait_window(dialog)
|
||||
|
||||
|
||||
def manage_database(self):
|
||||
"""Database management (admin only)"""
|
||||
dialog = DatabaseManagementDialog(self.root, self.db_manager)
|
||||
self.root.wait_window(dialog)
|
||||
|
||||
|
||||
def show_inventory_report(self):
|
||||
"""Show inventory report"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_inventory_report') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to view inventory reports")
|
||||
return
|
||||
|
||||
try:
|
||||
filename = self.inventory_service.export_inventory_report()
|
||||
messagebox.showinfo("Success", f"Inventory report exported to {filename}")
|
||||
@ -889,6 +989,11 @@ class MainWindow:
|
||||
|
||||
def show_sales_report(self):
|
||||
"""Show sales report with date range selection"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_reports') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to view sales reports")
|
||||
return
|
||||
|
||||
from src.ui.date_range_dialog import DateRangeDialog
|
||||
dialog = DateRangeDialog(self.root, "Select Date Range for Sales Report", "Export")
|
||||
self.root.wait_window(dialog)
|
||||
@ -903,6 +1008,11 @@ class MainWindow:
|
||||
|
||||
def show_purchase_report(self):
|
||||
"""Show purchase report with date range selection"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_reports') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to view purchase reports")
|
||||
return
|
||||
|
||||
from src.ui.date_range_dialog import DateRangeDialog
|
||||
dialog = DateRangeDialog(self.root, "Select Date Range for Purchase Report", "Export")
|
||||
self.root.wait_window(dialog)
|
||||
@ -917,6 +1027,11 @@ class MainWindow:
|
||||
|
||||
def show_manufacturing_report(self):
|
||||
"""Show manufacturing report with date range selection"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_reports') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to view manufacturing reports")
|
||||
return
|
||||
|
||||
from src.ui.date_range_dialog import DateRangeDialog
|
||||
dialog = DateRangeDialog(self.root, "Select Date Range for Manufacturing Report", "Export")
|
||||
self.root.wait_window(dialog)
|
||||
@ -931,6 +1046,11 @@ class MainWindow:
|
||||
|
||||
def show_stock_movement_report(self):
|
||||
"""Show stock movement report"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'view_stock_movements') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to view stock movement reports")
|
||||
return
|
||||
|
||||
try:
|
||||
filename = self.inventory_service.export_stock_movement_report()
|
||||
messagebox.showinfo("Success", f"Stock movement report exported to {filename}")
|
||||
@ -939,6 +1059,11 @@ class MainWindow:
|
||||
|
||||
def complete_purchase_order(self, order):
|
||||
"""Complete a purchase order"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'receive_purchase_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to complete purchase orders")
|
||||
return
|
||||
|
||||
if messagebox.askyesno("Confirm", f"Are you sure you want to complete purchase order #{order.id}?"):
|
||||
if self.purchase_service.receive_purchase_order(order.id):
|
||||
messagebox.showinfo("Success", f"Purchase order #{order.id} completed successfully")
|
||||
@ -948,6 +1073,11 @@ class MainWindow:
|
||||
|
||||
def complete_manufacturing_order(self, order):
|
||||
"""Complete a manufacturing order"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'complete_manufacturing_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to complete manufacturing orders")
|
||||
return
|
||||
|
||||
if messagebox.askyesno("Confirm", f"Are you sure you want to complete manufacturing order #{order.id}?"):
|
||||
if self.manufacturing_service.complete_manufacturing_order(order.id):
|
||||
messagebox.showinfo("Success", f"Manufacturing order #{order.id} completed successfully")
|
||||
@ -957,6 +1087,11 @@ class MainWindow:
|
||||
|
||||
def complete_sales_order(self, order):
|
||||
"""Complete a sales order"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'deliver_sales_orders') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to complete sales orders")
|
||||
return
|
||||
|
||||
if messagebox.askyesno("Confirm", f"Are you sure you want to complete sales order #{order.id}?"):
|
||||
if self.sales_service.deliver_sales_order(order.id):
|
||||
messagebox.showinfo("Success", f"Sales order #{order.id} completed successfully")
|
||||
@ -978,6 +1113,11 @@ class MainWindow:
|
||||
|
||||
def show_supplier_list(self):
|
||||
"""Show supplier management interface"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to manage suppliers")
|
||||
return
|
||||
|
||||
self.clear_content()
|
||||
self.status_bar.configure(text="Supplier Management")
|
||||
|
||||
@ -1036,7 +1176,7 @@ class MainWindow:
|
||||
for idx, supplier in enumerate(suppliers):
|
||||
row_frame = ctk.CTkFrame(scroll_frame, height=24)
|
||||
row_frame.pack(fill="x", padx=5, pady=2)
|
||||
row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
#row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
|
||||
ctk.CTkLabel(row_frame, text=supplier.name).grid(
|
||||
row=0, column=0, padx=5, pady=5, sticky="w")
|
||||
@ -1060,6 +1200,11 @@ class MainWindow:
|
||||
|
||||
def add_supplier(self):
|
||||
"""Add a new supplier"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to add suppliers")
|
||||
return
|
||||
|
||||
from src.ui.supplier_dialog import SupplierDialog
|
||||
dialog = SupplierDialog(self.root, self.supplier_service)
|
||||
self.root.wait_window(dialog)
|
||||
@ -1067,6 +1212,11 @@ class MainWindow:
|
||||
|
||||
def edit_supplier(self, supplier):
|
||||
"""Edit a supplier"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to edit suppliers")
|
||||
return
|
||||
|
||||
from src.ui.supplier_dialog import SupplierDialog
|
||||
dialog = SupplierDialog(self.root, self.supplier_service, supplier)
|
||||
self.root.wait_window(dialog)
|
||||
@ -1074,6 +1224,11 @@ class MainWindow:
|
||||
|
||||
def delete_supplier(self, supplier):
|
||||
"""Delete a supplier"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_suppliers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to delete suppliers")
|
||||
return
|
||||
|
||||
if messagebox.askyesno("Confirm Delete", f"Are you sure you want to delete supplier '{supplier.name}'?"):
|
||||
if self.supplier_service.delete_supplier(supplier.id):
|
||||
messagebox.showinfo("Success", f"Supplier '{supplier.name}' deleted successfully")
|
||||
@ -1083,6 +1238,11 @@ class MainWindow:
|
||||
|
||||
def show_customer_list(self):
|
||||
"""Show customer management interface"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to manage customers")
|
||||
return
|
||||
|
||||
self.clear_content()
|
||||
self.status_bar.configure(text="Customer Management")
|
||||
|
||||
@ -1141,7 +1301,7 @@ class MainWindow:
|
||||
for idx, customer in enumerate(customers):
|
||||
row_frame = ctk.CTkFrame(scroll_frame, height=24)
|
||||
row_frame.pack(fill="x", padx=5, pady=2)
|
||||
row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
#row_frame.pack_propagate(False) # Prevent frame from shrinking
|
||||
|
||||
ctk.CTkLabel(row_frame, text=customer.name).grid(
|
||||
row=0, column=0, padx=5, pady=5, sticky="w")
|
||||
@ -1165,6 +1325,11 @@ class MainWindow:
|
||||
|
||||
def add_customer(self):
|
||||
"""Add a new customer"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to add customers")
|
||||
return
|
||||
|
||||
from src.ui.customer_dialog import CustomerDialog
|
||||
dialog = CustomerDialog(self.root, self.customer_service)
|
||||
self.root.wait_window(dialog)
|
||||
@ -1172,6 +1337,11 @@ class MainWindow:
|
||||
|
||||
def edit_customer(self, customer):
|
||||
"""Edit a customer"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to edit customers")
|
||||
return
|
||||
|
||||
from src.ui.customer_dialog import CustomerDialog
|
||||
dialog = CustomerDialog(self.root, self.customer_service, customer)
|
||||
self.root.wait_window(dialog)
|
||||
@ -1179,6 +1349,11 @@ class MainWindow:
|
||||
|
||||
def delete_customer(self, customer):
|
||||
"""Delete a customer"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_customers') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to delete customers")
|
||||
return
|
||||
|
||||
if messagebox.askyesno("Confirm Delete", f"Are you sure you want to delete customer '{customer.name}'?"):
|
||||
if self.customer_service.delete_customer(customer.id):
|
||||
messagebox.showinfo("Success", f"Customer '{customer.name}' deleted successfully")
|
||||
@ -1212,6 +1387,11 @@ class MainWindow:
|
||||
|
||||
def add_product(self):
|
||||
"""Add a new product"""
|
||||
# Check permissions
|
||||
if not (self.auth_manager.user_has_permission(self.user['id'], 'manage_products') or self.user['is_admin']):
|
||||
messagebox.showerror("Access Denied", "You don't have permission to add products")
|
||||
return
|
||||
|
||||
from src.ui.product_dialog import ProductDialog
|
||||
dialog = ProductDialog(self.root, self.product_service)
|
||||
self.root.wait_window(dialog)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user