Data Science Jupyter Notebooks
11.5K subscribers
284 photos
42 videos
9 files
802 links
Explore the world of Data Science through Jupyter Notebooks—insights, tutorials, and tools to boost your data journey. Code, analyze, and visualize smarter with every post.
Download Telegram
#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.

---

#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 UI

Create 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 Handling

Now, 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 Logic

This 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: