/admin/invoices
Path: /admin/invoices
Namespace: admin
Resource: invoices
Overview
The Invoice resource represents all business documents in ERPax using a unified model. The invoice_type field determines the document's role in the workflow.
Relationships
Model Associations
Invoice connects to the following resources:
Domain
- Type:
belongs_toviahost_id - Field:
host_id(tenant domain) - Description: Tenant domain for multi-tenant scoping. All invoices belong to a domain.
- Reverse: Domain has many invoices (
domain.invoices) - API Access:
- Direct: Included in invoice response as
host_id - Filter:
GET /admin/invoices.json?q[host_id_eq]=1
- Direct: Included in invoice response as
- Related Documentation: Domains
Address (Multiple Roles)
- Type:
belongs_tovia multiple foreign keys - Description: Business partner relationships. Addresses can serve multiple roles in an invoice.
- Roles:
seller_id- Seller address (defaults todomain.addressif omitted in admin namespace)buyer_id- Buyer/customer addresssupplier_id- Supplier address (for purchase documents)seller_agent_id- Seller's agent addressbuyer_agent_id- Buyer's agent addressconsignee_id- Delivery consignee address
- Reverse: Address has many invoices in different roles (accessed via filtering):
- Invoices where address is seller - Filter by
seller_id - Invoices where address is buyer - Filter by
buyer_id - Invoices where address is supplier - Filter by
supplier_id
- Invoices where address is seller - Filter by
- API Access:
- Direct:
invoice.seller_id,invoice.buyer_id, etc. - Filter:
GET /admin/invoices.json?q[seller_id_eq]=1- Invoices where address is sellerGET /admin/invoices.json?q[buyer_id_eq]=1- Invoices where address is buyerGET /admin/invoices.json?q[supplier_id_eq]=1- Invoices where address is supplier
- Direct:
- Related Documentation: Addresses
Invoice (Self-Referential)
- Type:
belongs_to/has_manyviaparent_id - Field:
parent_id - Description: Parent document for document hierarchies (quotation → invoice, purchase_order → protocol → bill)
- Reverse: Invoice has many child invoices (
invoice.children) - API Access:
- Direct:
invoice.parent_id(parent invoice ID) - Filter:
GET /admin/invoices.json?q[parent_id_eq]=123(child invoices for parent123; there is no nested/admin/invoices/:id/childrenroute)
- Direct:
- Example: Create invoice from quotation:javascript
const invoice = await fetch('/admin/invoices.json', { method: 'POST', body: JSON.stringify({ invoice: { parent_id: 123, // quotation ID invoice_type: 'invoice' } }) }).then(r => r.json());
InvoiceLine[]
- Type:
has_manyviainvoice_id - Description: Line items for this invoice. Contains products, quantities, prices, and totals.
- Reverse: InvoiceLine belongs to Invoice (
invoice_line.invoice) - API Access:
- Direct: Included in invoice response as
invoice_linesarray - Nested:
GET /admin/invoices/:id/invoice_lines.json - Filter:
GET /admin/invoice_lines.json?q[invoice_id_eq]=123
- Direct: Included in invoice response as
- Related Documentation: Invoice Lines
- Example: Get invoice lines for an invoice:javascript
const invoiceLines = await fetch('/admin/invoices/123/invoice_lines.json', { credentials: 'include', headers: { 'Accept': 'application/json' } }).then(r => r.json());
AccountingAccount
- Type:
belongs_toviacredit_account_idanddebit_account_id - Fields:
credit_account_id,debit_account_id - Description: Accounting accounts for credit and debit entries. Used when invoice is confirmed and accounted.
- Reverse: AccountingAccount has many invoices (via credit/debit account assignments)
- API Access:
- Direct:
invoice.credit_account_id,invoice.debit_account_id - Filter:
GET /admin/invoices.json?q[credit_account_id_eq]=10
- Direct:
- Related Documentation: Accounting
PackingLine[]
- Type:
has_manyviainvoice_id - Description: Shipping and packing information for delivery tracking
- Reverse: PackingLine belongs to Invoice (
packing_line.invoice) - API Access:
- Direct: Included in invoice response as
packing_linesarray (if present) - Nested:
GET /admin/invoices/:id/packing_lines.json
- Direct: Included in invoice response as
- Related Documentation: Packing Lines
Reverse Associations
The following resources connect to Invoice:
Payment[]
- Type:
has_manyon Invoice viainvoice_id - Description: Payments recorded against this invoice. Track payment amounts, dates, and methods.
- API Access:
- Direct: Included in invoice response as
paymentsarray (if present) - Nested:
GET /admin/invoices/:id/payments.json - Filter:
GET /admin/payments.json?q[invoice_id_eq]=123
- Direct: Included in invoice response as
- Related Documentation: Payments
- Example: Get all payments for an invoice:javascript
const payments = await fetch('/admin/invoices/123/payments.json', { credentials: 'include', headers: { 'Accept': 'application/json' } }).then(r => r.json());
AccountingEquation[]
- Type:
has_manyon Invoice via polymorphicaccountableassociation - Description: Double-entry accounting transactions created automatically when invoice is confirmed and accounted. Ensures debits equal credits.
- API Access:
- Direct: Included in invoice response as
accounting_equationsarray (if present) - Nested:
GET /admin/invoices/:id/accounting_equations.json - Filter (top-level index):
GET /admin/accounting_equations.json?q[accountable_id_eq]=123&q[accountable_type_eq]=Invoice(equations are linked via polymorphicaccountable, not aninvoice_idcolumn on the equation)
- Direct: Included in invoice response as
- Related Documentation: Accounting
- Example: Get accounting equations for an invoice:javascript
const equations = await fetch('/admin/invoices/123/accounting_equations.json', { credentials: 'include', headers: { 'Accept': 'application/json' } }).then(r => r.json());
Relationship Patterns
Creating an invoice and lines (two requests)
- Use Case: Create the invoice, then add lines using the nested invoice-lines route
- Example:javascript
const { invoice } = await fetch('/admin/invoices.json', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ invoice: { invoice_type: 'invoice', seller_id: 1, buyer_id: 2, date: '2026-03-15', currency_code: 'USD' } }) }).then(r => r.json()); await fetch(`/admin/invoices/${invoice.id}/invoice_lines.json`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ invoice_line: { seller_item_id: 1, quantity: 10, unit_price: '100.00', description: 'Product description' } }) }).then(r => r.json());
Filtering Invoices by Address
- Use Case: Get all invoices where a specific address is the seller, buyer, or supplier
- Example: Get invoices where address is seller:javascript
const sellerInvoices = await fetch('/admin/invoices.json?q[seller_id_eq]=123', { credentials: 'include', headers: { 'Accept': 'application/json' } }).then(r => r.json()); - Example: Get invoices where address is buyer:javascript
const buyerInvoices = await fetch('/admin/invoices.json?q[buyer_id_eq]=123', { credentials: 'include', headers: { 'Accept': 'application/json' } }).then(r => r.json());
Accessing Related Resources via Nested Endpoints
- Use Case: Get invoice lines for an invoice without loading the full invoice
- Example:javascript
const invoiceLines = await fetch('/admin/invoices/123/invoice_lines.json', { credentials: 'include', headers: { 'Accept': 'application/json' } }).then(r => r.json());
Document Hierarchy Navigation
- Use Case: Create a child invoice from a parent (e.g., invoice from quotation)
- Example:javascript
const invoice = await fetch('/admin/invoices.json', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: JSON.stringify({ invoice: { parent_id: 123, // quotation ID invoice_type: 'invoice', // Other fields inherited from parent } }) }).then(r => r.json());
Key Features
- Unified Document Model - One model handles all document types (invoices, purchase orders, quotations, etc.)
- Automatic Lifecycle Transitions - Documents automatically transition through workflow stages
- Automatic Accounting - Accounting entries created automatically when invoice is confirmed
- Multi-Currency Support - Full currency conversion and exchange rate management
- Namespace-Specific Behavior - Different default behaviors in admin, sales, and client namespaces
- Document Hierarchies - Support for parent-child relationships (quotation → invoice, purchase_order → protocol → bill)
Document Types
ERPax supports multiple invoice types:
Sales Documents:
cart- Shopping cart for online purchases (draft state, no number)request- Customer purchase requestquotation- Price quote for potential salesproforma_invoice- Preliminary invoice before final invoiceinvoice- Final sales invoice (must have number and date)credit_note- Document for refunds or adjustments (reduces amount owed)debit_note- Document for additional charges (increases amount owed)
Purchase Documents:
purchase_order- Order to suppliersprotocol- Goods receipt confirmation (has protocol_number and protocol_date)bill- Supplier invoice
Recurring Documents:
subscription- Recurring service agreementlease- Equipment or property lease
Document Lifecycle
Documents automatically transition through lifecycle stages:
Sales Process:
cart → request → quotation → proforma_invoice → invoice
↓
credit_note / debit_notePurchase Process:
purchase_order → protocol → billDocuments inherit context from parent documents and automatically handle field normalization, account assignment, exchange rate updates, and number generation.
Namespace-Specific Behavior
Invoice creation behaves differently across namespaces, particularly regarding automatic seller/buyer assignment:
Admin Namespace:
- Default Seller: Domain address is automatically used as seller if
seller_idis omitted.
Sales Namespace:
- Fixed Seller: Host address is automatically set as seller. Domain address is used as supplier.
Client Namespace:
- Default Buyer: User address is automatically used as buyer. Seller must be from host addresses.
Available Operations
List Invoices (GET)
Endpoint: GET /admin/invoices.json
Query Parameters:
q[field_predicate]=value- Ransack query filters for advanced filteringscope=name- Apply named scope (e.g.,unpaid,due,confirmed)page=N- Page number for paginationper_page=N- Items per page (default: 25)
Request Examples:
curl -X GET "https://your-company.erpax.com/admin/invoices.json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"curl -X GET "https://your-company.erpax.com/admin/invoices.json?q[invoice_type_eq]=invoice" \
-H "Accept: application/json"curl -X GET "https://your-company.erpax.com/admin/invoices.json?q[date_gteq]=2024-01-01&q[date_lteq]=2024-12-31" \
-H "Accept: application/json"curl -X GET "https://your-company.erpax.com/admin/invoices.json?q[seller_id_eq]=1&q[buyer_id_eq]=2" \
-H "Accept: application/json"curl -X GET "https://your-company.erpax.com/admin/invoices.json?scope=unpaid&page=1&per_page=25" \
-H "Accept: application/json"JavaScript Example:
const response = await fetch('/admin/invoices.json', {
credentials: 'include',
headers: { 'Accept': 'application/json' }
});
const data = await response.json();Response (200 OK):
{
"invoices": [
{
"id": 1,
"invoice_type": "invoice",
"number": "INV-2024-001",
"date": "2024-01-15",
"seller_id": 1,
"buyer_id": 2,
"currency_code": "USD",
"total_amount_cents": 100000,
"total_amount": "1000.00",
"confirmed": true,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 25,
"total_pages": 5,
"total_count": 123
}
}Show Invoice (GET /:id)
Endpoint: GET /admin/invoices/:id.json
Request Example:
curl -X GET "https://your-company.erpax.com/admin/invoices/123.json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"JavaScript Example:
const response = await fetch('/admin/invoices/123.json', {
credentials: 'include',
headers: { 'Accept': 'application/json' }
});
const invoice = await response.json();Response (200 OK):
{
"invoice": {
"id": 123,
"invoice_type": "invoice",
"number": "INV-2024-001",
"date": "2024-01-15",
"seller_id": 1,
"buyer_id": 2,
"currency_code": "USD",
"total_amount_cents": 100000,
"confirmed": true,
"invoice_lines": [
{
"id": 1,
"seller_item_id": 1,
"quantity": 10,
"unit_price": "100.00",
"total_amount_cents": 100000
}
],
"payments": [],
"accounting_equations": []
}
}Response (404 Not Found):
{
"error": "Invoice not found"
}Create Invoice (POST)
Endpoint: POST /admin/invoices.json
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices.json" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"invoice": {
"invoice_type": "invoice",
"seller_id": 1,
"buyer_id": 2,
"date": "2026-03-15",
"currency_code": "USD",
"invoice_lines_attributes": [
{
"seller_item_id": 1,
"quantity": 10,
"unit_price": "100.00",
"description": "Product description"
}
]
}
}'Line items: You can send invoice_lines_attributes on create as above (correct keys: seller_item_id, quantity, unit_price, description). If the server ignores nested lines, create the invoice first, then POST /admin/invoices/:id/invoice_lines.json with an invoice_line object using the same fields (see Invoice lines).
JavaScript Example:
const response = await fetch('/admin/invoices.json', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
invoice: {
invoice_type: 'invoice',
seller_id: 1,
buyer_id: 2,
date: '2026-03-15',
currency_code: 'USD',
invoice_lines_attributes: [
{
seller_item_id: 1,
quantity: 10,
unit_price: '100.00',
description: 'Product description'
}
]
}
})
});
const invoice = await response.json();Response (201 Created):
{
"invoice": {
"id": 123,
"invoice_type": "invoice",
"number": null,
"date": "2026-03-15",
"seller_id": 1,
"buyer_id": 2,
"currency_code": "USD",
"total_amount_cents": 100000,
"confirmed": false,
"created_at": "2026-03-15T14:30:00Z"
}
}Response (422 Unprocessable Entity):
{
"errors": {
"seller_id": ["can't be blank"],
"buyer_id": ["can't be blank"],
"date": ["can't be blank"]
}
}Update Invoice (PATCH /:id)
Endpoint: PATCH /admin/invoices/:id.json
Request Example:
curl -X PATCH "https://your-company.erpax.com/admin/invoices/123.json" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"invoice": {
"confirmed": true
}
}'JavaScript Example:
const response = await fetch('/admin/invoices/123.json', {
method: 'PATCH',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
invoice: {
confirmed: true
}
})
});
const invoice = await response.json();Response (200 OK):
{
"invoice": {
"id": 123,
"number": "INV-2024-001",
"confirmed": true,
"updated_at": "2024-01-15T15:00:00Z"
}
}Note: Once an invoice is confirmed, most fields become read-only. Only users with specific permissions can modify confirmed invoices.
Delete Invoice (DELETE /:id)
Endpoint: DELETE /admin/invoices/:id.json
Request Example:
curl -X DELETE "https://your-company.erpax.com/admin/invoices/123.json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"JavaScript Example:
const response = await fetch('/admin/invoices/123.json', {
method: 'DELETE',
credentials: 'include',
headers: { 'Accept': 'application/json' }
});Response (204 No Content):
(empty response)Response (422 Unprocessable Entity):
{
"error": "Cannot delete confirmed invoice"
}Batch Actions
Endpoint: POST /admin/invoices/batch_action.json
Available batch actions:
- filter - Filter collection to show only selected records
- update - Update selected records with form fields (domain, debit_code, credit_code, next_billing_date, delivered_at, confirmed)
- renew - Renew selected renewable invoices (available when scope is 'renewable')
- cancel - Cancel selected invoices (sets cancelled_at to current time)
- confirm - Confirm selected invoices (sets confirmed to true)
- account - Create accounting entries for selected unaccounted invoices (available when scope is 'unaccounted')
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/batch_action.json" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"batch_action": "confirm",
"collection_selection": [1, 2, 3]
}'Member Actions
Custom actions available on individual invoices via API:
Print Invoice
Endpoint: GET /admin/invoices/:id/print
Description: Generate and return a printable version of the invoice.
Request Example:
curl -X GET "https://your-company.erpax.com/admin/invoices/123/print" \
-H "Accept: application/pdf" \
-H "Cookie: session_cookie"Response: Returns PDF or HTML printable version of the invoice.
Email Invoice
Endpoint: GET /admin/invoices/:id/email
Description: Send the invoice via email to the buyer.
Request Example:
curl -X GET "https://your-company.erpax.com/admin/invoices/123/email" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (200 OK):
{
"message": "Email sent successfully"
}Duplicate Invoice
Endpoint: POST /admin/invoices/:id/duplicate
Description: Create a duplicate copy of the invoice.
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/duplicate" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (201 Created):
{
"invoice": {
"id": 124,
"invoice_type": "invoice",
"number": null,
"date": "2024-01-15",
...
}
}Renew Invoice
Endpoint: POST /admin/invoices/:id/renew
Description: Renew a recurring invoice (subscription or lease).
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/renew" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (200 OK):
{
"invoice": {
"id": 123,
"next_billing_date": "2024-02-15",
...
}
}Create Backorder
Endpoint: POST /admin/invoices/:id/backorder
Description: Create a backorder for items that are out of stock.
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/backorder" \
-H "Accept: application/json" \
-H "Cookie: session_cookie"Response (201 Created):
{
"invoice": {
"id": 125,
"invoice_type": "backorder",
...
}
}Create Payment
Endpoint: POST /admin/invoices/:id/create_payment
Description: Create a payment record for the invoice.
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/create_payment" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"payment": {
"amount_cents": 100000,
"payment_method_id": 1,
"date": "2024-01-15"
}
}'Response (201 Created):
{
"payment": {
"id": 1,
"invoice_id": 123,
"amount_cents": 100000,
...
}
}Create Credit Note
Endpoint: POST /admin/invoices/:id/create_credit_note
Description: Create a credit note (refund or adjustment) for the invoice.
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/create_credit_note" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"credit_note": {
"reason": "Returned items",
"amount_cents": 50000
}
}'Response (201 Created):
{
"invoice": {
"id": 126,
"invoice_type": "credit_note",
"parent_id": 123,
...
}
}Create Debit Note
Endpoint: POST /admin/invoices/:id/create_debit_note
Description: Create a debit note (additional charge) for the invoice.
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/create_debit_note" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"debit_note": {
"reason": "Additional charges",
"amount_cents": 25000
}
}'Response (201 Created):
{
"invoice": {
"id": 127,
"invoice_type": "debit_note",
"parent_id": 123,
...
}
}Create Protocol
Endpoint: POST /admin/invoices/:id/create_protocol
Description: Create a protocol (goods receipt) for a purchase order.
Request Example:
curl -X POST "https://your-company.erpax.com/admin/invoices/123/create_protocol" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Cookie: session_cookie" \
-d '{
"protocol": {
"protocol_number": "PROT-2024-001",
"protocol_date": "2024-01-15"
}
}'Response (201 Created):
{
"invoice": {
"id": 128,
"invoice_type": "protocol",
"parent_id": 123,
"protocol_number": "PROT-2024-001",
...
}
}Scopes
Scopes are organized into groups for better navigation:
- active (default, group: status) - Active invoices only
- pending (group: shipping) - Active undelivered invoices
- renewable (group: recurring) - Active renewable invoices
- leads (group: document) - Active lead documents
- orders (group: document) - Active order documents
- accountable (group: accounting) - Active invoices that can be accounted
- accounted (group: accounting) - Active invoices that have been accounted
- unaccounted (group: accounting) - Active invoices that have not been accounted
- paid (group: billing) - Active paid invoices
- unpaid (group: billing) - Active unpaid invoices
- due (group: billing) - Active invoices that are due
- cancelled (group: status) - Cancelled invoices
Usage Example:
GET /admin/invoices.json?scope=unpaid
GET /admin/invoices.json?scope=due
GET /admin/invoices.json?scope=renewableFilters
Available filters for searching and filtering invoices:
Address Filters
- domain - Select filter (multiple) - Filter by domain
- seller - Select filter (multiple) - Filter by seller address
- seller_agent - Select filter (multiple) - Filter by seller agent
- buyer - Select filter (multiple) - Filter by buyer address
- buyer_agent - Select filter (multiple) - Filter by buyer agent
- supplier - Select filter (multiple) - Filter by supplier address
- consignee - Select filter (multiple) - Filter by consignee address
Document Filters
- document_number (label) - Text filter - Search by number, parent_number, protocol_number, purchase_order, or sales_order
- line_search (label) - Text filter - Search by invoice_lines code, name, or description
- invoice_type - Select filter (multiple) - Filter by invoice type
- number - Text filter - Filter by invoice number
- period - Date filter - Filter by period
Date Filters
- date - Date filter
- order_date - Date filter
- proforma_date - Date filter
- payment_date - Date filter
- delivery_date - Date filter
- delivered_at - Date filter
- cancelled_at - Date filter
- created_at - Date filter
- updated_at - Date filter
- next_billing_date - Date filter (shown when scope is 'renewable')
Currency and Financial Filters
- currency_code - Select filter (multiple) - Filter by currency code
- item_total_cents - Numeric range filter
- discount_total_cents - Numeric range filter
- net_total_cents - Numeric range filter
- tax_total_cents - Numeric range filter
- total_amount_cents - Numeric range filter
- total_paid_cents - Numeric range filter
- total_due_cents - Numeric range filter
Accounting Filters
- debit_account - Filter by debit account
- credit_account - Filter by credit account
Status Filters
- confirmed - Boolean filter - Filter by confirmation status
Filtering Examples:
# Text search
GET /admin/invoices.json?q[number_cont]=INV-2024
# Date range
GET /admin/invoices.json?q[date_gteq]=2024-01-01&q[date_lteq]=2024-12-31
# Multiple conditions
GET /admin/invoices.json?q[invoice_type_eq]=invoice&q[confirmed_eq]=true&q[total_amount_cents_gteq]=100000
# Association filters
GET /admin/invoices.json?q[seller_code_cont]=CUST&q[buyer_name_cont]=SupplierSee API Reference for complete Ransack query syntax.
Business Rules
Automatic Behaviors
- Number Generation: Invoice numbers are automatically generated when invoice is confirmed
- Accounting Integration: Accounting entries are automatically created when invoice is confirmed
- Field Normalization: Fields are automatically normalized based on invoice type
- Account Assignment: Accounting accounts are automatically assigned based on invoice type and configuration
- Exchange Rate Updates: Exchange rates are automatically updated based on currency and date
Document Lifecycle Rules
- Confirmation: Once confirmed, most fields become read-only
- Parent-Child Relationships: Child documents inherit context from parent documents
- Automatic Transitions: Documents automatically transition through workflow stages
EU VAT Compliance
For EU VAT invoices, ensure:
- Seller and buyer addresses have
tax_code(VAT ID) populated tax_typeis set to'vat'- Tax rates are correctly configured
- Invoice has all mandatory fields (number, date, seller, buyer, line items with tax)
Workflow Examples
Creating a Sales Invoice:
- Create quotation with
invoice_type: 'quotation' - Add invoice lines with products, quantities, and prices
- Confirm quotation (triggers automatic transitions)
- Convert to proforma_invoice or invoice as needed
- Confirm invoice to generate invoice number
- Invoice becomes read-only after confirmation
Creating a Purchase Order:
- Create purchase_order
- Set buyer to your company, seller to supplier
- Add purchase order lines
- Confirm purchase order
- Create protocol when goods are received
- Create bill when supplier invoice is received
Nested Resources
The Invoice resource has the following nested resources:
- Invoice Lines - /admin/invoices/:id/invoice_lines - Line items for the invoice
- Invoice Payments - /admin/invoices/:id/invoice_payments - Payments associated with the invoice
- Accounting Equations - /admin/invoices/:id/accounting_equations - Accounting transactions for the invoice
- Packing Lines - /admin/invoices/:id/packing_lines - Packing and shipping details
Related Resources
- Addresses - Manage seller/buyer addresses
- Items - Manage products for invoice lines
- Payments - Manage payments
- Accounting - Chart of accounts and accounting resources