Running a freelance business means drowning in billing admin: creating invoices, tracking payments, sending reminders. Here's how to automate the entire pipeline with Python.
The Problem
Manual billing wastes 3-5 hours per week for most freelancers. That's 150-250 hours per year — at $75/hour billing rate, that's $11,000-$18,000 of lost revenue potential.
Step 1: Invoice Generation
from reportlab.platypus import SimpleDocTemplate, Paragraph, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib import colors
import datetime
def generate_invoice(client_name, items, invoice_num):
doc = SimpleDocTemplate(f"invoice_{invoice_num}.pdf")
styles = getSampleStyleSheet()
story = []
story.append(Paragraph(f"INVOICE #{invoice_num}", styles["Title"]))
story.append(Paragraph(f"Date: {str(datetime.date.today())}", styles["Normal"]))
data = [["Description", "Hours", "Rate", "Total"]]
total = 0
for item in items:
subtotal = item["hours"] * item["rate"]
total += subtotal
data.append([item["desc"], item["hours"], f"${item['rate']}", f"${subtotal:.2f}"])
data.append(["", "", "TOTAL", f"${total:.2f}"])
table = Table(data)
table.setStyle(TableStyle([
("BACKGROUND", (0, 0), (-1, 0), colors.grey),
("GRID", (0, 0), (-1, -1), 1, colors.black),
]))
story.append(table)
doc.build(story)
return total
Step 2: Automated Email Delivery
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
def send_invoice(to_email, client_name, pdf_path, amount, invoice_num):
msg = MIMEMultipart()
msg["From"] = "your@email.com"
msg["To"] = to_email
msg["Subject"] = f"Invoice #{invoice_num} - ${amount:.2f} due"
body = f"Hi {client_name}, please find Invoice #{invoice_num} for ${amount:.2f} attached."
msg.attach(MIMEText(body, "plain"))
with open(pdf_path, "rb") as f:
part = MIMEBase("application", "octet-stream")
part.set_payload(f.read())
encoders.encode_base64(part)
part.add_header("Content-Disposition", f"attachment; filename=invoice_{invoice_num}.pdf")
msg.attach(part)
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server:
server.login("you@gmail.com", "app-password")
server.send_message(msg)
Step 3: Payment Tracking
import sqlite3
import datetime
conn = sqlite3.connect("billing.db")
c = conn.cursor()
c.execute("""
CREATE TABLE IF NOT EXISTS invoices
(id TEXT PRIMARY KEY, client TEXT, amount REAL,
sent_date TEXT, due_date TEXT, paid_date TEXT, status TEXT)
""")
conn.commit()
def record_invoice(invoice_num, client, amount):
sent = str(datetime.date.today())
due = str(datetime.date.today() + datetime.timedelta(days=30))
c.execute("INSERT INTO invoices VALUES (?,?,?,?,?,?,?)",
(invoice_num, client, amount, sent, due, None, "sent"))
conn.commit()
def get_overdue():
today = str(datetime.date.today())
return c.execute(
"SELECT * FROM invoices WHERE due_date < ? AND status = ?",
(today, "sent")
).fetchall()
Step 4: Automated Follow-Ups
import schedule
import time
def check_and_follow_up():
for invoice in get_overdue():
sent_date = datetime.date.fromisoformat(invoice[3])
days_late = (datetime.date.today() - sent_date).days
if days_late == 7:
send_reminder(invoice[1], invoice[2], "gentle")
elif days_late == 14:
send_reminder(invoice[1], invoice[2], "firm")
elif days_late == 30:
send_reminder(invoice[1], invoice[2], "urgent")
schedule.every().day.at("09:00").do(check_and_follow_up)
while True:
schedule.run_pending()
time.sleep(60)
The Full System
This billing pipeline — plus 40+ more automation scripts covering client onboarding, project tracking, and business reporting — is in the Python Business Automation Toolkit.
Set it up once in about 3 hours. It runs forever with zero ongoing cost.
Top comments (0)