Skip to main content

Customer Invoices

Transactions are grouped together to form an invoice, which is sent to the customer for payment.

Invoices have a start and end date, which is the period the invoice covers, and a due date, which is the date the invoice is due for payment.

Generate a Proforma Invoice

Invoices can be automatically generated by the system, for example, when a service is billed, an invoice is created for the retail cost, or they can be manually created, for example, if a customer requests a copy of an invoice, or if a customer is billed for a one-time charge.

Customer invoices are fully templated with Mailjet and can be customized to include the company logo, address, and payment details, and can be sent to the customer via email, or downloaded as a PDF.

Activity Log

Customizing Invoice Templates

OmniCRM uses HTML templates with Jinja2 templating to generate invoices. You can fully customize the invoice design, branding, colors, and layout.

Invoice Template Location

Invoice templates are stored in OmniCRM-API/invoice_templates/

Default Templates:

  • norfone_invoice_template.html - Sample invoice template
  • cifi_invoice_template.html - Alternative template example

Configuration:

The active invoice template is specified in OmniCRM-API/crm_config.yaml:

invoice:
template_filename: 'norfone_invoice_template.html'

Available Template Variables

Invoice templates have access to the following Jinja2 variables:

Invoice Information:

  • {{ invoice_number }} - Unique invoice ID (e.g., INV-2025-001234)
  • {{ date }} - Invoice issue date (ISO format: 2025-01-10T12:00:00)
  • {{ due_date }} - Payment due date (e.g., 2025-02-10)
  • {{ start_date }} - Billing period start date
  • {{ end_date }} - Billing period end date
  • {{ total_amount }} - Total invoice amount before tax (numeric)
  • {{ total_tax }} - Total tax amount calculated from all transactions (numeric)

Customer Information:

  • {{ client.name }} - Customer's full name or company name
  • {{ client.address.address_line_1 }} - Address line 1
  • {{ client.address.address_line_2 }} - Address line 2
  • {{ client.address.city }} - City
  • {{ client.address.state }} - State/province
  • {{ client.address.zip_code }} - Postal/ZIP code
  • {{ client.address.country }} - Country

Transaction Line Items:

Loop through transactions using:

{% for sub_transaction in transactions %}
<tr>
<td>{{ sub_transaction.transaction_id }}</td>
<td>{{ sub_transaction.created.split("T")[0] }}</td>
<td>{{ sub_transaction.title }}</td>
<td>{{ sub_transaction.description }}</td>
<td>${{ "%.2f"|format(sub_transaction.retail_cost) }}</td>
</tr>
{% endfor %}

Transaction Fields:

  • sub_transaction.transaction_id - Transaction ID
  • sub_transaction.created - Transaction date/time
  • sub_transaction.title - Transaction title
  • sub_transaction.description - Detailed description
  • sub_transaction.retail_cost - Line item amount
  • sub_transaction.tax_percentage - Tax percentage applied (e.g., 10 for 10%)
  • sub_transaction.tax_amount - Calculated tax amount in dollars

Displaying Tax in Templates:

<td>
{% if sub_transaction.tax_amount and sub_transaction.tax_amount > 0 %}
${{ "%.2f"|format(sub_transaction.tax_amount) }} ({{ sub_transaction.tax_percentage }}%)
{% else %}
-
{% endif %}
</td>

Creating a Custom Invoice Template

Step 1: Copy Existing Template

cd OmniCRM-API/invoice_templates/
cp norfone_invoice_template.html your_company_invoice_template.html

Step 2: Customize HTML/CSS

Edit your_company_invoice_template.html to match your branding:

Key Customization Areas:

  1. Company Logo and Branding

    <!-- Replace with your logo URL -->
    <img src="https://yourcompany.com/logo.png" alt="Your Company" width="200">

    <!-- Update company name -->
    <h1>Your Company Name</h1>
  2. Color Scheme

    <style>
    /* Primary brand color */
    .navbar {
    background: linear-gradient(to bottom right, #your-color-1, #your-color-2);
    }

    /* Table headers */
    .table thead th {
    background-color: #your-brand-color !important;
    color: white !important;
    }

    /* Buttons and links */
    .btn-primary {
    background-color: #your-brand-color;
    }
    </style>
  3. Company Information Footer

    <footer>
    <p>Your Company Name</p>
    <p>123 Business Street, City, Country</p>
    <p>Phone: +1-555-123-4567 | Email: billing@yourcompany.com</p>
    <p>ABN/Tax ID: 12345678900</p>
    </footer>
  4. Payment Instructions

    <div class="payment-info">
    <h3>Payment Methods</h3>
    <p><strong>Online:</strong> Pay at https://yourcompany.com/pay</p>
    <p><strong>Bank Transfer:</strong></p>
    <ul>
    <li>Account Name: Your Company Ltd</li>
    <li>BSB: 123-456</li>
    <li>Account Number: 987654321</li>
    <li>Reference: {{ invoice_number }}</li>
    </ul>
    </div>
  5. Terms and Conditions

    <div class="terms">
    <h4>Payment Terms</h4>
    <p>Payment due within 30 days of invoice date.</p>
    <p>Late payment fees: 2% per month on overdue balances.</p>
    <p>For billing inquiries: billing@yourcompany.com</p>
    </div>

Step 3: Update Configuration

Edit OmniCRM-API/crm_config.yaml:

invoice:
template_filename: 'your_company_invoice_template.html'

Step 4: Restart API

cd OmniCRM-API
sudo systemctl restart omnicrm-api

Step 5: Test Invoice Generation

  1. Navigate to a customer with transactions
  2. Generate a test invoice
  3. Download PDF to verify formatting
  4. Email invoice to yourself to test email delivery

Advanced Customization

Conditional Content:

Use Jinja2 conditionals to show/hide content:

{% if total_amount > 1000 %}
<div class="high-value-notice">
<p><strong>Note:</strong> Large balance - Payment plan available upon request.</p>
</div>
{% endif %}

{% if client.address.country == "Australia" %}
<p>GST Included: ${{ "%.2f"|format(total_amount * 0.10) }}</p>
{% endif %}

Multi-Language Support:

Create language-specific templates:

invoice_template_en.html
invoice_template_es.html
invoice_template_fr.html

Configure based on customer's language preference.

Custom Calculations:

<!-- Display subtotal and tax breakdown -->
<tr>
<td colspan="4" class="text-right"><strong>Subtotal:</strong></td>
<td>${{ "%.2f"|format(total_amount) }}</td>
</tr>
<tr>
<td colspan="4" class="text-right"><strong>Tax:</strong></td>
<td>${{ "%.2f"|format(total_tax) }}</td>
</tr>
<tr>
<td colspan="4" class="text-right"><strong>Total:</strong></td>
<td>${{ "%.2f"|format(total_amount + total_tax) }}</td>
</tr>

Note: The total_tax variable is automatically calculated by summing the tax_amount from all transactions in the invoice. Each transaction's tax is calculated based on its tax_percentage field, which defaults to the product's tax_percentage or 0% if not specified.

QR Code for Payment:

Generate QR code for mobile payment:

<div class="qr-payment">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data={{ payment_url }}"
alt="Scan to Pay">
<p>Scan with your phone to pay instantly</p>
</div>

PDF Styling Best Practices

OmniCRM uses WeasyPrint to convert HTML to PDF. Follow these guidelines:

Supported CSS:

  • Most CSS 2.1 properties
  • Limited CSS3 (flexbox, some transforms)
  • Web fonts via @font-face

Not Supported:

  • JavaScript
  • CSS Grid (use tables instead)
  • Complex animations
  • Some modern CSS properties

Page Size and Margins:

@page {
size: A4;
margin: 1cm;
}

body {
font-family: Arial, sans-serif;
font-size: 10pt;
}

Print-Specific Styling:

@media print {
.no-print {
display: none;
}

.page-break {
page-break-after: always;
}
}

Table Layout:

.table {
table-layout: fixed;
width: 100%;
}

.table th, .table td {
word-wrap: break-word;
padding: 4px;
}

Font Embedding:

For custom fonts, use web-safe fonts or embed:

@font-face {
font-family: 'YourFont';
src: url('https://yourcompany.com/fonts/yourfont.woff2') format('woff2');
}

body {
font-family: 'YourFont', Arial, sans-serif;
}

Testing Invoice Templates

Test Checklist:

  1. Visual Inspection:
    • Logo displays correctly
    • Colors match brand guidelines
    • Text is readable (not too small)
    • Tables align properly
    • All sections present
  2. Data Accuracy:
    • Customer details correct
    • Transaction amounts sum correctly
    • Dates formatted properly
    • All variables substituting correctly
  3. PDF Quality:
    • File size reasonable (&lt;5MB)
    • Images sharp and clear
    • No text cutoff or overflow
    • Page breaks in appropriate places
  4. Multi-Page Invoices:
    • Headers repeat on each page
    • Page numbers display
    • Long transaction lists paginate correctly
  5. Email Delivery:
    • PDF attaches to email
    • File size under Mailjet limit (15MB)
    • Renders in Gmail, Outlook, Apple Mail

Test Command (Manual Generation):

You can test invoice generation via API:

curl -X GET "http://localhost:5000/crm/invoice/{invoice_id}/pdf" \
-H "Authorization: Bearer YOUR_TOKEN" \
--output test_invoice.pdf

Common Template Issues

Variables not substituting:

  • Cause: Typo in variable name or missing data
  • Fix: Check spelling exactly (case-sensitive), verify data exists in database

PDF styling broken:

  • Cause: Unsupported CSS property
  • Fix: Use CSS 2.1 properties, test with WeasyPrint-compatible CSS

Images not showing:

  • Cause: Relative URLs or blocked external resources
  • Fix: Use absolute HTTPS URLs, ensure images publicly accessible

Tables overflowing page:

  • Cause: Fixed column widths too wide
  • Fix: Use percentage widths, table-layout: fixed

Fonts not rendering:

  • Cause: Font not embedded or unavailable
  • Fix: Use web-safe fonts (Arial, Times New Roman, etc.) or properly embed custom fonts

PDF generation fails:

  • Cause: HTML syntax errors or WeasyPrint crash
  • Fix: Validate HTML, check WeasyPrint logs, simplify complex layouts

Invoice PDF Caching

To improve performance and reduce redundant PDF generation, OmniCRM includes an Invoice PDF caching system. When an invoice PDF is first generated, it is cached in the database for subsequent requests.

How PDF Caching Works:

  1. First Request - When an invoice PDF is requested (download or email), the system:
    • Generates the PDF from the invoice template
    • Encodes the PDF as Base64
    • Calculates a SHA256 hash of the PDF content
    • Stores in Invoice_PDF_Cache table with:
      • Invoice ID reference
      • PDF data (Base64-encoded)
      • Filename
      • Content hash (for integrity verification)
      • Creation timestamp
  2. Subsequent Requests - When the same invoice is requested again:
    • System checks for cached PDF by invoice_id
    • If cache exists and is valid, returns cached PDF immediately
    • Updates last_accessed timestamp to track cache usage
  3. Cache Invalidation - Cached PDFs are invalidated when:
    • Invoice is modified (transactions added/removed, details changed)
    • Invoice template is updated
    • Manual cache clearing is triggered

Benefits:

  • Performance - Instant PDF delivery for repeat requests (no regeneration delay)
  • Consistency - Same PDF for all downloads of an invoice (unless invoice is modified)
  • Server Load - Reduces CPU usage from PDF generation
  • User Experience - Loading indicator appears during initial generation, subsequent requests are instant

Cache Management:

The Invoice PDF Cache is automatically managed by the system. Old or unused cache entries can be purged periodically based on:

  • Age (e.g., remove cache entries older than 90 days)
  • Access patterns (remove entries not accessed in 30 days)
  • Storage limits (implement cache size limits if needed)

API Behavior:

When downloading an invoice via API or UI:

  • First request: Shows loading indicator while PDF generates, then caches
  • Subsequent requests: Immediate download from cache
  • Cache hit/miss is transparent to the user

Important: When you update your invoice template, clear the cache to ensure new invoices use the updated design:

-- Clear all cached invoice PDFs (run in MySQL)
DELETE FROM Invoice_PDF_Cache;

Or update crm_config.yaml to automatically invalidate cache on template change.

Accessing Invoices

Invoices can be viewed at the system level or per-customer:

Per-Customer View:

  1. Navigate to Customers → [Select Customer]
  2. Click Billing tab
  3. View invoices list in the third card

System-Wide View:

  1. Navigate to Billing → Invoices (from main menu)
  2. View all invoices across all customers

Invoice Statistics Widgets

At the top of the invoices page, four statistics cards display financial summaries.

Invoice Statistics and List{.align-center width="800px"}

Widget Descriptions:

  • Total Invoices - Sum of all invoice retail costs (all time) and count of invoices sent
  • Unpaid Invoices - Sum of invoices not yet paid and count of unpaid invoices
  • Invoices This Month - Sum of invoices created this calendar month with count
  • Invoices Last Month - Sum of invoices created last calendar month with count

Value Formatting:

  • Values over 1,000: Display as "k" suffix (e.g., $1.5k)
  • Values over 1,000,000: Display as "M" suffix (e.g., $2.3M)
  • Values over 1,000,000,000: Display as "B" suffix (e.g., $1.1B)

Trend Indicators:

  • Widgets for "This Month" and "Last Month" show percentage change
  • Green arrow up: Increase from previous period
  • Red arrow down: Decrease from previous period
  • Gray arrow right: No change

Invoices List

The invoices table displays all invoices with the following columns:

Global Invoices List

Column Descriptions:

  • ID - Unique invoice ID
  • Title - Invoice title/description
  • Period - Billing period (start date - end date) or "N/A" for one-time invoices
  • Due Date - Payment due date
  • Created - Invoice creation date
  • Amount - Total invoice amount (retail cost)
  • Status - Paid, Unpaid, or Refunded
  • Actions - Available actions (varies by status)

Action Icons:

  • ⬇ (Download) - Download invoice PDF
  • 🗑️ (Delete) - Void invoice (only if not paid)
  • 💰 (Pay) - Pay invoice online (only if unpaid)
  • ✉️ (Email) - Send invoice email to customer
  • 💸 (Refund) - Refund Stripe payment (only for paid Stripe invoices)

Generating an Invoice

Click "+ Generate Proforma Invoice" to create a new invoice.

Generate Invoice Modal with Transaction Preview{.align-center width="800px"}

Field Descriptions:

  • Search Customers - Select customer (only shown in system-wide view, pre-filled in customer view)
  • Title - Invoice title/name (optional, defaults to "Invoice for [Period]")
  • Start Date - Beginning of billing period (defaults to 14 days ago)
  • End Date - End of billing period (defaults to today)
  • Due Date - Payment deadline (defaults to today)
  • Transaction Preview - Shows all uninvoiced transactions in date range with ability to include/exclude specific transactions

Transaction Selection:

  • ✓ (Green Plus) - Click to exclude a transaction from the invoice
  • × (Red X) - Click to include a previously excluded transaction
  • Select All - Include all displayed transactions
  • Clear All - Exclude all transactions
  • Excluded transactions appear grayed out with strikethrough text
  • Real-time totals update as you select/deselect transactions

What Happens:

  1. System finds all uninvoiced transactions for customer within date range
  2. Displays transaction preview with ability to include/exclude individual transactions
  3. Shows real-time calculation of subtotal, tax, and total based on selected transactions
  4. Only selected (included) transactions are added to the invoice
  5. Generates invoice PDF and caches it
  6. Marks selected transactions as invoiced (invoice_id field populated)
  7. Excluded transactions remain uninvoiced and available for future invoices
  8. Invoice appears in list with "Unpaid" status

Example Use Cases:

Monthly Billing: Set start date to first of month, end date to last day of month, preview shows all uninvoiced transactions from that period. Select all or manually exclude specific ones.

Service-Specific Invoice: Use same date range, then manually exclude unwanted transactions (e.g., exclude non-mobile transactions to create mobile-only invoice).

One-Time Invoice: Set both start and end date to the same day, preview shows only transactions from that date. Exclude any charges not relevant to this specific invoice.

Viewing Invoice Details

Click on any invoice row in the table to view full invoice details including all transactions, totals, and available actions.

Invoice Details View{.align-center width="800px"}

Invoice Details Modal:

  • Invoice Information - Shows invoice ID, title, dates, payment status, and void status
  • Transactions List - Displays all transactions included in the invoice with:
    • Transaction date
    • Title and description
    • Retail cost
    • Tax amount and percentage (formatted as $10.00 (10%))
    • Tax-exempt transactions show "-" in Tax column
  • Totals Summary - Real-time calculation showing:
    • Transaction count
    • Subtotal (sum of all retail costs)
    • Tax (sum of all tax amounts)
    • Invoice Total (subtotal + tax)
  • Action Buttons - Same actions available as in the table:
    • Download PDF - Download invoice PDF (always available)
    • Send Email - Email invoice to customer (non-voided invoices)
    • Pay Invoice - Process payment (unpaid, non-voided invoices only)
    • Refund - Refund Stripe payment (paid Stripe invoices only)
    • Delete - Void invoice (unpaid, non-voided invoices only)

Downloading Invoice PDFs

Click the download icon (⬇) in the table or "Download PDF" button in the invoice details modal to download an invoice as PDF.

Download Process:

  1. Click download icon next to invoice
  2. Loading spinner appears during generation (first time only)
  3. Browser prompts to save file: Invoice_01234.pdf
  4. PDF opens or saves to Downloads folder

PDF Caching Behavior:

  • First Download - PDF generated from template, cached in database (may take 2-3 seconds)
  • Subsequent Downloads - Instant download from cache
  • Cache Invalidation - Cache cleared if invoice modified or template updated

Troubleshooting Download Issues:

  • Spinner never stops - Check browser console, API may be down
  • PDF blank or corrupted - Check invoice template for syntax errors
  • Download fails - Check popup blocker settings, try different browser

Paying Invoices

Click the pay icon (💰) to pay an invoice online.

Pay Invoice Modal{.align-center width="800px"}

Payment Process:

  1. Click pay icon on unpaid invoice
  2. Payment modal opens showing invoice details
  3. Select payment method:
    • Stripe Transaction - Charge saved credit card (available to all users)
    • Cash - Manual cash payment (staff only)
    • Refund - Apply refund as payment (staff only)
    • POS Transaction - Point-of-sale terminal (staff only)
    • Bank Transfer - Manual bank transfer (staff only)
  4. If Stripe selected:
    • Select card from saved payment methods
    • Default card pre-selected
    • Click to select different card
  5. If other method selected:
    • Enter reference number (optional)
  6. Click "Pay Invoice" to process
  7. System processes payment:
    • Stripe - Charges card via Stripe API
    • Other methods - Creates negative transaction for payment amount
  8. Invoice status changes to "Paid"
  9. Success notification displayed

Self-Care vs Staff Payment:

:doc:`Self-Care Portal <self_care_portal>` (Customers):

  • Only Stripe payment available
  • Must have saved payment method
  • Warning shown if no payment methods exist
  • Link to add payment method provided

Staff Portal (Admins):

  • All payment methods available
  • Can mark invoice paid manually (cash, POS, bank transfer)
  • Can enter reference numbers for tracking

Payment Method Warning:

If customer has no saved payment methods, a warning is displayed prompting them to add a payment method before they can pay invoices.

Missing Payment Method Warning{.align-center width="800px"}

Emailing Invoices

Click the email icon (✉️) to send invoice to customer.

What Happens:

  1. Click email icon next to invoice
  2. System retrieves invoice PDF from cache (or generates if not cached)
  3. Sends email via Mailjet using api_crmCommunicationCustomerInvoice template
  4. Email includes:
    • Invoice PDF as attachment
    • Customer name
    • Invoice number and due date
    • Total amount due
    • Link to pay invoice online
    • Link to view/download invoice
  5. Success notification: "Invoice email successfully sent"

Email Recipients:

Email sent to all customer contacts with type "billing" or primary contact if no billing contact exists.

Email Template Variables:

  • {{ var:customer_name }} - Customer's full name
  • {{ var:invoice_number }} - Invoice ID
  • {{ var:invoice_date }} - Invoice issue date
  • {{ var:due_date }} - Payment due date
  • {{ var:total_amount }} - Total amount due
  • {{ var:invoice_url }} - Link to view/download PDF
  • {{ var:pay_url }} - Link to pay invoice online

Troubleshooting Email Issues:

  • Email not sent - Check Mailjet API credentials in crm_config.yaml
  • Customer not receiving - Verify customer contact email addresses
  • PDF not attaching - Check PDF generation succeeded (try downloading first)

Voiding Invoices

Click the delete icon (🗑️) to void an invoice.

Requirements:

  • Invoice must be Unpaid
  • Paid invoices cannot be voided (must be refunded instead)

How to Void:

  1. Locate unpaid invoice in list
  2. Click delete icon (🗑️)
  3. Confirm in modal:

Void Invoice Confirmation Modal{.align-center width="600px"}

What Happens:

  • Invoice marked as void = true
  • All transactions unlinked from invoice (invoice_id set to null)
  • Transactions become "uninvoiced" again
  • Transactions can be included in new invoice
  • Invoice appears in list with "Void:" prefix in title
  • Invoice actions disabled (no download, pay, or email)
  • Can be viewed by filtering for "Void" invoices

Important Notes:

  • Voiding is NOT the same as refunding
  • Void = "This invoice should never have existed" (billing error, duplicate)
  • Refund = "Reverse a valid paid invoice" (return money to customer)

Refunding Invoices

Click the refund icon (💸) to refund a paid invoice.

Requirements:

  • Invoice must be Paid
  • Invoice must be paid via Stripe
  • Invoice must have a valid payment_reference (Stripe payment intent ID)
  • Only available to staff users (not Self-Care)

How to Refund:

  1. Locate paid Stripe invoice
  2. Click refund icon (💸)
  3. Refund confirmation modal opens:

Refund Invoice Confirmation Modal{.align-center width="800px"}

  1. Click "Confirm Refund"
  2. System processes Stripe refund:
    • Calls Stripe API to refund payment
    • Creates refund transaction in Stripe
    • Updates invoice with refund_reference
  3. Invoice status changes to "Refunded"
  4. Success notification displayed

What Happens After Refund:

  • Invoice remains in system (not voided)
  • Status shows "Refunded"
  • Transactions remain linked to invoice
  • Customer receives refund to original payment method (3-7 business days)
  • Stripe dashboard shows refund transaction

Refund Restrictions:

  • Cannot refund invoices paid via cash, POS, or bank transfer (manual reversal required)
  • Cannot partial refund (full invoice amount only)
  • Cannot refund twice

Searching and Filtering Invoices

Use the search bar to find invoices. Searches across:

  • Invoice ID
  • Invoice title
  • Customer name (system-wide view only)

Filters

Apply filters to narrow invoice list:

Available Filters:

  • Void Status - All, Void, Not Void
  • Paid Status - All, Paid, Not yet Paid

Filter Actions:

  • Apply Filters - Apply selected filters to list
  • Reset Filters - Clear all filters and show all invoices

Sorting

Click any column header to sort:

  • ID - Sort by invoice ID (newest/oldest)
  • Title - Sort alphabetically
  • Due Date - Sort by due date
  • Created - Sort by creation date
  • Amount - Sort by retail cost (highest/lowest)
  • Status - Sort by paid status (paid first or unpaid first)

Click again to reverse sort direction (ascending ↔ descending).

Pagination

Navigate through large invoice lists with page controls showing current page, total pages, and items per page selector (10, 25, 50, or 100 items).

Common Invoice Workflows

Workflow 1: Monthly Billing with Transaction Preview

  1. End of month arrives (e.g., January 31)
  2. Navigate to Billing → Invoices
  3. Click "+ Generate Proforma Invoice"
  4. Select customer (or do per-customer if billing many customers)
  5. Set dates:
    • Start Date: 2025-01-01
    • End Date: 2025-01-31
    • Due Date: 2025-02-15 (15 days from now)
    • Title: "January 2025 Services" (optional)
  6. Transaction Preview section appears showing all uninvoiced transactions from January
  7. Review the preview:
    • All transactions are included by default
    • Check totals: Subtotal, Tax, and Invoice Total
    • Verify all charges are correct
  8. Click "Generate Invoice" (button shows transaction count, e.g., "Generate Invoice (15)")
  9. Invoice created with all selected transactions
  10. Click invoice row to view details and verify
  11. Click "Send Email" button in details modal or email icon in table
  12. Customer receives invoice email with PDF and pay link

Workflow 2: Selective Transaction Invoicing

  1. Customer has multiple services (Mobile + Internet) and misc charges
  2. Wants separate invoices for each service
  3. Generate first invoice (Mobile Services):
    • Click "+ Generate Proforma Invoice"
    • Title: "Mobile Services - January 2025"
    • Start/End: Jan 1-31
    • Due Date: Feb 15
    • In transaction preview, exclude all non-mobile transactions:
      • Click X button next to Internet transactions
      • Click X button next to miscellaneous charges
      • Only Mobile service transactions remain selected
    • Verify totals reflect only mobile services
    • Click "Generate Invoice" (shows count of mobile transactions)
  4. Generate second invoice (Internet Services):
    • Click "+ Generate Proforma Invoice" again
    • Title: "Internet Services - January 2025"
    • Start/End: Jan 1-31 (same period)
    • In transaction preview:
      • Mobile transactions already invoiced (don't appear)
      • Exclude miscellaneous charges using X button
      • Only Internet service transactions remain
    • Click "Generate Invoice"
  5. Generate third invoice (Additional Charges):
    • Click "+ Generate Proforma Invoice" again
    • Title: "Additional Charges - January 2025"
    • Only uninvoiced misc charges appear in preview
    • Click "Select All" to include all
    • Click "Generate Invoice"
  6. Email all three invoices to customer

Workflow 3: Excluding Disputed or Pending Transactions

  1. End of billing period arrives
  2. Navigate to customer Billing tab
  3. Click "+ Generate Proforma Invoice"
  4. Set billing period dates
  5. Transaction preview shows 20 transactions
  6. Customer has disputed one charge and another is pending investigation
  7. In transaction preview:
    • Locate disputed transaction (e.g., "Data overage charge")
    • Click X button to exclude it
    • Locate pending transaction (e.g., "Installation fee")
    • Click X button to exclude it
    • Transaction count updates: "18 Transactions selected"
    • Totals recalculate automatically
  8. Review updated totals (excludes disputed amounts)
  9. Click "Generate Invoice (18)"
  10. Invoice generated with only approved transactions
  11. Disputed/pending transactions remain uninvoiced for next billing cycle

Workflow 4: Quick Invoice Review and Adjustment

  1. Staff generates monthly invoice
  2. Transaction preview shows unexpected high total
  3. Review each transaction in the preview:
    • Notice duplicate charge for same service
    • Click X to exclude the duplicate
    • Notice test transaction that shouldn't be billed
    • Click X to exclude test transaction
  4. Totals update in real-time
  5. Verify new total matches expected amount
  6. Click "Generate Invoice" with corrected transactions
  7. Go back and void/delete the excluded transactions if needed
  8. Email invoice to customer with confidence

Workflow 5: One-Time Installation Invoice

  1. Field tech completes installation
  2. Staff adds installation transaction manually
  3. Navigate to customer Billing tab
  4. Click "+ Generate Proforma Invoice"
  5. Set dates:
    • Start Date: today
    • End Date: today
    • Due Date: today + 7 days
    • Title: "Installation Services"
  6. Transaction preview shows only today's transactions
  7. Verify installation charge appears
  8. Exclude any recurring charges using X button (if present)
  9. Click "Generate Invoice"
  10. Email to customer immediately
  11. Customer pays online via Stripe

Workflow 6: Reviewing Invoice Before Customer Contact

  1. Customer calls with billing question
  2. Staff navigates to customer's invoice list
  3. Click on invoice row to open Invoice Details modal
  4. Review invoice information:
    • Invoice ID, dates, status
    • All transactions included with descriptions
    • Tax breakdown per transaction
    • Subtotal, Tax, and Total amounts
  5. Answer customer's questions with exact details
  6. If customer requests PDF, click "Download PDF" button in modal
  7. If customer requests email resend, click "Send Email" button
  8. Close modal when done

Workflow 7: Correcting Billing Error

  1. Customer reports incorrect charge
  2. Staff clicks on invoice row to view details
  3. Reviews transaction list in Invoice Details modal
  4. Identifies incorrect transaction
  5. Invoice is unpaid, so can be voided
  6. Click "Delete" button in modal footer
  7. Confirm void
  8. Transactions become uninvoiced again
  9. Staff modifies or removes incorrect transaction from transaction list
  10. Generate new invoice with corrected transactions:
    • Use transaction preview to exclude corrected transaction if needed
    • Include only valid charges
  11. Email corrected invoice to customer

Workflow 8: Processing Multiple Payments

  1. Customer brings cash to pay multiple invoices
  2. Navigate to customer Billing tab
  3. View unpaid invoices
  4. Click on first invoice row to view details
  5. Verify amount and transactions
  6. Click "Pay Invoice" button in modal footer
  7. Select "Cash" payment method
  8. Enter reference: "Cash paid 2025-01-15"
  9. Click "Pay Invoice"
  10. Modal closes, invoice marked as "Paid"
  11. Repeat for remaining invoices
  12. All invoices now marked as "Paid"

Workflow 9: Handling Refund Request

  1. Customer requests refund for overpayment
  2. Staff verifies invoice was paid via Stripe
  3. Navigate to invoice in list
  4. Click on invoice row to view details
  5. Verify payment information and amount
  6. Click "Refund" button in modal footer (only appears for Stripe invoices)
  7. Confirm refund
  8. System processes Stripe refund
  9. Invoice status changes to "Refunded"
  10. Customer receives refund in 3-7 business days
  11. Staff follows up with customer to confirm receipt

Troubleshooting

Cannot generate invoice - No transactions found

  • Cause: No uninvoiced transactions in specified date range
  • Fix: Check transaction list, verify transactions exist and are not already invoiced. Adjust date range or remove filter.

Invoice PDF generation fails

  • Cause: Template syntax error, WeasyPrint crash, or missing customer data
  • Fix: Check invoice template HTML for errors, verify customer address fields populated, review API logs.

Payment fails with Stripe error

  • Cause: Card declined, insufficient funds, expired card, or Stripe API issue
  • Fix: Try different payment method, verify card valid, check Stripe dashboard for decline reason.

Cannot void invoice

  • Cause: Invoice already paid
  • Fix: Paid invoices cannot be voided. If refund needed, use refund function for Stripe invoices or create credit transaction manually.

Invoice email not sending

  • Cause: Mailjet API credentials invalid, customer has no billing contact, or email template missing
  • Fix: Verify Mailjet configuration in crm_config.yaml, check customer contacts, verify invoice email template exists.

Refund button not appearing

  • Cause: Invoice paid via cash/POS/bank transfer (not Stripe), or invoice not paid
  • Fix: Refund button only appears for Stripe payments. For other payment methods, create manual credit transaction.

Download PDF shows old template design

  • Cause: PDF cached before template update
  • Fix: Clear invoice PDF cache: DELETE FROM Invoice_PDF_Cache WHERE invoice_id = X;

Customer cannot pay invoice (no payment methods)

  • Cause: No saved payment methods in Self-Care portal
  • Fix: Customer must add credit card at Payment Methods page before paying invoices.

Multiple invoices generated for same period

  • Cause: Staff generated invoice twice, or date ranges overlap
  • Fix: Void duplicate invoice. Adjust date ranges to prevent overlap. Use transaction preview to ensure unique transaction sets.

Transaction preview shows no transactions

  • Cause: All transactions in date range are already invoiced or no transactions exist
  • Fix: Verify date range is correct. Check transaction list to confirm transactions exist. Filter invoices to see which invoice contains the transactions.

Cannot exclude transaction from invoice generation

  • Cause: Transaction already invoiced or browser issue
  • Fix: Verify transaction shows in preview with checkmark. Refresh page and try again. Clear browser cache if issue persists.

Invoice total doesn't match expected amount

  • Cause: Unexpected transactions included, tax not calculated, or excluded transactions still counted
  • Fix: Review transaction preview carefully. Check each transaction's retail cost and tax. Verify excluded transactions are grayed out. Check transaction count badge on Generate Invoice button.

Generate Invoice button is disabled

  • Cause: No transactions selected or invalid date range
  • Fix: Ensure at least one transaction is included (not excluded). Verify Start Date is before End Date. Check that Due Date is set.

Invoice Details modal not opening

  • Cause: JavaScript error or page not fully loaded
  • Fix: Refresh page. Check browser console for errors. Try different browser. Verify internet connection.

Transaction tax not displaying in Invoice Details

  • Cause: Transaction has 0% tax or tax_amount is null
  • Fix: Verify transaction has tax_percentage set. Check that tax_amount was calculated when transaction was created. Update transaction if needed.

Action buttons missing in Invoice Details modal

  • Cause: Invoice is voided or user lacks permissions
  • Fix: Voided invoices only show Download PDF button. Verify invoice status. Check user role and permissions.
  • integrations_mailjet - Email invoice delivery and templates
  • administration_configuration - Invoice template configuration
  • payments_transaction - Creating transactions that appear on invoices
  • payments_process - Processing invoice payments
  • basics_payment - Payment methods and Stripe integration