Skip to content

BaseCloud Accounting

Overview

The BaseCloud Accounting task provides integrated accounting functionality within your BaseCloud CRM system. It handles quotes, invoices, PDF generation, payment links, and automated payment tracking—all without requiring external accounting software.

Key Features:

  • 4 Actions: Create quotes/invoices, fetch documents, mark as paid
  • Invoice Layout System: Customizable HTML templates with placeholder support
  • PDF Generation: Automatic document generation with S3 storage
  • Payment Links: Integrated payment portal at pay.basecloudglobal.com
  • Global Triggers: Fire CRM automations on invoice events
  • Tracking Categories: Two-level project/department tracking
  • Multi-Currency: Support for multiple currency symbols and formats

Use Cases:

  • Automated invoicing workflows triggered by CRM events
  • Quote-to-invoice conversion on client approval
  • Subscription billing with recurring invoice generation
  • Project-based invoicing with tracking categories
  • Payment link distribution via email

Prerequisites

1. Invoice Layout Configuration

Before creating invoices, configure an invoice layout:

  1. Navigate to Settings → Invoice Layouts in BaseCloud CRM
  2. Create or edit a layout with HTML template
  3. Use placeholders like {{invoice_number}}, {{client_name}}, {{total_incl}}, etc.
  4. Note the Layout ID (invoice_var_id) for task configuration

2. Client Records

  • Clients must exist in your CRM with valid client_id
  • Client details (name, email, address) populate invoice placeholders

3. Tracking Categories (Optional)

  • Configure tracking categories for project/department tracking
  • Navigate to Settings → Tracking Categories
  • Create category values (e.g., Department: Sales, Marketing, Support)

Configuration

Action 1: fetch_quote_invoice

Retrieve an existing quote or invoice with all details, generate PDF if needed, and create payment link.

Field Required Description Example
accounting_action Yes Must be "fetch_quote_invoice" fetch_quote_invoice
Quote / Invoice ID Yes Document ID (formats: "INV123", "QU456", or just "123") INV-{{client_invoice_number}}

Output Variables:

task_22001_client_id          // Client ID associated with invoice
task_22001_id                 // Internal invoice database ID
task_22001_invoice_number     // Display number (e.g., 123)
task_22001_o_inv_id           // Full formatted ID ("INV123" or "QU456")
task_22001_type               // "Quote" or "Invoice"
task_22001_status             // "Unpaid", "Void", or "Paid"
task_22001_date_paid          // Date paid (if status=paid)
task_22001_date_created       // Creation date (DD/MM/YYYY HH:mm)
task_22001_date_expiry        // Expiry/due date (DD/MM/YYYY HH:mm)
task_22001_subtotal           // Subtotal before tax
task_22001_total              // Total including tax
task_22001_item_description   // Pipe-delimited descriptions
task_22001_item_code          // Pipe-delimited item codes
task_22001_item_quantity      // Pipe-delimited quantities
task_22001_item_unit_price    // Pipe-delimited unit prices
task_22001_item_tax_rate      // Pipe-delimited tax rates (%)
task_22001_tracking_1_label   // Pipe-delimited TC1 labels
task_22001_tracking_1_value   // Pipe-delimited TC1 value IDs
task_22001_tracking_2_label   // Pipe-delimited TC2 labels
task_22001_tracking_2_value   // Pipe-delimited TC2 value IDs
task_22001_file_name          // Slugified filename for PDF
task_22001_document_url       // S3 URL to generated PDF
task_22001_payment_link       // Payment portal URL

How It Works:

  1. Extracts numeric ID from input (removes non-digits: "INV123" → 123)
  2. Retrieves invoice from invoices table with all line items
  3. Fetches tracking category labels for each line item
  4. Generates PDF if not already generated (via Puppeteer + S3 upload)
  5. Creates 36-character payment token for payment portal link
  6. Returns complete invoice data with pipe-delimited line items

Action 2: paid_quote_invoice

Mark an invoice as paid, optionally convert quote to invoice, and trigger global CRM automation.

Field Required Description Example
accounting_action Yes Must be "paid_quote_invoice" paid_quote_invoice
Quote / Invoice ID Yes Document ID to mark as paid {{automation_invoice_id}}
Date Paid No Payment date (defaults to today) {{payment_received_date}}

Output Variables:

Same as fetch_quote_invoice action (returns full invoice data after update).

How It Works:

  1. Validates invoice exists and is currently unpaid (status=0)
  2. If document is a quote (quote_invoice=0), converts to invoice (quote_invoice=1)
  3. Updates status to paid (status=1)
  4. Sets date_paid field (defaults to today if not provided)
  5. Nullifies file_url to force PDF regeneration with "PAID" stamp
  6. Triggers Global CRM Automation: Type 3 trigger with var_id='invoice_paid'
  7. Returns complete updated invoice data

Error Scenarios:

  • "No quote/invoice found": Invalid document ID provided
  • "Invoice already marked as paid": Status is not 0 (unpaid)
  • "Invalid Date Paid provided": Date string cannot be parsed

Global Trigger:

When an invoice is marked as paid, BaseCloud automatically runs all CRM automations configured with:

  • Trigger Type: Quote/Invoice Changes
  • Variable: invoice_paid

This enables automated workflows like:

  • Send payment confirmation emails
  • Update client status to "Active"
  • Trigger fulfillment/provisioning tasks
  • Create workflow notes for accounting team

Action 3: create_quote

Create a new quote (quote_invoice=0) with line items, tracking categories, and automatic PDF generation.

Field Required Description Example
accounting_action Yes Must be "create_quote" create_quote
Client ID Yes Valid client ID from CRM {{client_id}}
Invoice Layout ID Yes Template/layout ID from Settings 5
item_Description Yes Pipe-delimited descriptions Consulting Services\|Design Work\|Development
item_Code Yes Pipe-delimited item codes CONSULT\|DESIGN\|DEV
item_Quantity Yes Pipe-delimited quantities 10\|5\|20
item_Unit_Cost Yes Pipe-delimited unit costs 150.00\|200.00\|100.00
item_Tax_Rate Yes Pipe-delimited tax rates (%) 15\|15\|15
tracking_category_1 No Pipe-delimited TC1 value IDs 12\|12\|13
tracking_category_2 No Pipe-delimited TC2 value IDs 45\|45\|45

Output Variables:

Same as fetch_quote_invoice action (returns full quote data after creation).

How It Works:

  1. Validates client_id exists in CRM
  2. Validates invoice_var_id (layout) exists in invoice_vars table
  3. Splits pipe-delimited line item arrays (all must be same length)
  4. Generates next sequential o_inv_id (e.g., "QU001")
  5. Sets quote_invoice=0 (indicates quote, not invoice)
  6. Sets expiry_date to +7 days from today (hardcoded)
  7. Creates invoice record in invoices table
  8. Batch inserts line items in invoice_line_items table
  9. Triggers Global CRM Automation: Type 3 trigger with var_id='invoice_created'
  10. Generates PDF document via Puppeteer (HTML template → PDF → S3)
  11. Returns complete quote data with PDF URL and payment link

Line Item Calculation:

For each line item:

Subtotal = Quantity × Unit_Cost
Tax_Amount = Subtotal × (Tax_Rate / 100)
Line_Total = Subtotal + Tax_Amount

Invoice totals:

Total_Subtotal = SUM(all line subtotals)
Total_Tax = SUM(all line tax amounts)
Total_Including_Tax = Total_Subtotal + Total_Tax

Action 4: create_invoice

Create a new invoice (quote_invoice=1) with line items. Configuration and process identical to create_quote with one difference:

Field Value
accounting_action create_invoice
quote_invoice Set to 1 (indicates invoice)
o_inv_id Sequential ID with "INV" prefix (e.g., "INV001")

All other fields, validation, and output identical to create_quote action.


Special Features

Invoice Layout/Template System

BaseCloud uses HTML-based invoice templates with placeholder replacement:

Common Placeholders:

Placeholder Description Example Value
{{invoice_number}} Display invoice number 123
{{o_inv_id}} Full formatted ID INV123 or QU456
{{client_name}} Client name Acme Corporation
{{client_email}} Client email billing@acme.com
{{client_address}} Client address 123 Main St, City
{{date_created}} Creation date 15/01/2024 14:30
{{date_expiry}} Due/expiry date 22/01/2024 14:30
{{subtotal}} Subtotal before tax 1000.00
{{total_vat}} Total tax amount 150.00
{{total_incl}} Total including tax 1150.00
{{currency_symbol}} Currency symbol $, R, £
{{status}} Payment status Unpaid, Paid, Void
{{payment_link}} Payment portal URL Full URL with token

Line Items Loop:

Templates include special section for line item iteration:

<table>
  <tr>
    <th>Description</th>
    <th>Quantity</th>
    <th>Unit Price</th>
    <th>Tax Rate</th>
    <th>Total</th>
  </tr>
  {{#line_items}}
  <tr>
    <td>{{description}}</td>
    <td>{{quantity}}</td>
    <td>{{currency_symbol}}{{unit_price}}</td>
    <td>{{tax_rate}}%</td>
    <td>{{currency_symbol}}{{line_total}}</td>
  </tr>
  {{/line_items}}
</table>

PDF Generation Process

  1. Template Retrieval: Fetches HTML template from invoice_layouts table
  2. Placeholder Replacement: Substitutes all {{...}} placeholders with actual data
  3. Puppeteer Rendering:
  4. Launches headless Chrome
  5. Renders HTML to PDF
  6. Settings: A4 size, print background, margins
  7. S3 Upload: Uploads PDF to S3 bucket with slugified filename
  8. URL Storage: Saves S3 URL in file_url field
  9. Special Handling: Detects BaseCloud internal billing (owner_id 10/11) for custom formatting
  10. Grouped Line Items: Supports grouping by tracking categories (TC1=76, TC2=77)

PDF Filename Format:

quote-{owner_id}-{invoice_number}-{timestamp}.pdf
// Example: quote-25-123-1705321800000.pdf

Payment links enable clients to pay invoices directly via the BaseCloud payment portal:

Link Format:

https://pay.basecloudglobal.com/{token}

Token Generation:

  • 36-character alphanumeric token
  • Stored in invoices table in payment_token field
  • Unique per invoice, never reused

Payment Portal Features:

  • Client-facing payment page (BC_PAYMENT_FE)
  • Displays invoice details, line items, totals
  • Accepts credit card payments
  • Automatically marks invoice as paid on successful payment
  • Triggers invoice_paid global automation

Global Trigger System

BaseCloud fires CRM automations on invoice events:

Trigger Type: Quote/Invoice Changes

Events:

  1. invoice_created - Fired when quote or invoice created
  2. invoice_paid - Fired when invoice marked as paid
  3. invoice_edited - Fired when invoice updated
  4. invoice_deleted - Fired when invoice deleted

Usage Example:

Create automation with:

  • Trigger: Quote/Invoice Changes
  • Variable: invoice_paid
  • Tasks: Send receipt email → Update client status → Create workflow note

When any invoice is marked as paid (via task or payment portal), automation runs automatically.

Tracking Categories

Track invoices by project, department, cost center, or custom categories:

Configuration:

  1. Navigate to Settings → Tracking Categories
  2. Create categories (e.g., "Department", "Project")
  3. Add category values (e.g., Department: Sales, Marketing, Support)
  4. Note value IDs for use in line items

Two-Level Tracking:

  • Tracking Category 1: Primary classification (e.g., Department)
  • Tracking Category 2: Secondary classification (e.g., Project)

Line Item Assignment:

item_Description: "Consulting Services|Design Work"
tracking_category_1: "12|13"  // 12=Sales, 13=Marketing
tracking_category_2: "45|45"  // 45=Website Project

Reporting:

Query invoices by tracking categories for departmental/project revenue reports.

Number Management

Sequential Generation:

  • Quotes and invoices share same sequence per owner
  • Function: Get current max invoice_number + 1
  • Format: Numeric (e.g., 1, 2, 3, ..., 123)

Full ID Format:

  • Quotes: QU{invoice_number} (e.g., QU001)
  • Invoices: INV{invoice_number} (e.g., INV001)

Sequence Reset:

Contact BaseCloud support to reset invoice numbering sequence.


Real-World Examples

Example 1: Automated Service Invoicing

Scenario: Automatically create and send invoices when a service is marked complete in CRM.

Workflow:

  1. Trigger: CRM Trigger - Service Status Changed
  2. Condition: {{service_status}} equals "Complete"

  3. Task: BaseCloud Accounting - Create Invoice

    accounting_action: create_invoice
    Client ID: {{client_id}}
    Invoice Layout ID: 5
    item_Description: {{service_name}}
    item_Code: {{service_code}}
    item_Quantity: 1
    item_Unit_Cost: {{service_price}}
    item_Tax_Rate: 15
    tracking_category_1: {{department_id}}
    

  4. Task: Variable - Store Invoice Details

    invoice_pdf_url: {{task_22001_document_url}}
    invoice_payment_link: {{task_22001_payment_link}}
    invoice_number: {{task_22001_o_inv_id}}
    

  5. Task: Email - Send Invoice to Client

    To: {{client_email}}
    Subject: Invoice {{invoice_number}} - {{service_name}}
    Body: Thank you for your business. Please find your invoice attached.
          Pay online: {{invoice_payment_link}}
    Attachment: {{invoice_pdf_url}}
    

  6. Task: Workflow Note - Log Invoice Sent

    Note: Invoice {{invoice_number}} sent to {{client_name}} for service {{service_name}}
    Type: Finance
    

Result: Invoices automatically generated and emailed when services complete, with payment links for easy client payment.


Example 2: Quote-to-Invoice Conversion

Scenario: Create quote for prospect, convert to invoice on approval, trigger fulfillment.

Workflow Part 1: Create Quote

  1. Trigger: Manual Button - Generate Quote

  2. Task: BaseCloud Accounting - Create Quote

    accounting_action: create_quote
    Client ID: {{client_id}}
    Invoice Layout ID: 3
    item_Description: {{quote_item_description}}|{{quote_item_description_2}}
    item_Code: {{quote_item_code}}|{{quote_item_code_2}}
    item_Quantity: {{quote_quantity}}|{{quote_quantity_2}}
    item_Unit_Cost: {{quote_unit_price}}|{{quote_unit_price_2}}
    item_Tax_Rate: 15|15
    

  3. Task: Variable - Store Quote ID

    quote_id: {{task_22001_o_inv_id}}
    quote_pdf: {{task_22001_document_url}}
    

  4. Task: Email - Send Quote

    Subject: Quote {{quote_id}} - {{company_name}}
    Body: Thank you for your interest. Please review the attached quote.
          Valid until: {{task_22001_date_expiry}}
    Attachment: {{quote_pdf}}
    

Workflow Part 2: Quote Approval (Separate Automation)

  1. Trigger: Manual Button - Quote Approved

  2. Task: BaseCloud Accounting - Mark as Paid (converts to invoice)

    accounting_action: paid_quote_invoice
    Quote / Invoice ID: {{client_quote_id}}
    Date Paid: (leave empty for today)
    

  3. Global Trigger Fires: invoice_paid automation runs

  4. Task (in Global Automation): Edit Client

    Field: status
    Value: Active
    

  5. Task (in Global Automation): Webhook Out - Trigger Fulfillment System

    URL: https://fulfillment.example.com/api/orders
    Method: POST
    Body: {
      "invoice_id": "{{task_22001_o_inv_id}}",
      "client_id": "{{task_22001_client_id}}",
      "items": "{{task_22001_item_code}}",
      "quantities": "{{task_22001_item_quantity}}"
    }
    

  6. Task (in Global Automation): Email - Send Order Confirmation

    Subject: Order Confirmation - Invoice {{task_22001_o_inv_id}}
    Body: Your order has been confirmed and is being processed.
    

Result: Quotes seamlessly convert to invoices on approval, automatically triggering fulfillment and client communication workflows.


Example 3: Subscription Billing with Retry Logic

Scenario: Monthly recurring invoices for SaaS subscriptions with automated payment retry on failure.

Workflow Part 1: Monthly Billing

  1. Trigger: Timer Trigger - Monthly (1st of month at 09:00)

  2. Task: MySQL Query - Get Active Subscriptions

    SELECT client_id, subscription_plan_id, subscription_price, 
           subscription_item_code, subscription_item_description
    FROM clients
    WHERE subscription_status = 'Active'
      AND subscription_next_billing <= CURDATE()
    

  3. Task: Loop - Iterate Subscribers

    Loop through MySQL results
    

  4. Task (Inside Loop): BaseCloud Accounting - Create Invoice

    accounting_action: create_invoice
    Client ID: {{loop_item_client_id}}
    Invoice Layout ID: 7
    item_Description: {{loop_item_subscription_item_description}}
    item_Code: {{loop_item_subscription_item_code}}
    item_Quantity: 1
    item_Unit_Cost: {{loop_item_subscription_price}}
    item_Tax_Rate: 15
    tracking_category_1: 25  // Subscription revenue
    

  5. Task (Inside Loop): If Condition - Check Invoice Created

    Condition: {{task_22001_o_inv_id}} is not empty
    

  6. Task (Inside If - Success): Email - Send Invoice

    To: {{loop_item_client_email}}
    Subject: Monthly Subscription Invoice - {{task_22001_o_inv_id}}
    Body: Your subscription invoice is ready.
          Pay online: {{task_22001_payment_link}}
    Attachment: {{task_22001_document_url}}
    

  7. Task (Inside If - Success): MySQL - Update Next Billing Date

    UPDATE clients
    SET subscription_next_billing = DATE_ADD(CURDATE(), INTERVAL 1 MONTH)
    WHERE client_id = {{loop_item_client_id}}
    

  8. Task (Inside If - Fail): Email - Alert Accounting Team

    To: accounting@company.com
    Subject: FAILED: Invoice creation for client {{loop_item_client_id}}
    Body: Manual intervention required. Check client and subscription data.
    

Workflow Part 2: Payment Reminder (Separate Automation)

  1. Trigger: Timer Trigger - Daily (10:00)

  2. Task: MySQL Query - Get Unpaid Invoices (>7 days old)

    SELECT i.o_inv_id, i.client_id, c.email, c.first_name,
           i.total, i.payment_token, i.date_created
    FROM invoices i
    JOIN clients c ON i.client_id = c.client_id
    WHERE i.status = 0  -- Unpaid
      AND i.quote_invoice = 1  -- Invoice (not quote)
      AND DATEDIFF(CURDATE(), i.date_created) > 7
    

  3. Task: Loop - Send Reminders

  4. Task (Inside Loop): Email - Payment Reminder

    To: {{loop_item_email}}
    Subject: Payment Reminder - Invoice {{loop_item_o_inv_id}}
    Body: Hi {{loop_item_first_name}},
    
          This is a friendly reminder that invoice {{loop_item_o_inv_id}} 
          for ${{loop_item_total}} is still outstanding.
    
          Pay online: https://pay.basecloudglobal.com/{{loop_item_payment_token}}
    

Result: Fully automated subscription billing with monthly invoice generation and proactive payment reminders for overdue invoices.


Example 4: Project-Based Invoicing with Tracking

Scenario: Time tracking integration - create invoices with departmental and project tracking for accurate reporting.

Workflow:

  1. Trigger: Manual Button - Generate Project Invoice

  2. Task: MySQL Query - Get Billable Time Entries

    SELECT 
      t.description,
      SUM(t.hours) as total_hours,
      t.hourly_rate,
      t.department_id,
      t.project_id
    FROM time_entries t
    WHERE t.client_id = {{client_id}}
      AND t.billable = 1
      AND t.invoiced = 0
      AND t.project_id = {{selected_project_id}}
    GROUP BY t.description, t.hourly_rate, t.department_id, t.project_id
    

  3. Task: Formatter - Prepare Line Items

    Format: Pipe-delimited arrays
    item_Description: Join descriptions with |
    item_Code: "CONSULTING|CONSULTING|..."
    item_Quantity: Join total_hours with |
    item_Unit_Cost: Join hourly_rate with |
    item_Tax_Rate: "15|15|..."
    tracking_category_1: Join department_id with |
    tracking_category_2: Join project_id with |
    

  4. Task: BaseCloud Accounting - Create Invoice

    accounting_action: create_invoice
    Client ID: {{client_id}}
    Invoice Layout ID: 6
    item_Description: {{formatted_descriptions}}
    item_Code: {{formatted_codes}}
    item_Quantity: {{formatted_hours}}
    item_Unit_Cost: {{formatted_rates}}
    item_Tax_Rate: {{formatted_tax}}
    tracking_category_1: {{formatted_departments}}
    tracking_category_2: {{formatted_projects}}
    

  5. Task: MySQL - Mark Time Entries as Invoiced

    UPDATE time_entries
    SET invoiced = 1,
        invoice_id = {{task_22001_id}}
    WHERE client_id = {{client_id}}
      AND billable = 1
      AND invoiced = 0
      AND project_id = {{selected_project_id}}
    

  6. Task: Email - Send Invoice

    To: {{client_email}}
    Subject: Invoice {{task_22001_o_inv_id}} - Project {{project_name}}
    Body: Please find attached invoice for consulting services rendered 
          during the billing period.
    
          Total Hours: {{total_billable_hours}}
          Amount Due: ${{task_22001_total}}
    
          Pay online: {{task_22001_payment_link}}
    Attachment: {{task_22001_document_url}}
    

  7. Task: Workflow Note - Log Invoice

    Note: Project invoice {{task_22001_o_inv_id}} generated for {{total_billable_hours}} hours
          Department breakdown: {{formatted_departments}}
          Project: {{project_name}}
    Type: Finance
    

Reporting (Separate Automation):

  1. Trigger: Timer Trigger - Monthly (Last day at 23:00)

  2. Task: MySQL Query - Department Revenue by Tracking

    SELECT 
      tc1.label as department,
      SUM(il.total_incl) as revenue
    FROM invoice_line_items il
    JOIN tracking_categories_values tc1 ON il.tracking_category_1 = tc1.id
    JOIN invoices i ON il.invoice_id = i.id
    WHERE i.status = 1  -- Paid
      AND MONTH(i.date_paid) = MONTH(CURDATE())
      AND YEAR(i.date_paid) = YEAR(CURDATE())
    GROUP BY tc1.label
    ORDER BY revenue DESC
    

  3. Task: Email - Monthly Department Report

    To: finance@company.com
    Subject: Monthly Department Revenue Report
    Body: Revenue by department for {{current_month}}:
          {{mysql_results_table}}
    

Result: Time entries automatically converted to invoices with dual tracking (department + project), enabling granular financial reporting and project profitability analysis.


Scenario: Send clients a single payment link for multiple outstanding invoices.

Workflow:

  1. Trigger: Manual Button - Send Payment Reminder

  2. Task: MySQL Query - Get Unpaid Invoices for Client

    SELECT o_inv_id, total, date_created, payment_token
    FROM invoices
    WHERE client_id = {{client_id}}
      AND status = 0  -- Unpaid
      AND quote_invoice = 1  -- Invoice
    ORDER BY date_created ASC
    

  3. Task: Loop - Fetch Each Invoice Details

    Loop through MySQL results
    

  4. Task (Inside Loop): BaseCloud Accounting - Fetch Invoice

    accounting_action: fetch_quote_invoice
    Quote / Invoice ID: {{loop_item_o_inv_id}}
    

  5. Task (Inside Loop): Variable - Collect Payment Links

    Append to array:
    invoice_list: "{{task_22001_o_inv_id}}: ${{task_22001_total}} - {{task_22001_payment_link}}"
    

  6. Task: Formatter - Format Invoice List

    Format: HTML table
    Headers: Invoice #, Date, Amount, Pay Link
    Rows: {{invoice_list}}
    

  7. Task: Email - Send Consolidated Statement

    To: {{client_email}}
    Subject: Account Statement - Multiple Invoices Due
    Body: Hi {{client_first_name}},
    
          You have {{invoice_count}} outstanding invoices:
    
          {{formatted_invoice_table}}
    
          Please click the payment link next to each invoice to pay online.
    
          Total Amount Due: ${{total_outstanding}}
    

  8. Task: Workflow Note - Log Reminder Sent

    Note: Payment reminder sent for {{invoice_count}} unpaid invoices (total: ${{total_outstanding}})
    

Result: Clients receive organized statement with individual payment links for each outstanding invoice, improving payment collection rates.


Troubleshooting

Error: "No quote/invoice found"

Cause: Invalid document ID provided to fetch_quote_invoice or paid_quote_invoice

Solutions:

  1. Verify invoice ID exists in database:

    SELECT * FROM invoices WHERE o_inv_id = 'INV123'
    

  2. Check format - accepts "INV123", "QU456", or numeric "123"

  3. Ensure invoice belongs to correct owner (multi-tenant system)

  4. Use {{task_22001_o_inv_id}} from create action for subsequent fetches

Error: "Invoice already marked as paid"

Cause: Attempting to mark invoice as paid when status is not 0 (unpaid)

Solutions:

  1. Check current invoice status:

    fetch_quote_invoice action → Check {{task_22001_status}}
    

  2. Only mark unpaid invoices (status "Unpaid")

  3. Voided invoices (status=2) cannot be marked as paid

  4. Add conditional check before marking paid:

    If {{task_22001_status}} equals "Unpaid" → Then mark as paid
    

Error: "Invalid Date Paid provided"

Cause: Date string cannot be parsed by JavaScript Date constructor

Solutions:

  1. Use standard date formats:
  2. DD/MM/YYYY HH:mm
  3. YYYY-MM-DD
  4. MM/DD/YYYY

  5. Leave blank to default to today's date

  6. Use Date Formatter task to standardize date format

  7. Validate date before passing:

    If {{payment_date}} is not empty → Use {{payment_date}}
    Else → Leave empty (defaults to today)
    

Error: "Client ID not found"

Cause: client_id does not exist in clients table

Solutions:

  1. Verify client exists in CRM

  2. Use valid {{client_id}} from trigger or previous task

  3. Create client first with New Client task if needed

  4. Check for typos in client ID variable reference

Error: "Invoice Layout ID not found"

Cause: invoice_var_id does not exist in invoice_vars table

Solutions:

  1. Navigate to Settings → Invoice Layouts in CRM

  2. Verify layout exists and note correct ID

  3. Ensure layout belongs to current owner (multi-tenant)

  4. Use default layout ID if unsure (check with admin)

Error: "Line items length mismatch"

Cause: Pipe-delimited arrays have different lengths

Solutions:

  1. Count pipe delimiters in each field - must match:

    item_Description: "A|B|C"  // 3 items
    item_Code: "X|Y|Z"         // 3 items
    item_Quantity: "1|2|3"     // 3 items
    item_Unit_Cost: "10|20"    // 2 items ✗ MISMATCH
    

  2. Use Formatter task to ensure consistent array lengths

  3. Validate data source before creating invoice

  4. Use Loop task with individual line item creation if arrays are dynamic

PDF Generation Failed

Cause: Puppeteer/Chrome error during PDF rendering

Solutions:

  1. Check invoice layout HTML is valid (no unclosed tags)

  2. Ensure all placeholders in template have values

  3. Verify S3 credentials configured correctly (server-side)

  4. Check server has sufficient memory for Puppeteer

  5. Retry: Call fetch_quote_invoice again - regenerates PDF

  6. Contact BaseCloud support for persistent PDF failures

Cause: Payment token not generated or payment portal misconfigured

Solutions:

  1. Verify {{task_22001_payment_link}} is not empty

  2. Check payment portal is accessible: https://pay.basecloudglobal.com

  3. Ensure invoice belongs to owner with payment portal enabled

  4. Regenerate link by calling fetch_quote_invoice again

  5. Use payment portal directly with token:

    https://pay.basecloudglobal.com/{{task_22001_payment_token}}
    

Tracking Category Values Not Showing

Cause: Invalid tracking category value IDs provided

Solutions:

  1. Verify value IDs exist in tracking_categories_values table:

    SELECT * FROM tracking_categories_values WHERE id IN (12, 13, 45)
    

  2. Use correct numeric IDs (not labels)

  3. Leave blank if no tracking needed (not "null" string)

  4. Ensure tracking categories belong to correct owner

Global Trigger Not Firing

Cause: No automations configured for invoice_created or invoice_paid event

Solutions:

  1. Create automation with Trigger Type: Quote/Invoice Changes

  2. Select Variable: invoice_paid or invoice_created

  3. Ensure automation is Active (not disabled)

  4. Check trigger conditions (if any) are met

  5. Verify automation owner matches invoice owner

  6. Test by manually marking invoice as paid


Best Practices

Invoice Layout Design

  1. Test Templates: Create test invoice first to preview PDF output

  2. Responsive Design: Use tables and fixed widths for consistent PDF rendering

  3. Placeholder Validation: Ensure all placeholders have fallback values in template

  4. Branding: Include company logo, colors, and contact information

  5. Legal Requirements: Include tax registration numbers, terms, and payment instructions

Line Item Management

  1. Consistent Arrays: Always ensure all pipe-delimited fields have same number of items

  2. Item Codes: Use meaningful codes for reporting (e.g., "CONSULT", "DEV", "DESIGN")

  3. Descriptions: Be specific - helps clients understand charges

  4. Tax Rates: Verify correct tax rates per jurisdiction/product type

  5. Tracking: Assign tracking categories for financial reporting

Payment Collection

  1. Always Include Payment Links: Even if not primary payment method

  2. Email Timing: Send invoices during business hours for better engagement

  3. Payment Terms: Clearly state due dates and late payment policies

  4. Reminders: Set up automated reminders at 7, 14, and 30 days

  5. Multiple Channels: Send via email, SMS, and portal notifications

Automation Strategy

  1. Global Triggers: Leverage invoice_paid and invoice_created for centralized workflows

  2. Error Handling: Use If Conditions to handle invoice creation failures gracefully

  3. Logging: Always create workflow notes for invoice events (audit trail)

  4. Testing: Test automations with quotes first (less impact than invoices)

  5. Reconciliation: Regularly compare CRM invoices with accounting records

Security & Compliance

  1. Access Control: Limit invoice creation to authorized users/automations

  2. Data Privacy: Don't include sensitive client data in email bodies (use PDFs)

  3. Audit Trail: Use workflow notes to log all invoice actions

  4. Backup: Regular database backups include invoice data

  5. Tax Compliance: Ensure invoice layouts meet local tax authority requirements


FAQ

Q: Can I edit an invoice after it's created?

A: Not directly via task. Invoices are edit-protected once created. Options:

  • Void and create new invoice
  • Manually edit via database (not recommended)
  • Contact BaseCloud support for invoice edits

Q: What's the difference between quotes and invoices?

A:

  • Quotes (quote_invoice=0): Pre-sale documents, prefixed "QU", can be converted to invoices
  • Invoices (quote_invoice=1): Post-sale documents, prefixed "INV", used for payment collection

Both use same database table and share invoice numbering sequence.

Q: Can I delete or void invoices?

A: Yes, but not via task action:

  • Set status=2 in database to void
  • Triggers invoice_deleted global automation
  • Voided invoices still appear in reports (not deleted)

Q: How do I handle refunds or credit notes?

A: BaseCloud Accounting task doesn't support credit notes. Options:

  • Create negative amount invoice (workaround)
  • Handle refunds via payment processor directly
  • Request credit note feature from BaseCloud support

Q: Can I use custom invoice numbering?

A: Partially:

  • invoice_number field is auto-generated sequential
  • o_inv_id is formatted as "INV{number}" or "QU{number}"
  • Custom numbering requires database changes (contact support)

Q: What currencies are supported?

A: All currencies supported via currency_symbol in invoice layout:

  • Set per invoice layout in Settings
  • Default: $ (USD)
  • Examples: R (ZAR), £ (GBP), € (EUR), ¥ (JPY)

Note: BaseCloud Accounting doesn't handle currency conversion - use single currency per owner.

Q: How do I invoice multiple clients at once?

A: Use Loop task:

  1. MySQL Query: Get list of clients to invoice
  2. Loop: Iterate through results
  3. Inside Loop: Create Invoice task per client

See Example 3 (Subscription Billing) for complete implementation.

Q: Can I send invoices to multiple recipients?

A: Yes:

  • Use Email task with comma-separated addresses
  • Or use Loop to send individual emails per recipient
  • Payment portal link works for any recipient

Q: What happens if PDF generation fails?

A: Invoice is still created, but file_url is NULL:

  • Call fetch_quote_invoice to retry PDF generation
  • Check invoice layout HTML for errors
  • Contact support if persistent failures

Q: How do I integrate with external payment gateways?

A:

  • Use global trigger on invoice_paid event
  • Trigger Stripe/Paystack/PayPal webhook task
  • Or include payment link in invoice emails
  • Payment portal supports credit card processing

Q: Can I schedule invoice generation?

A: Yes, use Timer Trigger:

  • Set schedule (e.g., monthly on 1st at 09:00)
  • Add Create Invoice task
  • See Example 3 (Subscription Billing)

Q: How do I query invoices for reporting?

A: Use MySQL Query task:

-- Total revenue this month
SELECT SUM(total) as monthly_revenue
FROM invoices
WHERE status = 1  -- Paid
  AND MONTH(date_paid) = MONTH(CURDATE())
  AND owner_id = {current_owner}

-- Unpaid invoices by client
SELECT c.first_name, c.last_name, i.o_inv_id, i.total
FROM invoices i
JOIN clients c ON i.client_id = c.client_id
WHERE i.status = 0  -- Unpaid
  AND i.quote_invoice = 1  -- Invoice
ORDER BY i.date_created DESC

Q: What's the maximum number of line items per invoice?

A: No hard limit, but practical limits:

  • Database limit: 100+ line items supported
  • PDF rendering: Very long invoices may have formatting issues
  • Recommendation: Group similar items for better readability

Q: How do I add discounts to invoices?

A: BaseCloud Accounting doesn't have dedicated discount field. Workarounds:

  1. Discount Line Item: Add negative amount line item
  2. Pre-calculate: Subtract discount from unit cost
  3. Use Tracking: Mark discount items with specific tracking category

Q: Can I customize email templates for invoice emails?

A: Yes:

  • Email task allows full HTML customization
  • Use placeholders from task_22001_* variables
  • Include PDF attachment: {{task_22001_document_url}}
  • Include payment link: {{task_22001_payment_link}}

Q: How do I handle partial payments?

A: BaseCloud Accounting is binary (paid/unpaid). For partial payments:

  1. Create workflow note with partial amount
  2. Use custom client field to track balance
  3. Mark fully paid only when complete
  4. Or split invoice into multiple invoices per payment

Q: What happens when invoice is paid via payment portal?

A:

  1. Client pays via https://pay.basecloudglobal.com/{token}
  2. Payment processed by integrated gateway
  3. Invoice status updated to paid (status=1)
  4. date_paid set to today
  5. Global trigger fires invoice_paid automation
  6. Client receives payment confirmation email

Q: Can I use BaseCloud Accounting with external accounting software?

A: Yes, common integrations:

  • Export: Use MySQL Query to export invoice data
  • Xero/Sage: Create invoices in BaseCloud, sync to external system via API
  • QuickBooks: Export CSV and import
  • Custom Integration: Use global triggers + Webhook Out tasks

Q: How do I archive old invoices?

A: Invoices never deleted, only voided:

  • Query by date range to show recent invoices
  • Void old invoices: Set status=2
  • Use tracking categories to mark archived periods
  • Database retains all historical invoice data


Technical Details

  • Type ID: 22
  • Function: taskBaseCloudAccounting() in automationService.js (lines 5029-5650)
  • Database Tables: invoices, invoice_line_items, invoice_vars, invoice_layouts, tracking_categories_values
  • External Services: AWS S3 (PDF storage), Puppeteer (PDF generation)
  • Output Prefix: task_22001_*
  • Global Triggers: Type 3 (Quote/Invoice Changes) with var_id values: invoice_created, invoice_paid, invoice_edited, invoice_deleted