Overview
Spree’s reporting system is designed for extension. Each report is a pair of classes — a Report that defines the data query and a ReportLineItem that formats each row — registered inSpree.reports so it appears in the admin UI.
This guide walks you through building a custom report from scratch, including advanced patterns for SQL aggregations and multi-vendor support.
Before starting, make sure you understand how the reporting system works.
Creating a Custom Report
Step 1: Create the Report Class
Create a new report class inheriting fromSpree::Report. The key method to implement is line_items_scope, which returns an ActiveRecord::Relation defining the records in your report:
app/models/spree/reports/customer_orders.rb
line_items_scope method has access to:
| Helper | Description |
|---|---|
store | The current store |
date_from | Report start date |
date_to | Report end date |
currency | Report currency |
vendor | Vendor (if multi-vendor is enabled) |
Step 2: Create the Line Item Class
Create a corresponding line item class that transforms each record into report columns. The class name must match the report class name (e.g.,Reports::CustomerOrders → ReportLineItems::CustomerOrders):
app/models/spree/report_line_items/customer_orders.rb
- Use
attributeto define columns with their types — these become CSV headers - Each attribute needs a corresponding method that extracts/formats data from
record recordis a single item fromline_items_scope- Use
Spree::Moneyfor currency formatting currencyandstoreare delegated from the report
Available Base Class Methods
Spree::ReportLineItem provides:
Step 3: Register the Report
Add your report to the registry in an initializer:config/initializers/spree.rb
Step 4: Add Translations
Add the report name and column header translations:config/locales/en.yml
Advanced Patterns
Complex Queries with Aggregations
For reports that aggregate data across records, use SQL directly inline_items_scope:
app/models/spree/reports/revenue_by_category.rb
record in your line item class will have virtual attributes (like total_quantity, total_revenue) available as methods.
Custom Summary Section
Overridesummary to provide aggregate metrics alongside the line items:
app/models/spree/reports/customer_orders.rb
Multi-Vendor Support
If you’re using Spree Multi-Vendor, filter by vendor when one is selected:app/models/spree/reports/vendor_sales.rb
Testing Custom Reports
Testing the Report Class
Test that your report’sline_items_scope returns the correct records:
spec/models/spree/reports/customer_orders_spec.rb
Testing the ReportLineItem Class
Test that your line item correctly formats each record:spec/models/spree/report_line_items/customer_orders_spec.rb
Key Testing Patterns
- Test scope filtering — verify
line_items_scopereturns only records matching date range, currency, and store - Test attribute formatting — verify each attribute method returns correctly formatted data
- Test CSV output — check
headers,csv_headers, andto_csvreturn expected values - Test edge cases — handle nil values gracefully (e.g., missing addresses)

