Invoices Sub Service - Nioron07/Easy-Acumatica GitHub Wiki

This guide covers the InvoicesService, your primary tool for creating, retrieving, updating, and releasing AR Invoice records through the contract-based API.

1. Importing Helpers

Before you start, import the necessary helpers for building invoice payloads and queries.

from easy_acumatica.models.invoice_builder import InvoiceBuilder  
from easy_acumatica.models.query_builder import QueryOptions, CustomField  
from easy_acumatica.models.filter_builder import F

2. Retrieving Invoices

get_invoices(api_version, options=None)

This is the main method for fetching a list of invoice records. It can be used to get all invoices or a filtered, specific list by using QueryOptions.

Example: Get all open invoices

# Create a filter for invoices with an 'Open' status  
my_filter = (F.Status == 'Open')

# Use QueryOptions to select specific fields and page the results  
opts = QueryOptions(  
    filter=my_filter,  
    select=["ReferenceNbr", "Type", "Customer", "Amount"],  
    top=25  
)

# Fetch the invoices  
open_invoices = client.invoices.get_invoices("24.200.001", options=opts)

for invoice in open_invoices:  
    print(f"Ref Nbr: {invoice['ReferenceNbr']['value']}, Amount: {invoice['Amount']['value']}")

3. Creating and Updating Invoices

create_invoice(api_version, builder, options=None)

Use this method to create a new invoice. You must provide an InvoiceBuilder object containing the new invoice's details.

Example: Create an invoice with overridden taxes

# Build the invoice payload  
invoice_payload = (  
    InvoiceBuilder()  
    .type("Invoice")  
    .customer("AACUSTOMER")  
    .date("2025-01-23")  
    .description("Invoice with custom tax override")  
    .is_tax_valid(True) # This is required to override taxes  
    .add_detail_line("CONSULTING", 10, 100.0)  
    .add_tax_detail("GST", 1000.0, 50.0) # Manually specify tax  
    .set_custom_field("CurrentDocument", "TaxZoneID", "CANADABC")  
)

# Use QueryOptions to get the details back in the response  
response_opts = QueryOptions(expand=["Details", "TaxDetails"])

# Create the invoice  
new_invoice = client.invoices.create_invoice(  
    "24.200.001",   
    invoice_payload,   
    options=response_opts  
)  
print(f"Successfully created invoice: {new_invoice['ReferenceNbr']['value']}")

update_invoice(api_version, builder, options=None)

Use this method to update an existing invoice. You must identify the invoice by calling the .id() method on the builder with the invoice's NoteID (GUID).

Example: Change the Tax Zone of an existing invoice

# The NoteID (GUID) of the invoice to update  
invoice_note_id = "8deb6bf9-2072-eb11-b83e-00155d408001"

# Define the fields to update  
update_payload = (  
    InvoiceBuilder()  
    .id(invoice_note_id)  
    .set_custom_field("CurrentDocument", "TaxZoneID", "AVALARA")  
)

# Specify in QueryOptions that you want the custom field in the response  
custom_opts = QueryOptions(custom=[CustomField.field("CurrentDocument", "TaxZoneID")])

# Perform the update  
updated_invoice = client.invoices.update_invoice(  
    "24.200.001",   
    update_payload,  
    options=custom_opts  
)

4. Releasing an Invoice

release_invoice(api_version, note_id)

This invokes the ReleaseInvoice action, which posts the invoice to the General Ledger, changing its status from Balanced to Open. This is a critical financial step and cannot be easily undone.

Example: Release an invoice

# The NoteID (GUID) of the invoice to release  
invoice_note_id_to_release = "8beb2af9-fa58-ec11-9e16-9828a61840c3"

# Release the invoice  
# This action is often asynchronous; the method handles polling for completion.  
print(f"Releasing invoice {invoice_note_id_to_release}...")  
client.invoices.release_invoice(  
    "24.200.001",  
    note_id=invoice_note_id_to_release  
)  
print("Invoice released successfully.")