Skip to content

/admin/items

Path: /admin/items
Namespace: admin
Resource: items

Overview

The Item resource represents sellable products with variants, properties, pricing, inventory tracking, and multi-domain support. Items are used in invoice lines and can be associated with addresses.

Relationships

Model Associations

Item connects to the following resources:

Address
  • Type: belongs_to via seller_id or address_id
  • Field: seller_id, address_id
  • Description: Address that owns this item. Items can be associated with addresses for seller/buyer-specific product catalogs.
  • Reverse: Address has many items (address.items)
  • API Access:
    • Direct: Included in item response as seller_id or address_id
    • Filter: GET /admin/items.json?q[address_id_eq]=123
    • Nested: GET /admin/addresses/:id/items.json (items owned by address)
  • Related Documentation: Addresses
  • Example: Get all items owned by an address:
    javascript
    const items = await fetch('/admin/addresses/123/items.json', {
      credentials: 'include',
      headers: { 'Accept': 'application/json' }
    }).then(r => r.json());
Domain
  • Type: belongs_to via host_id
  • Field: host_id
  • Description: Tenant domain for multi-tenant scoping. Items belong to a domain.
  • Reverse: Domain has many items (domain.items)
  • API Access:
    • Direct: Included in item response as host_id
    • Filter: GET /admin/items.json?q[host_id_eq]=1
  • Related Documentation: Domains
Domain[] (Multi-Domain Visibility)
  • Type: has_and_belongs_to_many via domains_items join table
  • Description: Domains with access to this item. Items can be visible to multiple domains (multi-domain visibility).
  • Reverse: Domain has many items via domains_items join table
  • API Access:
    • Direct: Included in item response as domains array (if present)
    • Filter: GET /admin/items.json?q[domains_id_eq]=1 (items visible to domain)
  • Example: Filter items visible to a specific domain:
    javascript
    const items = await fetch('/admin/items.json?q[domains_id_eq]=1', {
      credentials: 'include',
      headers: { 'Accept': 'application/json' }
    }).then(r => r.json());
AccountingAccount (Multiple Accounts)
  • Type: belongs_to via multiple foreign keys
  • Fields: credit_account_id, debit_account_id, tax_credit_account_id, tax_debit_account_id
  • Description: Accounting accounts for credit, debit, and tax entries. Used for automatic accounting when items are used in invoice lines.
  • Reverse: AccountingAccount has many items (via credit/debit/tax account assignments)
  • API Access:
    • Direct: item.credit_account_id, item.debit_account_id, etc.
    • Filter: GET /admin/items.json?q[credit_account_id_eq]=10
  • Related Documentation: Accounting
Product
  • Type: belongs_to via product_id (optional)
  • Field: product_id
  • Description: Product template this item was created from. Items can be created from products in the catalog.
  • Reverse: Product has many items (product.items)
  • API Access:
    • Direct: item.product_id (may be null)
    • Filter: GET /admin/items.json?q[product_id_eq]=123
    • Nested: GET /admin/products/:id/items.json (items created from product)
  • Related Documentation: Catalog

Reverse Associations

The following resources connect to Item:

InvoiceLine (Multiple Roles)
  • Type: has_many on InvoiceLine via seller_item_id and buyer_item_id
  • Description: Invoice lines using this item as seller item or buyer item. Items are used in invoice lines to represent products in transactions.
  • API Access:
    • Filter:
      • GET /admin/invoice_lines.json?q[seller_item_id_eq]=123 - Lines using item as seller_item
      • GET /admin/invoice_lines.json?q[buyer_item_id_eq]=123 - Lines using item as buyer_item
    • Via Invoice: GET /admin/invoices/:id/invoice_lines.json (then filter by item_id)
  • Related Documentation: Invoice Lines
  • Example: Get all invoice lines using this item as seller item:
    javascript
    const invoiceLines = await fetch('/admin/invoice_lines.json?q[seller_item_id_eq]=123', {
      credentials: 'include',
      headers: { 'Accept': 'application/json' }
    }).then(r => r.json());

Relationship Patterns

Using Items in Invoice Lines
  • Use Case: Add an item to an invoice as a line item
  • Example: Create invoice with item in invoice line:
    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: '2024-01-15',
          invoice_lines_attributes: [
            {
              seller_item_id: 123, // Item ID
              quantity: 10,
              unit_price_cents: 10000
            }
          ]
        }
      })
    }).then(r => r.json());
Filtering Items by Owner
  • Use Case: Get all items owned by a specific address
  • Example:
    javascript
    const addressItems = await fetch('/admin/items.json?q[address_id_eq]=123', {
      credentials: 'include',
      headers: { 'Accept': 'application/json' }
    }).then(r => r.json());
Multi-Domain Item Visibility
  • Use Case: Make an item visible to multiple domains
  • Example: When creating an item, specify domains:
    javascript
    const item = await fetch('/admin/items.json', {
      method: 'POST',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify({
        item: {
          code: 'PROD-001',
          name: 'Widget',
          address_id: 1,
          domain_ids: [1, 2, 3] // Visible to multiple domains
        }
      })
    }).then(r => r.json());

Key Features

  • Product Catalog: Manage product information, descriptions, images
  • Inventory Tracking: inventory_quantity, inventory_policy for stock management
  • Pricing: Multiple price fields (price, cost, vendor_price, min_price, compare_at_price)
  • Tax Configuration: tax_rate, tax_type for tax calculation
  • Accounting Integration: debit_account_id, credit_account_id for automatic accounting
  • Multi-currency: Currency support with exchange rates
  • Variants & Properties: Support for product variants and custom properties
  • Domain Scoping: Items can be associated with multiple domains

Inventory Management

Items support inventory tracking:

  • inventory_quantity: Current stock level
  • inventory_policy: Inventory management policy
  • Scopes: in_stock, out_of_stock

Available Operations

List Items (GET)

Endpoint: GET /admin/items.json

Query Parameters:

  • q[field_predicate]=value - Ransack query filters for advanced filtering
  • scope=name - Apply named scope (e.g., in_stock, out_of_stock, drafts)
  • page=N - Page number for pagination
  • per_page=N - Items per page (default: 25)

Request Examples:

bash
curl -X GET "https://your-company.erpax.com/admin/items.json" \
  -H "Accept: application/json" \
  -H "Cookie: session_cookie"
bash
curl -X GET "https://your-company.erpax.com/admin/items.json?q[name_cont]=Product" \
  -H "Accept: application/json"
bash
curl -X GET "https://your-company.erpax.com/admin/items.json?q[price_gteq]=10000&q[price_lteq]=50000" \
  -H "Accept: application/json"
bash
curl -X GET "https://your-company.erpax.com/admin/items.json?scope=in_stock&q[currency_code_eq]=USD" \
  -H "Accept: application/json"

JavaScript Example:

javascript
const response = await fetch('/admin/items.json', {
  credentials: 'include',
  headers: { 'Accept': 'application/json' }
});
const data = await response.json();

Response (200 OK):

json
{
  "items": [
    {
      "id": 1,
      "code": "PROD-001",
      "name": "Widget A",
      "description": "High-quality widget",
      "price_cents": 10000,
      "price": "100.00",
      "cost_cents": 5000,
      "currency_code": "USD",
      "inventory_quantity": 100,
      "tax_rate": 0.1,
      "tax_type": "vat",
      "created_at": "2024-01-10T10:00:00Z"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 50,
    "total_pages": 5,
    "total_count": 234
  }
}

Show Item (GET /:id)

Endpoint: GET /admin/items/:id.json

Request Example:

bash
curl -X GET "https://your-company.erpax.com/admin/items/1.json" \
  -H "Accept: application/json" \
  -H "Cookie: session_cookie"

JavaScript Example:

javascript
const response = await fetch('/admin/items/1.json', {
  credentials: 'include',
  headers: { 'Accept': 'application/json' }
});
const item = await response.json();

Response (200 OK):

json
{
  "item": {
    "id": 1,
    "code": "PROD-001",
    "name": "Widget A",
    "description": "High-quality widget",
    "price_cents": 10000,
    "price": "100.00",
    "cost_cents": 5000,
    "vendor_price_cents": 6000,
    "currency_code": "USD",
    "inventory_quantity": 100,
    "inventory_policy": "continue",
    "tax_rate": 0.1,
    "tax_type": "vat",
    "unit": "piece",
    "address_id": 1,
    "debit_account_id": 10,
    "credit_account_id": 20,
    "created_at": "2024-01-10T10:00:00Z",
    "updated_at": "2024-01-15T12:00:00Z"
  }
}

Create Item (POST)

Endpoint: POST /admin/items.json

Request Example:

bash
curl -X POST "https://your-company.erpax.com/admin/items.json" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Cookie: session_cookie" \
  -d '{
    "item": {
      "code": "PROD-002",
      "name": "Widget B",
      "description": "Premium widget",
      "price_cents": 20000,
      "cost_cents": 10000,
      "currency_code": "USD",
      "inventory_quantity": 50,
      "tax_rate": 0.1,
      "tax_type": "vat",
      "unit": "piece",
      "address_id": 1
    }
  }'

JavaScript Example:

javascript
const response = await fetch('/admin/items.json', {
  method: 'POST',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    item: {
      code: 'PROD-002',
      name: 'Widget B',
      description: 'Premium widget',
      price_cents: 20000,
      cost_cents: 10000,
      currency_code: 'USD',
      inventory_quantity: 50,
      tax_rate: 0.1,
      tax_type: 'vat',
      unit: 'piece',
      address_id: 1
    }
  })
});
const item = await response.json();

Response (201 Created):

json
{
  "item": {
    "id": 2,
    "code": "PROD-002",
    "name": "Widget B",
    "price_cents": 20000,
    "inventory_quantity": 50,
    "created_at": "2024-01-15T14:30:00Z"
  }
}

Response (422 Unprocessable Entity):

json
{
  "errors": {
    "code": ["has already been taken"],
    "name": ["can't be blank"]
  }
}

Update Item (PATCH /:id)

Endpoint: PATCH /admin/items/:id.json

Request Example:

bash
curl -X PATCH "https://your-company.erpax.com/admin/items/1.json" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Cookie: session_cookie" \
  -d '{
    "item": {
      "price_cents": 12000,
      "inventory_quantity": 95
    }
  }'

JavaScript Example:

javascript
const response = await fetch('/admin/items/1.json', {
  method: 'PATCH',
  credentials: 'include',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  },
  body: JSON.stringify({
    item: {
      price_cents: 12000,
      inventory_quantity: 95
    }
  })
});
const item = await response.json();

Response (200 OK):

json
{
  "item": {
    "id": 1,
    "price_cents": 12000,
    "inventory_quantity": 95,
    "updated_at": "2024-01-15T15:00:00Z"
  }
}

Delete Item (DELETE /:id)

Endpoint: DELETE /admin/items/:id.json

Request Example:

bash
curl -X DELETE "https://your-company.erpax.com/admin/items/1.json" \
  -H "Accept: application/json" \
  -H "Cookie: session_cookie"

JavaScript Example:

javascript
const response = await fetch('/admin/items/1.json', {
  method: 'DELETE',
  credentials: 'include',
  headers: { 'Accept': 'application/json' }
});

Response (204 No Content):

(empty response)

Response (422 Unprocessable Entity):

json
{
  "error": "Cannot delete item with associated invoice lines"
}

Batch Actions

Endpoint: POST /admin/items/batch_action.json

Available batch actions:

  • update - Update selected items with batch form fields

Request Example:

bash
curl -X POST "https://your-company.erpax.com/admin/items/batch_action.json" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Cookie: session_cookie" \
  -d '{
    "batch_action": "update",
    "collection_selection": [1, 2, 3],
    "item": {
      "tax_rate": 0.2
    }
  }
  }'

Scopes

  • all (default) - All items
  • drafts - Draft items
  • free - Free items (price is 0 or nil)
  • tax_free - Items with no tax
  • losing - Items where price is less than cost
  • earning - Items where price is greater than cost
  • in_stock - Items with inventory_quantity > 0
  • out_of_stock - Items with inventory_quantity <= 0

Usage Example:

bash
GET /admin/items.json?scope=in_stock
GET /admin/items.json?scope=out_of_stock
GET /admin/items.json?scope=drafts

Filters

Available filters for searching and filtering items:

  • code_or_name_or_description_cont - Text filter (autofocus) - Search by code, name, or description (contains)
  • product - Select filter - Filter by product
  • address - Select filter - Filter by address
  • code - Text filter - Filter by item code
  • barcode - Text filter - Filter by barcode
  • name_cont - Text filter - Search by name (contains)
  • description_cont - Text filter - Search by description (contains)
  • unit - Text filter - Filter by unit
  • period - Text filter - Filter by period
  • currency_code - Select filter (multiple) - Filter by currency code
  • price - Numeric range filter - Filter by price range
  • cost - Numeric range filter - Filter by cost range
  • vendor_price - Numeric range filter - Filter by vendor price range
  • tax_rate - Numeric range filter - Filter by tax rate range
  • tax_type - Select filter (multiple) - Filter by tax type
  • inventory_quantity - Numeric range filter - Filter by inventory quantity range
  • inventory_policy - Select filter - Filter by inventory policy
  • visibility - Select filter (multiple) - Filter by visibility level
  • domain - Select filter (multiple) - Filter by domain
  • tag - Select filter (multiple) - Filter by tags
  • debit_account - Filter by debit account
  • credit_account - Filter by credit account
  • created_at - Date filter - Filter by creation date
  • updated_at - Date filter - Filter by update date

Filtering Examples:

bash
# Search by name or code
GET /admin/items.json?q[code_or_name_cont]=Widget

# Filter by price range
GET /admin/items.json?q[price_gteq]=10000&q[price_lteq]=50000

# Filter by inventory
GET /admin/items.json?q[inventory_quantity_gt]=0
GET /admin/items.json?scope=in_stock
GET /admin/items.json?scope=out_of_stock

# Filter by currency and tax
GET /admin/items.json?q[currency_code_eq]=USD&q[tax_type_eq]=vat

Business Rules

  • Code Uniqueness: Item codes must be unique within a domain
  • Inventory Tracking: Inventory quantity is automatically updated when items are used in invoice lines
  • Price Validation: Price must be greater than or equal to cost (unless configured otherwise)
  • Domain Scoping: Items are automatically scoped to the current domain
  • Accounting Integration: Accounting accounts are automatically assigned based on item configuration

Nested Resources

Items can be nested under addresses:

  • Invoices - Items are used in invoice lines
  • Addresses - Items can be associated with addresses
  • Catalog - Product catalog management including products, properties, property types, and product-property associations

Released under an open source license.