Invoice Scripts
Table of Contents
- Overview
- When Invoice Scripts Run
- Context Variables
- Output Format
- invoice (Optional)
- invoice_items (Optional)
- Return Behaviour
- Examples
- Example 1: Modifying the Default Invoice Item
- Example 2: Adding Multiple Invoice Items
- Example 3: Conditional Invoicing Based on User and Multi-Resource Reservations
- Example 4: Modifying Invoice Properties
- Example 5: Dynamic Pricing Based on Reservation Quantity
- Best Practices
Overview
Invoice Scripts are powerful tools that allow you to customize how invoice items are generated when a reservation is added to an invoice. By attaching an Invoice Script to a resource, you can dynamically modify invoice items, add additional items, or even remove items entirely based on custom business logic.
When Invoice Scripts Run
Invoice Scripts are triggered when:
- A reservation for a resource with an attached Invoice Script is added to an invoice
- The system automatically processes reservations for invoicing
Context Variables
Invoice Scripts have access to the following global variables:
invoice
: Information about the invoice being generatedinvoice_items
: The default invoice items that would be created without scriptingreservation
: Contains all details about the reservation being invoicedparent_reservation
: Information about the parent reservation when the current reservation is part of a multi-resource reservation
Output Format
An Invoice Script must return a dictionary with the following structure:
invoice
(Optional)
A dictionary containing modifications to make to the invoice. This can include:
Field | Type | Description |
---|---|---|
bill_to_user_id |
string | 32-character alphanumeric ID of the user to bill |
bill_to_name |
string | Name to display on the invoice |
bill_to_email |
string | Email address for billing |
bill_to_account_number |
string | Account number for the billed party |
bill_to_address |
string | Billing address |
memo |
string | Memo to display on the invoice |
payment_instructions |
string | Instructions for payment |
purchase_order_number |
string | PO number reference |
invoice_address |
string | Address of the invoicing entity |
hidden_note |
string | Internal note (not visible to customer) |
due_date |
string | Due date in ISO format (YYYY-MM-DD) |
invoice_date |
string | Invoice date in ISO format (YYYY-MM-DD) |
deposit_amount |
float | Deposit amount applied to the invoice |
status |
string | Status of the invoice |
status_detail |
string | Additional status details |
invoice_items
(Optional)
A list of invoice items to include. Each item is a dictionary with:
Field | Type | Description |
---|---|---|
date |
string | Date for the item in ISO format (YYYY-MM-DD) |
item |
string | Short name of the item |
sku |
string | Stock Keeping Unit identifier |
description |
string | Detailed description of the item |
units |
float/integer | Quantity of units |
unit_rate |
float/integer | Price per unit |
units_name |
string | Name of the unit (e.g., "hours", "sessions") |
tax_rate |
integer | Tax rate to apply stored as 10000 * rate (e.g. 13.4% stored as 134000 ) |
tax_code |
string | Tax code for the item |
tax_note |
string | Additional tax information |
Note
Tax rates are stored as 10000 * rate
where rate
is the percentage rate of a tax rate. For example, a tax rate of 13.4% is stored as 10000 * 13.4 = 134000
.
Return Behaviour
- If you return
{}
(empty dictionary): The default invoice item will be used - If you return
{'invoice_items': []}
(empty list): No invoice items will be created (removes default item) - If you don't include
invoice_items
in the return: The default invoice item will be used - If you include
invoice_items
with items: Only the items you specify will be used (replaces default)
Examples
Example 1: Modifying the Default Invoice Item
# This script modifies the description and adds a tax rate to the default invoice item
# Get information from the reservation
resource_name = util.dicts.get(d=reservation, path='reservable.name')
hours_reserved = util.dicts.get(d=reservation, path='duration') / 3600
# Create a more detailed description
detailed_description = "Reservation of " + str(resource_name) + " for " + str(hours_reserved) + " hours"
# Get the default invoice item (assuming it's the first item in the list)
modified_item = invoice_items[0]
# Update fields in the default item
modified_item = modified_item + {'description': detailed_description}
modified_item = modified_item + {'tax_rate': 70000} # 7% tax rate
modified_item = modified_item + {'tax_code': 'EQUIPMENT-7'}
# Return the modified item
return {
'invoice_items': [modified_item]
}
Example 2: Adding Multiple Invoice Items
# This script splits a reservation into multiple invoice items
# (e.g., base fee plus hourly charges)
# Extract required information
duration_hours = util.dicts.get(d=reservation, path='duration') / 3600
resource_name = util.dicts.get(d=reservation, path='reservable.name')
base_rate = 50.00
hourly_rate = 25.00
# Create list for our invoice items
items = []
# Add base fee item
base_item = {
'item': 'Base Fee',
'description': "Setup fee for " + str(resource_name),
'units': 1,
'unit_rate': base_rate,
'units_name': 'fee',
'tax_rate': 70000
}
items = items + [base_item]
# Add hourly charges item
hourly_item = {
'item': 'Usage Fee',
'description': "Usage of " + str(resource_name) + " (" + str(duration_hours) + " hours)",
'units': duration_hours,
'unit_rate': hourly_rate,
'units_name': 'hours',
'tax_rate': 70000
}
items = items + [hourly_item]
# Return both items
return {
'invoice_items': items
}
Example 3: Conditional Invoicing Based on User and Multi-Resource Reservations
# This script applies different billing rules based on the user type
# Get user information
user_id = util.dicts.get(d=reservation, path='reserved_for.user_id')
# Define our internal user IDs (for example purposes)
internal_user_ids = [
'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
'q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2'
]
# Check if user is internal
if user_id in internal_user_ids:
# For internal users, don't create any invoice items
return {
'invoice_items': []
}
else:
# For external users, apply a special rate
modified_items = []
for invoice_item in invoice_items:
modified_item = invoice_item
modified_item = modified_item + {"item": "External Usage"}
modified_item = modified_item + {"unit_rate": 75.00}
modified_item = modified_item + {"description": "External user rate - " + modified_item['description']}
modified_items = modified_items + [modified_item]
return {
'invoice_items': modified_items
}
Example 4: Modifying Invoice Properties
# This script modifies both invoice items and invoice properties
# Current date plus 30 days for due date
today = datetime.now()
due_date = datetime.add(dt=today, days=90)
# Get default item and modify (using the first item in the invoice_items list)
modified_item = invoice_items[0]
modified_item = modified_item + {"description": "Premium service fee"}
# Create our return object with invoice modifications
return {
'invoice': {
'payment_instructions': "Payment due within 90 days. Please include invoice number.",
'memo': "Thank you for your business!",
'due_date': due_date,
},
'invoice_items': [modified_item]
}
Example 5: Dynamic Pricing Based on Reservation Quantity
# This script adjusts pricing based on the quantity reserved
# Get reservation details
quantity = util.dicts.get(d=reservation, path='units')
resource_name = util.dicts.get(d=reservation, path='reservable.name')
# Base pricing
base_rate = 100.00
# Apply volume discounts
if quantity >= 10:
discounted_rate = base_rate * 0.8 # 20% discount
discount_text = "20% volume discount applied"
if quantity >= 5 and quantity < 10:
discounted_rate = base_rate * 0.9 # 10% discount
discount_text = "10% volume discount applied"
if quantity < 5:
discounted_rate = base_rate
discount_text = "Standard rate"
# Create our invoice item
item = {
'item': resource_name,
'description': str(resource_name) + " x " + str(quantity) + " - " + str(discount_text),
'units': quantity,
'unit_rate': discounted_rate,
'units_name': 'units',
'sku': "RES-" + str(resource_name)
}
# Return the item
return {
'invoice_items': [item]
}
Best Practices
Testing: Always test your invoice scripts thoroughly with different scenarios before using them in production.
Default Values: When modifying the default invoice item, start by making a copy to avoid losing important default values.
Consistency: Maintain consistent pricing and billing logic across related resources.
Documentation: Keep documentation of your custom billing rules for reference by your team.