#PyQt5 #SQLite #DesktopApp #Pharmacy #Barcode #Python
Lesson: Building a Pharmacy Management System with PyQt5 and Barcode Scanning
This tutorial will guide you through creating a complete desktop application for managing a pharmacy. The system will use a SQLite database for inventory, and a Point of Sale (POS) interface that uses barcode scanning to add drugs to a sale and automatically deducts stock upon completion.
---
First, we create a dedicated file to handle all SQLite database operations. This keeps our data logic separate from our UI logic. Create a file named
---
Create the main application file,
Lesson: Building a Pharmacy Management System with PyQt5 and Barcode Scanning
This tutorial will guide you through creating a complete desktop application for managing a pharmacy. The system will use a SQLite database for inventory, and a Point of Sale (POS) interface that uses barcode scanning to add drugs to a sale and automatically deducts stock upon completion.
---
#Step 1: Database Setup (database.py)First, we create a dedicated file to handle all SQLite database operations. This keeps our data logic separate from our UI logic. Create a file named
database.py.import sqlite3
DB_NAME = 'pharmacy.db'
def connect():
return sqlite3.connect(DB_NAME)
def setup_database():
conn = connect()
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS drugs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
barcode TEXT NOT NULL UNIQUE,
quantity INTEGER NOT NULL,
price REAL NOT NULL,
expiry_date TEXT NOT NULL
)
''')
conn.commit()
conn.close()
def add_drug(name, barcode, quantity, price, expiry_date):
conn = connect()
cursor = conn.cursor()
try:
cursor.execute("INSERT INTO drugs (name, barcode, quantity, price, expiry_date) VALUES (?, ?, ?, ?, ?)",
(name, barcode, quantity, price, expiry_date))
conn.commit()
except sqlite3.IntegrityError:
return False # Barcode already exists
finally:
conn.close()
return True
def get_all_drugs():
conn = connect()
cursor = conn.cursor()
cursor.execute("SELECT id, name, barcode, quantity, price, expiry_date FROM drugs ORDER BY name")
drugs = cursor.fetchall()
conn.close()
return drugs
def find_drug_by_barcode(barcode):
conn = connect()
cursor = conn.cursor()
cursor.execute("SELECT id, name, barcode, quantity, price, expiry_date FROM drugs WHERE barcode = ?", (barcode,))
drug = cursor.fetchone()
conn.close()
return drug
def update_drug_quantity(drug_id, sold_quantity):
conn = connect()
cursor = conn.cursor()
cursor.execute("UPDATE drugs SET quantity = quantity - ? WHERE id = ?", (sold_quantity, drug_id))
conn.commit()
conn.close()
# Hashtags: #SQLite #DatabaseDesign #DataPersistence #Python
---
#Step 2: Main Application and Inventory Management UICreate the main application file,
main.py. We will set up the main window with tabs for "Point of Sale" and "Inventory Management". We will fully implement the inventory tab first, allowing users to view and add drugs to the database.import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QDate
import database as db
class PharmacyApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Pharmacy Management System")
self.setGeometry(100, 100, 1200, 700)
db.setup_database()
self.tabs = QTabWidget()
self.setCentralWidget(self.tabs)
self.pos_tab = QWidget()
self.inventory_tab = QWidget()
self.tabs.addTab(self.pos_tab, "Point of Sale")
self.tabs.addTab(self.inventory_tab, "Inventory Management")
self.setup_inventory_ui()
# self.setup_pos_ui() will be done in the next step
self.load_inventory_data()
def setup_inventory_ui(self):
layout = QVBoxLayout()
self.inventory_table = QTableWidget()
self.inventory_table.setColumnCount(6)
self.inventory_table.setHorizontalHeaderLabels(['ID', 'Name', 'Barcode', 'Quantity', 'Price', 'Expiry Date'])
layout.addWidget(self.inventory_table)
form = QFormLayout()
self.drug_name = QLineEdit()
self.drug_barcode = QLineEdit()
self.drug_qty = QSpinBox()
self.drug_qty.setRange(0, 9999)
self.drug_price = QLineEdit()
self.drug_expiry = QDateEdit(QDate.currentDate().addYears(1))
self.drug_expiry.setDisplayFormat("yyyy-MM-dd")
form.addRow("Name:", self.drug_name)
form.addRow("Barcode:", self.drug_barcode)
form.addRow("Quantity:", self.drug_qty)
form.addRow("Price:", self.drug_price)
form.addRow("Expiry Date:", self.drug_expiry)
add_btn = QPushButton("Add Drug to Inventory")
add_btn.clicked.connect(self.add_drug_to_db)
layout.addLayout(form)
layout.addWidget(add_btn)
self.inventory_tab.setLayout(layout)
def load_inventory_data(self):
drugs = db.get_all_drugs()
self.inventory_table.setRowCount(len(drugs))
for row, drug in enumerate(drugs):
for col, data in enumerate(drug):
self.inventory_table.setItem(row, col, QTableWidgetItem(str(data)))
def add_drug_to_db(self):
name = self.drug_name.text()
barcode = self.drug_barcode.text()
qty = self.drug_qty.value()
price = float(self.drug_price.text())
expiry = self.drug_expiry.date().toString("yyyy-MM-dd")
if not all([name, barcode, qty > 0, price > 0]):
QMessageBox.warning(self, "Input Error", "Please fill all fields correctly.")
return
if db.add_drug(name, barcode, qty, price, expiry):
self.load_inventory_data()
else:
QMessageBox.warning(self, "Database Error", "A drug with this barcode already exists.")
# Main execution block at the end of the file
if __name__ == '__main__':
app = QApplication(sys.argv)
window = PharmacyApp()
window.show()
sys.exit(app.exec_())
# Hashtags: #PyQt5 #GUI #CRUD #Inventory
---
#Step 3: Point of Sale (POS) UI and Barcode HandlingNow, let's build the user interface for the sales tab. This will include an input for the barcode, a table for the current sale items (the "cart"), and buttons to finalize or clear the sale. A physical barcode scanner typically emulates a keyboard, entering the numbers and pressing "Enter". We will simulate this with the
returnPressed signal on a QLineEdit.Add these methods to the
PharmacyApp class:# In __init__, call the setup method
self.setup_pos_ui()
self.current_sale_items = {} # Dictionary to store {drug_id: {data, quantity}}
def setup_pos_ui(self):
main_layout = QHBoxLayout()
# Left side: Sale and Barcode input
left_layout = QVBoxLayout()
barcode_group = QGroupBox("Scan Barcode")
barcode_layout = QVBoxLayout()
self.barcode_input = QLineEdit()
self.barcode_input.setPlaceholderText("Scan or type barcode and press Enter...")
self.barcode_input.returnPressed.connect(self.add_item_to_sale)
barcode_layout.addWidget(self.barcode_input)
barcode_group.setLayout(barcode_layout)
self.sales_table = QTableWidget()
self.sales_table.setColumnCount(5)
self.sales_table.setHorizontalHeaderLabels(['ID', 'Name', 'Quantity', 'Unit Price', 'Total Price'])
left_layout.addWidget(barcode_group)
left_layout.addWidget(self.sales_table)
# Right side: Totals and Actions
right_layout = QVBoxLayout()
total_group = QGroupBox("Sale Summary")
total_form = QFormLayout()
self.total_amount_label = QLabel("0.00")
total_form.addRow("Total Amount:", self.total_amount_label)
total_group.setLayout(total_form)
complete_sale_btn = QPushButton("Complete Sale")
complete_sale_btn.clicked.connect(self.complete_sale)
clear_sale_btn = QPushButton("Clear Sale")
clear_sale_btn.clicked.connect(self.clear_sale)
right_layout.addWidget(total_group)
right_layout.addWidget(complete_sale_btn)
right_layout.addWidget(clear_sale_btn)
right_layout.addStretch()
main_layout.addLayout(left_layout, stretch=3) # Left side takes 3/4 of space
main_layout.addLayout(right_layout, stretch=1) # Right side takes 1/4
self.pos_tab.setLayout(main_layout)
#Hashtags: #PointOfSale #BarcodeScanner #UIUX #PyQt5
---
#Step 4: Implementing the Sales LogicThis is the core logic that connects the barcode input to the sales table and the database. When a barcode is entered, we find the drug, add it to the current sale, and update the UI. The "Complete Sale" button will finalize the transaction by updating the database.
Add these methods to the
PharmacyApp class: