Project 5: Automated Invoice Generator with Email Delivery

Project 5: Automated Invoice Generator with Email Delivery

Build a system that generates personalized invoices in Excel and emails them to customers automatically.


Project Overview

Your company sends monthly invoices to hundreds of customers. Currently, someone manually fills in an Excel template for each customer, saves it as PDF, and emails it. Your task: automate the entire workflow.

What Youโ€™ll Build

  • Read customer data and billing details from a database or Excel file
  • For each customer, generate a personalized invoice using an Excel template
  • Populate invoice with customer-specific data (name, items, amounts, taxes)
  • Apply business logic (discounts, tax calculations, late fees)
  • Save each invoice as a PDF
  • Send invoices via email with personalized messages
  • Generate a summary report of all invoices sent

Technologies

  • openpyxl for Excel template manipulation
  • xlsxwriter or openpyxl for invoice generation
  • PDF generation (Excelโ€™s built-in PDF export or reportlab)
  • smtplib for email sending
  • jinja2 for email template rendering (optional)

Learning Objectives

By completing this project, you will:

  1. Master template-based document generation - Merge data with templates
  2. Implement business logic - Discounts, taxes, late fees
  3. Generate PDFs from Excel - Cross-platform considerations
  4. Send emails with Python - SMTP, attachments, HTML formatting
  5. Handle batch processing - Progress tracking, error recovery
  6. Build auditable systems - Logging, reports, verification

Deep Theoretical Foundation

Template-Based Document Generation

Template-based generation separates structure from content, enabling scalable document creation:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              TEMPLATE-BASED GENERATION PATTERN                   โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  TEMPLATE (Structure)                                            โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚    โ”‚
โ”‚  โ”‚  โ”‚            YOUR COMPANY NAME                        โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Invoice #: {{invoice_number}}                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Date: {{invoice_date}}                             โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Bill To:                                           โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    {{customer_name}}                                โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    {{customer_address}}                             โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  {{#line_items}}                                    โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    {{description}} | {{qty}} | {{price}}           โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  {{/line_items}}                                    โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Total: {{total}}                                   โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              +                                   โ”‚
โ”‚  DATA (Content)                                                  โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  {                                                       โ”‚    โ”‚
โ”‚  โ”‚    "invoice_number": "INV-2024-12-001",                 โ”‚    โ”‚
โ”‚  โ”‚    "invoice_date": "December 31, 2024",                 โ”‚    โ”‚
โ”‚  โ”‚    "customer_name": "Acme Corporation",                 โ”‚    โ”‚
โ”‚  โ”‚    "customer_address": "123 Main St",                   โ”‚    โ”‚
โ”‚  โ”‚    "line_items": [                                      โ”‚    โ”‚
โ”‚  โ”‚      {"description": "Widget", "qty": 5, "price": 100},โ”‚    โ”‚
โ”‚  โ”‚      {"description": "Gadget", "qty": 3, "price": 50}  โ”‚    โ”‚
โ”‚  โ”‚    ],                                                   โ”‚    โ”‚
โ”‚  โ”‚    "total": 650                                         โ”‚    โ”‚
โ”‚  โ”‚  }                                                       โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              =                                   โ”‚
โ”‚  OUTPUT (Merged Document)                                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚    โ”‚
โ”‚  โ”‚  โ”‚            YOUR COMPANY NAME                        โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Invoice #: INV-2024-12-001                         โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Date: December 31, 2024                            โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Bill To:                                           โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    Acme Corporation                                 โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    123 Main St                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    Widget | 5 | $100                                โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚    Gadget | 3 | $50                                 โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚                                                      โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ”‚  Total: $650                                        โ”‚โ”‚    โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Template-Based Generation Pattern

Business Logic: Invoice Calculations

Invoice calculations follow a specific order of operations:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              INVOICE CALCULATION FLOW                            โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  LINE ITEMS                                                      โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                                     โ”‚
โ”‚  Item 1: Widget ร— 50 units ร— $125.00 = $6,250.00                โ”‚
โ”‚  Item 2: Gadget ร— 30 units ร— $89.50  = $2,685.00                โ”‚
โ”‚  Item 3: Tool   ร— 75 units ร— $67.30  = $5,047.50                โ”‚
โ”‚                                    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                 โ”‚
โ”‚                                    SUBTOTAL: $13,982.50         โ”‚
โ”‚                                                                   โ”‚
โ”‚  DISCOUNT (Applied first)                                        โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                                        โ”‚
โ”‚  Customer discount rate: 10%                                    โ”‚
โ”‚  Discount amount: $13,982.50 ร— 0.10 = $1,398.25                โ”‚
โ”‚                                    โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                 โ”‚
โ”‚                       SUBTOTAL AFTER DISCOUNT: $12,584.25       โ”‚
โ”‚                                                                   โ”‚
โ”‚  TAX (Applied to discounted subtotal)                           โ”‚
โ”‚  โ”€โ”€โ”€โ”€                                                            โ”‚
โ”‚  Tax rate: 9%                                                   โ”‚
โ”‚  Tax amount: $12,584.25 ร— 0.09 = $1,132.58                     โ”‚
โ”‚                                                                   โ”‚
โ”‚  LATE FEE (If applicable)                                        โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                                        โ”‚
โ”‚  Previous invoice overdue: Yes                                  โ”‚
โ”‚  Late fee: 1% of previous balance = $87.50                     โ”‚
โ”‚                                                                   โ”‚
โ”‚  FINAL CALCULATION                                               โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                                               โ”‚
โ”‚  Subtotal after discount:  $12,584.25                           โ”‚
โ”‚  Tax:                      + $1,132.58                          โ”‚
โ”‚  Late fee:                 +    $87.50                          โ”‚
โ”‚                            โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                         โ”‚
โ”‚  TOTAL DUE:                 $13,804.33                          โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Invoice Calculation Flow

Email Architecture: SMTP Deep Dive

Understanding email protocols is essential for reliable delivery:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   EMAIL SENDING ARCHITECTURE                     โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  YOUR PYTHON SCRIPT                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  smtplib.SMTP('smtp.gmail.com', 587)                    โ”‚    โ”‚
โ”‚  โ”‚  server.starttls()  # Upgrade to secure connection      โ”‚    โ”‚
โ”‚  โ”‚  server.login(username, password)                       โ”‚    โ”‚
โ”‚  โ”‚  server.send_message(msg)                               โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  YOUR EMAIL PROVIDER (e.g., Gmail)                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  SMTP Server: smtp.gmail.com:587                        โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  Authentication check:                                   โ”‚    โ”‚
โ”‚  โ”‚    โœ“ Valid username/password or app password            โ”‚    โ”‚
โ”‚  โ”‚    โœ“ 2FA compliance (if required)                       โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  Spam checks:                                            โ”‚    โ”‚
โ”‚  โ”‚    โœ“ SPF record valid?                                  โ”‚    โ”‚
โ”‚  โ”‚    โœ“ DKIM signature?                                    โ”‚    โ”‚
โ”‚  โ”‚    โœ“ Rate limiting (max emails/hour)                    โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  RECIPIENT'S EMAIL SERVER                                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  Receiving checks:                                       โ”‚    โ”‚
โ”‚  โ”‚    โ€ข Is sender domain legitimate?                       โ”‚    โ”‚
โ”‚  โ”‚    โ€ข Spam score acceptable?                             โ”‚    โ”‚
โ”‚  โ”‚    โ€ข Virus scan passed?                                 โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  Delivery:                                               โ”‚    โ”‚
โ”‚  โ”‚    โ†’ Inbox (if checks pass)                             โ”‚    โ”‚
โ”‚  โ”‚    โ†’ Spam folder (if suspicious)                        โ”‚    โ”‚
โ”‚  โ”‚    โ†’ Rejected (if blacklisted)                          โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  RECIPIENT'S INBOX                                               โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  From: billing@yourcompany.com                          โ”‚    โ”‚
โ”‚  โ”‚  Subject: Your December 2024 Invoice - $13,804.33       โ”‚    โ”‚
โ”‚  โ”‚  Attachment: Invoice_INV-2024-12-001.pdf                โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Email Sending Architecture

MIME Message Structure

Email attachments require understanding MIME (Multipurpose Internet Mail Extensions):

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                   MIME MESSAGE STRUCTURE                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  MIMEMultipart (Container)                                       โ”‚
โ”‚  โ”œโ”€โ”€ Headers                                                     โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ From: billing@yourcompany.com                          โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ To: customer@client.com                                โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ Subject: Your Invoice                                  โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ Content-Type: multipart/mixed                          โ”‚
โ”‚  โ”‚                                                                โ”‚
โ”‚  โ”œโ”€โ”€ Part 1: MIMEText (alternative)                             โ”‚
โ”‚  โ”‚   โ”œโ”€โ”€ text/plain version                                     โ”‚
โ”‚  โ”‚   โ”‚   "Dear John, Please find attached..."                   โ”‚
โ”‚  โ”‚   โ””โ”€โ”€ text/html version (optional)                           โ”‚
โ”‚  โ”‚       "<html><body><h1>Invoice</h1>..."                      โ”‚
โ”‚  โ”‚                                                                โ”‚
โ”‚  โ””โ”€โ”€ Part 2: MIMEBase (attachment)                              โ”‚
โ”‚      โ”œโ”€โ”€ Content-Type: application/pdf                          โ”‚
โ”‚      โ”œโ”€โ”€ Content-Disposition: attachment; filename="invoice.pdf"โ”‚
โ”‚      โ””โ”€โ”€ Content (base64 encoded PDF bytes)                     โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

PDF Generation Strategies

There are multiple approaches to generating PDFs from Excel:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                PDF GENERATION STRATEGIES                         โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  STRATEGY 1: Excel's Native PDF Export (Windows + Excel)        โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”‚
โ”‚  Pros:                                                           โ”‚
โ”‚    โœ“ Perfect fidelity - exactly matches Excel view              โ”‚
โ”‚    โœ“ Supports all Excel features (charts, formatting)          โ”‚
โ”‚    โœ“ Simple API via win32com                                    โ”‚
โ”‚  Cons:                                                           โ”‚
โ”‚    โœ— Requires Excel installed                                   โ”‚
โ”‚    โœ— Windows only (or Mac with modifications)                   โ”‚
โ”‚    โœ— Slower (launches Excel process)                            โ”‚
โ”‚                                                                   โ”‚
โ”‚  Code:                                                           โ”‚
โ”‚    excel = win32com.client.Dispatch("Excel.Application")        โ”‚
โ”‚    wb = excel.Workbooks.Open(xlsx_path)                         โ”‚
โ”‚    wb.ExportAsFixedFormat(0, pdf_path)  # 0 = PDF               โ”‚
โ”‚                                                                   โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”‚
โ”‚                                                                   โ”‚
โ”‚  STRATEGY 2: LibreOffice Headless (Cross-platform)              โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”‚
โ”‚  Pros:                                                           โ”‚
โ”‚    โœ“ Free and open source                                       โ”‚
โ”‚    โœ“ Works on Linux, Mac, Windows                               โ”‚
โ”‚    โœ“ Good Excel compatibility                                   โ”‚
โ”‚  Cons:                                                           โ”‚
โ”‚    โœ— Requires LibreOffice installed                             โ”‚
โ”‚    โœ— Some formatting may differ                                 โ”‚
โ”‚                                                                   โ”‚
โ”‚  Code:                                                           โ”‚
โ”‚    subprocess.run(['libreoffice', '--headless',                 โ”‚
โ”‚                    '--convert-to', 'pdf', xlsx_path])           โ”‚
โ”‚                                                                   โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”‚
โ”‚                                                                   โ”‚
โ”‚  STRATEGY 3: Generate PDF Directly (No Excel)                   โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€  โ”‚
โ”‚  Pros:                                                           โ”‚
โ”‚    โœ“ No external dependencies                                   โ”‚
โ”‚    โœ“ Full control over output                                   โ”‚
โ”‚    โœ“ Works anywhere Python runs                                 โ”‚
โ”‚  Cons:                                                           โ”‚
โ”‚    โœ— Must recreate layout in code                               โ”‚
โ”‚    โœ— More code to write                                         โ”‚
โ”‚                                                                   โ”‚
โ”‚  Libraries: reportlab, weasyprint, fpdf                         โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Core Question Youโ€™re Answering

โ€œHow do I transform data into personalized, professional documents at scale?โ€

This is template-based document automationโ€”a foundational pattern in business automation. Youโ€™re learning to separate structure (the template) from content (the data), then merge them programmatically.


Project Specification

Input Requirements

  1. Customer/Billing Data: customer_billing.xlsx or database
    customer_id | name | address | city | state | zip | email | discount_rate | payment_terms
    
  2. Line Items Data: Transactions for the billing period
    customer_id | product | quantity | unit_price | date
    
  3. Invoice Template: invoice_template.xlsx
    • Pre-designed layout with placeholder cells
    • Formatting, logos, and structure already defined

Output Requirements

  1. Individual Invoices (per customer):
    • Excel file: invoices/2024-12/{Customer}_INV-YYYY-MM-XXX.xlsx
    • PDF file: invoices/2024-12/{Customer}_INV-YYYY-MM-XXX.pdf
  2. Email Sent to each customer with:
    • Personalized subject line
    • Professional body text with invoice summary
    • PDF attachment
  3. Summary Report: Invoice_Summary_YYYY-MM.xlsx
    • List of all invoices generated
    • Total revenue
    • Email delivery status
    • Any errors or flagged items

Functional Requirements

  • Support variable number of line items (1-100+)
  • Apply customer-specific discount rates
  • Calculate tax based on location
  • Add late fees for overdue accounts
  • Handle email failures gracefully (retry, log, continue)
  • Idempotent: safe to run multiple times for same period
  • Generate unique sequential invoice numbers

Solution Architecture

Component Design

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                 INVOICE AUTOMATION SYSTEM                        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚                    DATA LAYER                              โ”‚ โ”‚
โ”‚  โ”‚                                                              โ”‚ โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ CustomerDB โ”‚   โ”‚ LineItems  โ”‚   โ”‚ InvoiceNum โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚            โ”‚   โ”‚            โ”‚   โ”‚  Sequence  โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข get_all()โ”‚   โ”‚ โ€ข by_cust()โ”‚   โ”‚ โ€ข next()   โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข by_id()  โ”‚   โ”‚ โ€ข by_date()โ”‚   โ”‚ โ€ข reserve()โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚                  BUSINESS LOGIC LAYER                      โ”‚ โ”‚
โ”‚  โ”‚                                                              โ”‚ โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ Calculator โ”‚   โ”‚ Validator  โ”‚   โ”‚ LateFee    โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚            โ”‚   โ”‚            โ”‚   โ”‚  Checker   โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข subtotal โ”‚   โ”‚ โ€ข address  โ”‚   โ”‚ โ€ข is_late()โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข discount โ”‚   โ”‚ โ€ข email    โ”‚   โ”‚ โ€ข calc_fee()          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข tax      โ”‚   โ”‚ โ€ข items    โ”‚   โ”‚            โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข total    โ”‚   โ”‚            โ”‚   โ”‚            โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚                 GENERATION LAYER                           โ”‚ โ”‚
โ”‚  โ”‚                                                              โ”‚ โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ Template   โ”‚   โ”‚   PDF      โ”‚   โ”‚   Email    โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚  Engine    โ”‚   โ”‚ Generator  โ”‚   โ”‚  Sender    โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚            โ”‚   โ”‚            โ”‚   โ”‚            โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข load()   โ”‚   โ”‚ โ€ข convert()โ”‚   โ”‚ โ€ข compose()โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข fill()   โ”‚   โ”‚ โ€ข save()   โ”‚   โ”‚ โ€ข attach() โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข save()   โ”‚   โ”‚            โ”‚   โ”‚ โ€ข send()   โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚                  REPORTING LAYER                           โ”‚ โ”‚
โ”‚  โ”‚                                                              โ”‚ โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚  Summary   โ”‚   โ”‚   Logger   โ”‚   โ”‚   Error    โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚  Report    โ”‚   โ”‚            โ”‚   โ”‚  Handler   โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚            โ”‚   โ”‚ โ€ข info()   โ”‚   โ”‚            โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข create() โ”‚   โ”‚ โ€ข warn()   โ”‚   โ”‚ โ€ข capture()โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข add_row()โ”‚   โ”‚ โ€ข error()  โ”‚   โ”‚ โ€ข retry()  โ”‚          โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ โ€ข save()   โ”‚   โ”‚            โ”‚   โ”‚ โ€ข escalate()          โ”‚ โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  COMPLETE DATA FLOW                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  Phase 1: INITIALIZATION                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  1. Load configuration (SMTP settings, paths, tax rates)โ”‚    โ”‚
โ”‚  โ”‚  2. Connect to data sources                              โ”‚    โ”‚
โ”‚  โ”‚  3. Load invoice template                                โ”‚    โ”‚
โ”‚  โ”‚  4. Initialize invoice number sequence                   โ”‚    โ”‚
โ”‚  โ”‚  5. Create output directories                            โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  Phase 2: DATA GATHERING                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  1. Fetch all active customers                           โ”‚    โ”‚
โ”‚  โ”‚  2. For each customer:                                   โ”‚    โ”‚
โ”‚  โ”‚     a. Get line items for billing period                 โ”‚    โ”‚
โ”‚  โ”‚     b. Check for overdue balances                        โ”‚    โ”‚
โ”‚  โ”‚     c. Get customer-specific settings                    โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  Phase 3: PER-CUSTOMER PROCESSING (Loop)                        โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  For each customer with line items:                      โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  3a. CALCULATE                                           โ”‚    โ”‚
โ”‚  โ”‚      - Subtotal = sum(quantity ร— unit_price)            โ”‚    โ”‚
โ”‚  โ”‚      - Discount = subtotal ร— discount_rate              โ”‚    โ”‚
โ”‚  โ”‚      - Tax = (subtotal - discount) ร— tax_rate           โ”‚    โ”‚
โ”‚  โ”‚      - Late fee (if applicable)                         โ”‚    โ”‚
โ”‚  โ”‚      - Total = subtotal - discount + tax + late_fee     โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  3b. GENERATE INVOICE                                    โ”‚    โ”‚
โ”‚  โ”‚      - Load template copy                                โ”‚    โ”‚
โ”‚  โ”‚      - Fill customer info cells                          โ”‚    โ”‚
โ”‚  โ”‚      - Fill line items rows                              โ”‚    โ”‚
โ”‚  โ”‚      - Fill totals cells                                 โ”‚    โ”‚
โ”‚  โ”‚      - Save as .xlsx                                     โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  3c. CONVERT TO PDF                                      โ”‚    โ”‚
โ”‚  โ”‚      - Open .xlsx with Excel/LibreOffice                โ”‚    โ”‚
โ”‚  โ”‚      - Export as PDF                                     โ”‚    โ”‚
โ”‚  โ”‚      - Close and save                                    โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  3d. SEND EMAIL                                          โ”‚    โ”‚
โ”‚  โ”‚      - Compose email with customer name                  โ”‚    โ”‚
โ”‚  โ”‚      - Attach PDF                                        โ”‚    โ”‚
โ”‚  โ”‚      - Send via SMTP                                     โ”‚    โ”‚
โ”‚  โ”‚      - Log result (success/failure)                      โ”‚    โ”‚
โ”‚  โ”‚                                                          โ”‚    โ”‚
โ”‚  โ”‚  3e. RECORD IN SUMMARY                                   โ”‚    โ”‚
โ”‚  โ”‚      - Add row to summary report                         โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                              โ”‚                                   โ”‚
โ”‚                              โ–ผ                                   โ”‚
โ”‚  Phase 4: FINALIZATION                                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚  1. Save summary report                                  โ”‚    โ”‚
โ”‚  โ”‚  2. Save error log (if any failures)                    โ”‚    โ”‚
โ”‚  โ”‚  3. Print completion statistics                          โ”‚    โ”‚
โ”‚  โ”‚  4. Send admin notification (optional)                   โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Invoice Template Structure

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                  TEMPLATE CELL MAPPING                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                                   โ”‚
โ”‚  TEMPLATE CELL    PLACEHOLDER           DATA SOURCE              โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€     โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€           โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€              โ”‚
โ”‚  B2              COMPANY_LOGO           Static (in template)     โ”‚
โ”‚  B4              COMPANY_NAME           Static                   โ”‚
โ”‚  B5              COMPANY_ADDRESS        Static                   โ”‚
โ”‚  B6              COMPANY_PHONE          Static                   โ”‚
โ”‚                                                                   โ”‚
โ”‚  G4              {{invoice_number}}     Generated sequence       โ”‚
โ”‚  G5              {{invoice_date}}       datetime.now()           โ”‚
โ”‚  G6              {{due_date}}           invoice_date + 30 days   โ”‚
โ”‚                                                                   โ”‚
โ”‚  B10             {{customer_name}}      customers.name           โ”‚
โ”‚  B11             {{customer_address}}   customers.address        โ”‚
โ”‚  B12             {{customer_city_st_zip}} Formatted              โ”‚
โ”‚  B13             {{customer_email}}     customers.email          โ”‚
โ”‚                                                                   โ”‚
โ”‚  A17:E17+        LINE_ITEM_ROWS         line_items[]             โ”‚
โ”‚    A             Row number             Auto-generated           โ”‚
โ”‚    B             Description            line_items.product       โ”‚
โ”‚    C             Quantity               line_items.quantity      โ”‚
โ”‚    D             Unit Price             line_items.unit_price    โ”‚
โ”‚    E             Amount                 qty ร— unit_price         โ”‚
โ”‚                                                                   โ”‚
โ”‚  E47             {{subtotal}}           sum(line amounts)        โ”‚
โ”‚  E48             {{discount}}           subtotal ร— rate          โ”‚
โ”‚  E49             {{subtotal_after}}     subtotal - discount      โ”‚
โ”‚  E50             {{tax}}                subtotal_after ร— tax_rateโ”‚
โ”‚  E51             {{late_fee}}           if overdue: fee amount   โ”‚
โ”‚  E53             {{total_due}}          Final total              โ”‚
โ”‚                                                                   โ”‚
โ”‚  B55             {{payment_terms}}      customers.payment_terms  โ”‚
โ”‚                                                                   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Phased Implementation Guide

Phase 1: Template Design

Goal: Create a professional invoice template in Excel.

Tasks:

  1. Design invoice layout in Excel
  2. Add company branding (logo, colors)
  3. Mark placeholder cells with identifiable patterns
  4. Set print area and page layout
  5. Test that it looks correct when opened

Checkpoint: Template opens correctly and looks professional.

Phase 2: Data Loading

Goal: Load customer and billing data into Python.

Tasks:

  1. Read customer data from Excel/database
  2. Read line items for billing period
  3. Group line items by customer
  4. Validate required fields exist
  5. Handle missing/invalid data

Checkpoint: Dictionary of customer โ†’ line_items ready.

Phase 3: Invoice Calculation Logic

Goal: Implement accurate business calculations.

Tasks:

  1. Calculate line item amounts (qty ร— price)
  2. Calculate subtotal
  3. Apply customer discount rate
  4. Calculate tax based on location
  5. Check for and apply late fees
  6. Calculate final total

Checkpoint: All calculations match manual Excel verification.

Phase 4: Template Filling

Goal: Populate template with one customerโ€™s data.

Tasks:

  1. Load template as new workbook
  2. Write customer information
  3. Write line items (handling variable count)
  4. Write calculated totals
  5. Generate invoice number
  6. Save with customer-specific filename

Checkpoint: Single complete invoice generates correctly.

Phase 5: PDF Conversion

Goal: Convert Excel invoices to PDF.

Tasks:

  1. Choose PDF generation strategy
  2. Implement conversion function
  3. Handle page breaks for long invoices
  4. Verify PDF matches Excel formatting
  5. Save PDF alongside Excel file

Checkpoint: PDFs generate and look correct.

Phase 6: Email Composition

Goal: Create professional invoice emails.

Tasks:

  1. Create email template (plain text and HTML)
  2. Compose personalized subject line
  3. Build email body with invoice summary
  4. Attach PDF
  5. Test email locally (print to console)

Checkpoint: Email content is correct without actually sending.

Phase 7: Email Sending

Goal: Actually send emails via SMTP.

Tasks:

  1. Configure SMTP connection
  2. Handle authentication (app passwords)
  3. Send test email to yourself
  4. Implement retry logic for failures
  5. Log send results

Checkpoint: Emails arrive in inboxes with attachments.

Phase 8: Batch Processing

Goal: Process all customers efficiently.

Tasks:

  1. Implement main loop over customers
  2. Add progress tracking (tqdm)
  3. Handle per-customer errors (continue, donโ€™t crash)
  4. Collect all results for summary
  5. Implement rate limiting for email

Checkpoint: Full run processes all customers.

Phase 9: Summary Report

Goal: Generate audit trail and summary.

Tasks:

  1. Track all generated invoices
  2. Track all email send results
  3. Calculate total revenue
  4. Save summary to Excel
  5. Highlight any failures

Checkpoint: Summary accurately reflects run results.


Testing Strategy

Unit Tests

def test_calculate_subtotal():
    items = [
        {'quantity': 5, 'unit_price': 100},
        {'quantity': 3, 'unit_price': 50}
    ]
    assert calculate_subtotal(items) == 650

def test_apply_discount():
    subtotal = 1000
    discount_rate = 0.10
    result = apply_discount(subtotal, discount_rate)
    assert result == 900

def test_calculate_tax():
    amount = 900
    tax_rate = 0.09
    tax = calculate_tax(amount, tax_rate)
    assert tax == 81

def test_invoice_number_sequence():
    gen = InvoiceNumberGenerator('2024-12')
    assert gen.next() == 'INV-2024-12-001'
    assert gen.next() == 'INV-2024-12-002'

Integration Tests

def test_full_invoice_generation():
    customer = {
        'name': 'Test Customer',
        'email': 'test@example.com',
        'address': '123 Test St',
        'discount_rate': 0.10
    }
    items = [
        {'product': 'Widget', 'quantity': 5, 'unit_price': 100}
    ]

    invoice_path = generate_invoice(customer, items, 'INV-TEST-001')

    assert os.path.exists(invoice_path)
    wb = load_workbook(invoice_path)
    ws = wb.active
    assert ws['B10'].value == 'Test Customer'
    assert ws['E47'].value == 500  # subtotal

def test_pdf_generation():
    xlsx_path = 'test_invoice.xlsx'
    pdf_path = convert_to_pdf(xlsx_path)

    assert os.path.exists(pdf_path)
    assert pdf_path.endswith('.pdf')

def test_email_composition():
    msg = compose_invoice_email(
        customer_email='test@example.com',
        customer_name='John',
        invoice_number='INV-001',
        amount=1500.00,
        pdf_path='test.pdf'
    )

    assert msg['To'] == 'test@example.com'
    assert 'INV-001' in msg['Subject']
    assert len(msg.get_payload()) == 2  # body + attachment

Manual Testing Checklist

  • Invoice layout matches design
  • All placeholders filled correctly
  • Calculations are accurate
  • PDF looks identical to Excel
  • Email subject is personalized
  • Email body contains correct amounts
  • PDF attachment opens correctly
  • Email doesnโ€™t go to spam
  • Summary report is accurate
  • Error handling works (test with invalid email)

Common Pitfalls and Debugging

Pitfall 1: Email Goes to Spam

Symptom: Emails sent but not appearing in inbox.

Causes and solutions:

  1. Sender reputation: Use a reputable email service
  2. Missing SPF/DKIM: Configure domain DNS properly
  3. Suspicious subject: Avoid all-caps, โ€œFREEโ€, urgency words
  4. Too many recipients: Batch slowly, respect rate limits
  5. Plain text only: Include HTML version too

Pitfall 2: PDF Formatting Different from Excel

Symptom: PDF has different margins, page breaks, fonts.

Cause: Print settings not configured in template.

Solution:

  1. In template: Set Page Layout โ†’ Print Area
  2. Set Page Layout โ†’ Margins
  3. Set Page Layout โ†’ Page Breaks
  4. Test print preview before automating

Pitfall 3: Line Items Overflow

Symptom: Customer with 50 items breaks the template.

Cause: Fixed row count in template.

Solution:

def insert_line_items(ws, items, start_row):
    # Insert rows if needed
    if len(items) > MAX_TEMPLATE_ROWS:
        extra_rows = len(items) - MAX_TEMPLATE_ROWS
        ws.insert_rows(start_row + MAX_TEMPLATE_ROWS, extra_rows)

    # Copy formatting from template row
    template_row = ws[start_row]
    for i, item in enumerate(items):
        target_row = start_row + i
        # Apply template formatting
        copy_row_formatting(template_row, ws[target_row])
        # Fill data
        ws[f'A{target_row}'] = i + 1
        ws[f'B{target_row}'] = item['description']
        # ...

Pitfall 4: SMTP Authentication Failure

Symptom: โ€œAuthentication failedโ€ error.

Cause: Gmail/Outlook requires app-specific passwords.

Solution:

  1. For Gmail: Enable 2FA, create App Password
  2. For Outlook: Create app password or use OAuth
  3. Never use main account password in code

Pitfall 5: Memory Error on Large Batches

Symptom: Script crashes processing 500+ customers.

Cause: Keeping all invoices in memory.

Solution:

# Bad: Load all at once
all_invoices = [generate_invoice(c) for c in customers]

# Good: Process and release
for customer in customers:
    invoice = generate_invoice(customer)
    send_email(customer, invoice)
    # invoice is garbage collected here

Extensions and Challenges

Extension 1: Customer Portal Integration

Generate unique payment links for each invoice.

Skills practiced: URL generation, web integration

Extension 2: Payment Tracking

Update invoice status when payment received.

Skills practiced: State management, database updates, webhooks

Extension 3: Multi-Currency Support

Generate invoices in customerโ€™s local currency.

Skills practiced: Currency conversion APIs, formatting

Extension 4: Recurring Invoices

Automatically generate invoices on schedule.

Skills practiced: Scheduling, subscription management

Extension 5: Invoice Templates per Customer

Different customers get different template designs.

Skills practiced: Template selection logic, customization


Real-World Connections

Industry Applications

  • SaaS Companies: Monthly subscription invoices
  • Consulting Firms: Project billing and time tracking
  • Manufacturing: Order confirmations and invoices
  • Freelancers: Client billing automation

Career Relevance

This project demonstrates skills for:

  • Automation Engineer roles
  • Business Analyst positions
  • Backend Developer roles
  • DevOps Engineer (for scheduling/deployment)

Portfolio Value

When presenting:

  1. Show the volume handled (247 invoices in 4 minutes)
  2. Demonstrate error recovery
  3. Explain the template system flexibility
  4. Discuss security (credentials, customer data)

Interview Questions

Prepare to answer:

  1. โ€œHow would you handle invoices that need to be generated in multiple languages?โ€

  2. โ€œWhatโ€™s the best way to prevent email from being marked as spam?โ€

  3. โ€œHow do you securely store SMTP credentials?โ€

  4. โ€œWhat if a customer needs a correction to an already-sent invoice?โ€

  5. โ€œHow would you scale this to handle 10,000 invoices instead of 247?โ€

  6. โ€œWhatโ€™s the difference between generating Excel then converting to PDF vs generating PDF directly?โ€


Hints by Layer

Layer 1: Load Template and Customer Data

from openpyxl import load_workbook
import pandas as pd

# Load template
template = load_workbook('invoice_template.xlsx')

# Load customer data
customers = pd.read_excel('customer_billing_data.xlsx')

Layer 2: Fill Template for One Customer

def generate_invoice(customer_data, items, invoice_num):
    wb = load_workbook('invoice_template.xlsx')
    ws = wb.active

    # Fill in customer data
    ws['G4'] = f'INV-2024-12-{invoice_num:03d}'
    ws['G5'] = datetime.now().strftime('%B %d, %Y')
    ws['G6'] = (datetime.now() + timedelta(days=30)).strftime('%B %d, %Y')
    ws['B10'] = customer_data['name']
    ws['B11'] = customer_data['address']
    ws['B12'] = f"{customer_data['city']}, {customer_data['state']} {customer_data['zip']}"

    # Fill line items
    row = 17
    subtotal = 0
    for item in items:
        ws[f'A{row}'] = row - 16
        ws[f'B{row}'] = item['product']
        ws[f'C{row}'] = item['quantity']
        ws[f'D{row}'] = item['unit_price']
        amount = item['quantity'] * item['unit_price']
        ws[f'E{row}'] = amount
        subtotal += amount
        row += 1

    # Calculate totals
    discount = subtotal * customer_data['discount_rate']
    subtotal_after = subtotal - discount
    tax = subtotal_after * 0.09
    total = subtotal_after + tax

    ws['E47'] = subtotal
    ws['E48'] = -discount
    ws['E50'] = tax
    ws['E53'] = total

    filename = f"invoices/{customer_data['name'].replace(' ', '_')}_INV-{invoice_num:03d}.xlsx"
    wb.save(filename)
    return filename, total

Layer 3: Convert to PDF (Windows)

import win32com.client

def excel_to_pdf(excel_path):
    pdf_path = excel_path.replace('.xlsx', '.pdf')
    excel = win32com.client.Dispatch("Excel.Application")
    excel.Visible = False

    try:
        wb = excel.Workbooks.Open(os.path.abspath(excel_path))
        wb.ExportAsFixedFormat(0, os.path.abspath(pdf_path))
        wb.Close(False)
    finally:
        excel.Quit()

    return pdf_path

Layer 4: Send Email with Attachment

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders

def send_invoice_email(customer_email, customer_name, pdf_path, amount):
    sender = 'billing@yourcompany.com'
    password = 'your_app_password'  # Use environment variable in production!

    msg = MIMEMultipart()
    msg['From'] = sender
    msg['To'] = customer_email
    msg['Subject'] = f'Your December 2024 Invoice - ${amount:,.2f}'

    body = f"""Dear {customer_name},

Thank you for your continued business.

Please find attached your invoice for December 2024.

Amount Due: ${amount:,.2f}

Best regards,
Your Company Billing Team
"""
    msg.attach(MIMEText(body, 'plain'))

    # Attach PDF
    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={os.path.basename(pdf_path)}')
        msg.attach(part)

    # Send
    with smtplib.SMTP('smtp.gmail.com', 587) as server:
        server.starttls()
        server.login(sender, password)
        server.send_message(msg)

Layer 5: Batch Processing with Progress

from tqdm import tqdm

def process_all_invoices(customers, items_by_customer):
    results = []
    failures = []

    for idx, customer in tqdm(customers.iterrows(), total=len(customers)):
        try:
            items = items_by_customer.get(customer['id'], [])
            if not items:
                continue  # Skip customers with no items

            # Generate invoice
            excel_path, total = generate_invoice(customer, items, idx + 1)
            pdf_path = excel_to_pdf(excel_path)

            # Send email
            send_invoice_email(customer['email'], customer['name'], pdf_path, total)

            results.append({
                'customer': customer['name'],
                'invoice': os.path.basename(excel_path),
                'amount': total,
                'status': 'Sent'
            })

        except Exception as e:
            failures.append({
                'customer': customer['name'],
                'error': str(e)
            })

    return results, failures

Self-Assessment Checklist

Before considering complete:

  • Template designed and professional-looking
  • Customer data loads correctly
  • Line items grouped by customer
  • Calculations verified accurate
  • Invoices generate for all customers
  • PDFs match Excel formatting
  • Emails composed with correct content
  • Emails send successfully
  • Attachments open correctly
  • Summary report accurate
  • Errors handled gracefully
  • Credentials stored securely (not in code)
  • Script is idempotent (safe to rerun)
  • Performance acceptable (< 5 min for 250 customers)
  • Logging provides audit trail

Resources

Topic Resource
Excel automation with openpyxl โ€œAutomate the Boring Stuff with Pythonโ€ by Al Sweigart - Ch. 13
Email automation โ€œAutomate the Boring Stuff with Pythonโ€ by Al Sweigart - Ch. 18
PDF generation โ€œAutomate the Boring Stuff with Pythonโ€ by Al Sweigart - Ch. 15
Template pattern โ€œDesign Patternsโ€ by Gang of Four
Business logic design โ€œClean Codeโ€ by Robert C. Martin - Ch. 6
Error handling and logging โ€œFluent Pythonโ€ by Luciano Ramalho - Ch. 7