DEV Community

Brad
Brad

Posted on

Python for Freelancers: Automate Invoicing, Follow-ups, and Time Tracking

Running a freelance business means juggling invoices, client emails, and time tracking. Most freelancers waste 5-10 hours per week on admin.

Python automates nearly all of it. Here are 4 scripts I use daily:

1. PDF Invoice Generator

from fpdf import FPDF
import datetime

def create_invoice(client_name, hours, rate, project_desc):
    pdf = FPDF()
    pdf.add_page()
    pdf.set_font("Helvetica", size=16)

    total = hours * rate
    pdf.cell(200, 10, txt="INVOICE", ln=True, align="C")
    pdf.set_font("Helvetica", size=12)
    pdf.cell(200, 8, txt="Client: " + client_name, ln=True)
    pdf.cell(200, 8, txt="Project: " + project_desc, ln=True)
    pdf.cell(200, 8, txt="Hours: " + str(hours) + " @ $" + str(rate) + "/hr", ln=True)
    pdf.set_font("Helvetica", "B", size=14)
    pdf.cell(200, 10, txt="TOTAL: $" + str(total), ln=True)

    filename = "invoice_" + client_name + ".pdf"
    pdf.output(filename)
    return filename

# One call to generate a professional PDF invoice
create_invoice("Acme Corp", 20, 75, "Website automation project")
Enter fullscreen mode Exit fullscreen mode

2. Client Follow-up Scheduler

import json
from datetime import datetime, timedelta

def schedule_followup(client_email, message, days=3, contacts_file="clients.json"):
    try:
        with open(contacts_file) as f:
            contacts = json.load(f)
    except FileNotFoundError:
        contacts = {}

    contacts[client_email] = {
        "message": message,
        "due": (datetime.now() + timedelta(days=days)).isoformat(),
        "sent": False
    }
    with open(contacts_file, "w") as f:
        json.dump(contacts, f)
    print("Follow-up scheduled for " + client_email + " in " + str(days) + " days")

schedule_followup(
    "client@example.com",
    "Hi, following up on our proposal from last week!",
    days=3
)
Enter fullscreen mode Exit fullscreen mode

3. Time Tracker with Earnings Report

import time, json
from datetime import datetime

class TimeTracker:
    def __init__(self, project, rate):
        self.project = project
        self.rate = rate
        self.start_time = None
        self.sessions = []

    def start(self):
        self.start_time = time.time()
        print("Timer started for: " + self.project)

    def stop(self, description=""):
        elapsed = (time.time() - self.start_time) / 3600
        earned = elapsed * self.rate
        self.sessions.append({
            "date": datetime.now().isoformat(),
            "hours": round(elapsed, 2),
            "earned": round(earned, 2),
            "description": description
        })
        print("Logged: " + str(round(elapsed,2)) + "h = $" + str(round(earned,2)))
        self.start_time = None

    def report(self):
        total = sum(s["earned"] for s in self.sessions)
        print("Total earned on " + self.project + ": $" + str(round(total, 2)))

tracker = TimeTracker("Client Project", 75)
tracker.start()
# ... work ...
tracker.stop("Implemented API integration")
tracker.report()
Enter fullscreen mode Exit fullscreen mode

4. Expense Tracker

import csv
from datetime import datetime
from pathlib import Path

def add_expense(desc, category, amount, file="expenses.csv"):
    write_header = not Path(file).exists()
    with open(file, "a", newline="") as f:
        w = csv.writer(f)
        if write_header:
            w.writerow(["Date", "Description", "Category", "Amount"])
        w.writerow([datetime.now().date(), desc, category, amount])
    print("Logged: " + desc + " - $" + str(amount))

add_expense("Python course", "Education", 197)
add_expense("VS Code Pro", "Software", 49)
Enter fullscreen mode Exit fullscreen mode

Get 12 Ready-to-Use Scripts

These are 4 of 12 scripts in my Python Business Automation Toolkit (9).

The full package includes: invoice generator, email automation, business dashboard, lead tracker, backup tool, and more. All documented, all ready to run.

At 9 it pays for itself after one saved hour.


What admin task costs you the most time? I might have a script for it.

Top comments (0)