Adding Barcodes and QR Codes to Invoices for Warehouse Tracking using Python

In fulfillment warehouses, tracking invoices as they move through different stations is essential for efficiency. By embedding barcodes or QR codes onto invoices, you create a simple and effective system for monitoring each stage of fulfillment.

This article will show you how to add barcodes and QR codes to a PDF or Word document invoice. We’ll use a Python script to handle the generation of these codes and show how to test them using your cell phone.

Setting Up the Environment

Before diving into the code, create a virtual environment to keep the project dependencies isolated.

On Windows:

python -m venv venv_invoice_tracker
venv_invoice_tracker\Scripts\activate
pip install python-barcode qrcode reportlab PyPDF2

On Linux:

python3 -m venv venv_invoice_tracker
source venv_invoice_tracker/bin/activate
pip install python-barcode qrcode reportlab PyPDF2

Adding Barcodes and QR Codes to Invoices

Let’s assume the invoice is named invoice_template.pdf. Our goal is to generate a PDF with a unique barcode and QR code for tracking.

Step 1: Generate Barcodes and QR Codes

Create a Python script named generate_codes.py:

from barcode import Code128
from barcode.writer import ImageWriter
import qrcode

def generate_barcode(data, filename):
    """
    Generates a barcode image.
    Args:
        data (str): The data for the barcode.
        filename (str): The output image filename.
    """
    barcode = Code128(data, writer=ImageWriter())
    barcode.save(filename)

def generate_qr_code(data, filename):
    """
    Generates a QR code image.
    Args:
        data (str): The data for the QR code.
        filename (str): The output image filename.
    """
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_L,
        box_size=10,
        border=4
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(filename)

if __name__ == "__main__":
    invoice_id = "INV12345"
    generate_barcode(invoice_id, "barcode") # Code128 class in the python-barcode library automatically appends the file extension (.png)
    generate_qr_code(invoice_id, "qrcode.png")
    print(f"Generated barcode and QR code for invoice {invoice_id}.")

This script generates a barcode and QR code based on an invoice ID. The files barcode.png and qrcode.png will be created in the same folder.

NOTE: The line from barcode import Code128 in Python imports the Code128 class from the python-barcode library. This library is used to generate various types of barcodes programmatically. The Code128 class specifically supports generating Code 128 barcodes, which are widely used in shipping, packaging, and tracking systems due to their high density and ability to encode all 128 ASCII characters.

Output: What Does This Generate?

The output will be a PNG image of a Code 128 barcode and a QR code. Scanning either with a compatible reader will decode it back to the original data (INV12345 in this case).

QRCode and Barcode Created by generate_codes.py

Step 2: Embed Codes into a PDF

Next, embed these images into your PDF. Create a new script named embed_codes.py:

from reportlab.pdfgen import canvas
from PyPDF2 import PdfReader, PdfWriter
from io import BytesIO

def add_codes_to_pdf(input_pdf, output_pdf, barcode_path, qr_code_path):
    """
    Embeds a barcode and QR code into an existing PDF.
    Args:
        input_pdf (str): Path to the input PDF template.
        output_pdf (str): Path to the output PDF with embedded codes.
        barcode_path (str): Path to the barcode image.
        qr_code_path (str): Path to the QR code image.
    """
    # Page dimensions for 8.5 x 12 inches (portrait orientation)
    page_width = 612  # 8.5 inches
    page_height = 864  # 12 inches
    
    # Create a new PDF with the codes
    packet = BytesIO()
    c = canvas.Canvas(packet, pagesize=(page_width, page_height))
    
    # Dimensions for the images
    barcode_width, barcode_height = 200, 50  # Adjust as needed
    qr_code_width, qr_code_height = 100, 100  # Adjust as needed

    # Calculate bottom-right positions
    barcode_x = page_width - barcode_width - 20  # 20-point margin from the right
    barcode_y = 20  # 20-point margin from the bottom
    qr_code_x = page_width - qr_code_width - 20  # Align QR code with barcode on the right
    qr_code_y = barcode_y + barcode_height + 10  # 10-point gap above the barcode

    # Add barcode
    c.drawImage(barcode_path, barcode_x, barcode_y, width=barcode_width, height=barcode_height)
    
    # Add QR code
    c.drawImage(qr_code_path, qr_code_x, qr_code_y, width=qr_code_width, height=qr_code_height)
    
    c.save()
    packet.seek(0)
    
    # Read the original PDF
    reader = PdfReader(input_pdf)
    writer = PdfWriter()
    
    # Overlay the new PDF onto each page of the original PDF
    overlay = PdfReader(packet).pages[0]
    for page in reader.pages:
        page.merge_page(overlay)
        writer.add_page(page)
    
    # Write the final PDF
    with open(output_pdf, "wb") as output_file:
        writer.write(output_file)
    print(f"Generated {output_pdf} with embedded codes.")

if __name__ == "__main__":
    add_codes_to_pdf("invoice_template.pdf", "tracked_invoice.pdf", "barcode.png", "qrcode.png")

This script takes the original invoice template and embeds the barcode and QR code images into it. You can adjust the x and y positions to place the codes in your desired locations.

For testing, I downloaded the sample pdf found here, then placed that pdf in the root folder and named it invoice_template.pdf.

Below is the result after running embed_codes.py.

QRCode and Barcode Embedded using Python

How to Place the QR Code and Barcode Where You Want

The placement of the barcode and QR code is controlled by their X and Y coordinates, as well as their dimensions (width and height).

Key Variables for Positioning

Page Dimensions:

  • Defined as page_width = 612 (8.5 inches) and page_height = 864 (12 inches). These correspond to a standard portrait-oriented page.

Barcode and QR Code Dimensions:

  • barcode_width and barcode_height specify the size of the barcode.
  • qr_code_width and qr_code_height specify the size of the QR code.

X and Y Coordinates:

  • barcode_x and barcode_y define the position of the bottom-left corner of the barcode.
  • qr_code_x and qr_code_y define the position of the bottom-left corner of the QR code.

Adjusting Placement

To change where the QR code and barcode appear, update the barcode_x, barcode_y, qr_code_x, and qr_code_y values.

Example Placement Scenarios:

  1. Top-Right Corner:
barcode_x = page_width - barcode_width - 20
barcode_y = page_height - barcode_height - 20
qr_code_x = page_width - qr_code_width - 20
qr_code_y = barcode_y - qr_code_height - 10
  • Places the barcode at the top-right with a 20-point margin.
  • Positions the QR code below the barcode.

Top-Center:

barcode_x = (page_width - barcode_width) / 2
barcode_y = page_height - barcode_height - 20
qr_code_x = barcode_x
qr_code_y = barcode_y - qr_code_height - 10
  • Centers both the barcode and QR code at the top of the page.

Bottom-Left Corner:

barcode_x = 20
barcode_y = 20
qr_code_x = 20
qr_code_y = barcode_y + barcode_height + 10
  • Places the barcode in the bottom-left corner.
  • Positions the QR code above the barcode.

Middle of the Page:

barcode_x = (page_width - barcode_width) / 2
barcode_y = (page_height - barcode_height) / 2
qr_code_x = barcode_x
qr_code_y = barcode_y + barcode_height + 10
  • Centers the barcode horizontally and vertically on the page.
  • Positions the QR code above the barcode.

Testing the Codes Using a Mobile Phone

Without a barcode scanner, your phone can be used for testing. Install a barcode or QR code reader app, which is available for most smartphones.

  1. Open the tracked_invoice.pdf on your computer or print it out.
  2. Use the app to scan the barcode or QR code.
  3. Confirm that the scanned result matches the invoice ID (e.g., INV12345).
QR Code Read from PDF on Cell Phone

Expanding the Workflow for Fulfillment Tracking

The generated PDF can now be tracked at various stages of the fulfillment process. As the invoice moves through the warehouse:

  1. The QR code can be scanned to confirm arrival at specific stations.
  2. Optical Character Recognition (OCR) libraries can be used to read the invoice or customer number from the pdf, then make that the Barcode or QR Code.
  3. Updates can be logged into a system, which tracks progress in real-time.

For example, if your cell phone app sends the scanned data to a server, you can extend the workflow by capturing timestamps, user IDs, and station details.

Example: QR Code Station Confirmation System

Step 1: Install Required Libraries

Install Flask and SQLite (built into Python):

pip install flask

Step 2: Set Up the Flask Application

Create a file named station_server.py:

from flask import Flask, request, jsonify
import sqlite3
from datetime import datetime

app = Flask(__name__)

# Initialize SQLite database
DATABASE = 'station_log.db'

def init_db():
    conn = sqlite3.connect(DATABASE)
    cursor = conn.cursor()
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS station_log (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            invoice_id TEXT NOT NULL,
            station TEXT NOT NULL,
            timestamp TEXT NOT NULL
        )
    ''')
    conn.commit()
    conn.close()

# Route to log QR code scans
@app.route('/scan', methods=['POST'])
def scan_qr_code():
    data = request.json
    invoice_id = data.get('invoice_id')
    station = data.get('station')

    if not invoice_id or not station:
        return jsonify({'error': 'Missing invoice_id or station'}), 400

    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

    # Log the scan into the database
    conn = sqlite3.connect(DATABASE)
    cursor = conn.cursor()
    cursor.execute('''
        INSERT INTO station_log (invoice_id, station, timestamp)
        VALUES (?, ?, ?)
    ''', (invoice_id, station, timestamp))
    conn.commit()
    conn.close()

    return jsonify({'message': 'Scan logged successfully', 'invoice_id': invoice_id, 'station': station, 'timestamp': timestamp}), 200

# Route to fetch logs
@app.route('/logs', methods=['GET'])
def get_logs():
    conn = sqlite3.connect(DATABASE)
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM station_log')
    logs = cursor.fetchall()
    conn.close()

    return jsonify({'logs': logs})

if __name__ == '__main__':
    init_db()
    app.run(host='0.0.0.0', port=5000)

Step 3: How It Works

QR Code Scanning:

  • A QR code scanner (e.g., a mobile app or hardware scanner) sends a POST request to the /scan endpoint.
  • The request includes the invoice_id and the station name as JSON.

Example JSON payload:

{
    "invoice_id": "INV12345",
    "station": "Station A"
}

Log Storage:

  • The server logs the invoice_id, station, and a timestamp into the SQLite database.

Logs Retrieval:

  • You can view all logs by sending a GET request to /logs.

Step 4: Test the System

Run the Flask app:

python station_server.py

Use curl or any HTTP client to test the endpoints:

  • Log a scan:
curl -X POST -H "Content-Type: application/json" -d '{"invoice_id": "INV12345", "station": "Station A"}' http://localhost:5000/scan

Fetch logs:

curl http://localhost:5000/logs

Database Structure

The SQLite database (station_log.db) stores scan logs with the following columns:

  • id: Auto-incrementing primary key.
  • invoice_id: The scanned QR code’s invoice identifier.
  • station: The station where the QR code was scanned.
  • timestamp: The date and time of the scan.

Python can create an integrated fulfillment system that gathers station-specific details, such as completed tasks. A straightforward app or user interface can facilitate QR code scanning, sending requests, and triggering alerts when an invoice reaches a specific station or encounters delays.


Thank you for reading this article. I hope you found it helpful and informative. If you have any questions, or if you would like to suggest new Python code examples or topics for future tutorials, please feel free to reach out. Your feedback and suggestions are always welcome!

Happy coding!
C. C. Python Programming

You can also find this article at Medium.com

Leave a Reply