Skip to content

Sales Dashboard Report Documentation

Overview

The Sales Dashboard Report module (report.sale) provides comprehensive sales analytics and business intelligence dashboards for the sales management system. This is the master dashboard report that aggregates multiple metrics including sales trends, customer analytics, product performance, opportunity tracking, and revenue forecasting. It serves as the central reporting hub for sales executives and managers.


Model Information

Model Name: report.sale Display Name: Sales Dashboard Report Type: Non-Stored Report Model

Features

  • ❌ Not stored in database (_store = False)
  • ❌ No persistent fields (dashboard data generated on-demand)
  • ✅ Real-time analytics and KPI calculations
  • ✅ Multiple dashboard widgets and visualizations
  • ✅ Historical trend analysis with time series data
  • ✅ Interactive drill-down capabilities

Report Purpose

Business Questions Answered

The Sales Dashboard Report provides insights to answer:

  1. Sales Performance: How are sales trending month-over-month?
  2. Product Analysis: Which products and categories are top sellers?
  3. Customer Insights: Who are the top revenue-generating customers?
  4. Pipeline Management: What is the value of opportunities by stage?
  5. Revenue Forecasting: What is the expected revenue for upcoming periods?
  6. Customer Acquisition: How many new customers were acquired?
  7. Conversion Metrics: What is the lead-to-customer conversion rate?

Key Metrics Calculated

  • Monthly Sales Volume: Total sales amount per month (last 6 months)
  • Sales Per Product: Revenue by product (top 5 + others)
  • Sales Per Product Category: Revenue by category (top 5 + others)
  • Sales Per Customer: Revenue by customer (top 5 + others)
  • Opportunity Pipeline Value: Expected revenue by sales stage
  • Expected Revenue Forecast: Projected revenue for next 6 months
  • New Customer Count: Number of new customers acquired
  • New Customer Sales: Total revenue from new customers
  • Lead Conversion Rate: Percentage of leads converted to customers
  • Daily Sales Cumulative: Day-by-day cumulative sales comparison

Report Methods

1. Sales Per Month

Method: sales_per_month(context={})

Analyzes sales trends over the past 6 months, showing confirmed and completed orders.

Data Source:

# Query: sale_order table, aggregated by month
# States: 'confirmed', 'done'
# Period: Last 6 months from today

Returns: list - List of tuples (month_name, amount)

Example Output:

[
    ("October", 150000.00),
    ("November", 175000.00),
    ("December", 200000.00),
    ("January", 165000.00),
    ("February", 180000.00),
    ("March", 210000.00)
]

Usage:

# Get monthly sales trend
data = get_model("report.sale").sales_per_month()

# Result: [("October", 150000.00), ("November", 175000.00), ...]

SQL Query:

SELECT to_char(date,'YYYY-MM') AS month,
       SUM(amount_total_cur) as amount
FROM sale_order
WHERE state IN ('confirmed','done')
GROUP BY month


2. Sales Per Product

Method: sales_per_product(context={})

Identifies top-selling products by revenue, showing the top 5 products individually and grouping the rest as "Other".

Data Source:

# Query: sale_order_line + sale_order + product
# States: 'confirmed', 'done'
# Aggregation: Sum of line amounts by product

Returns: list - List of tuples (product_name, amount)

Example Output:

[
    ("Premium Widget", 45000.00),
    ("Standard Widget", 32000.00),
    ("Deluxe Package", 28000.00),
    ("Basic Service", 21000.00),
    ("Pro Service", 18000.00),
    ("Other", 56000.00)  # Sum of all other products
]

Usage:

# Get product performance
products = get_model("report.sale").sales_per_product()

# Display in pie chart or bar graph

SQL Query:

SELECT p.name, SUM(l.amount_cur) as amount
FROM sale_order_line l
JOIN sale_order o ON o.id=l.order_id
JOIN product p ON p.id=l.product_id
WHERE o.state IN ('confirmed','done')
GROUP BY p.name
ORDER BY amount DESC


3. Sales Per Product Category

Method: sales_per_product_categ(context={}, month={})

Analyzes sales by product category for a specific month or current month.

Parameters: - month (str): Date string in YYYY-MM-DD format (defaults to current month)

Returns: list - List of tuples (category_name, amount)

Example Output:

[
    ("Electronics", 85000.00),
    ("Software", 62000.00),
    ("Services", 43000.00),
    ("Hardware", 28000.00),
    ("Accessories", 15000.00),
    ("Other", 32000.00)
]

Usage:

# Get current month category sales
categories = get_model("report.sale").sales_per_product_categ()

# Get specific month
categories = get_model("report.sale").sales_per_product_categ(
    month="2026-01-01"
)

SQL Query:

SELECT c.name, SUM(l.amount_cur) as amount
FROM sale_order_line l
JOIN sale_order o ON o.id=l.order_id
JOIN product p ON p.id=l.product_id
JOIN product_categ c ON c.id=p.categ_id
WHERE o.create_time >= '{start_date}'
  AND o.create_time <= '{end_date}'
  AND o.state IN ('confirmed','done')
GROUP BY c.name
ORDER BY amount DESC


4. Sales Per Customer

Method: sales_per_customer(context={})

Identifies top customers by revenue, showing the top 5 customers and grouping others.

Data Source:

# Query: sale_order + contact
# States: 'confirmed', 'done'
# Aggregation: Sum of order totals by customer

Returns: list - List of tuples (customer_name, amount)

Example Output:

[
    ("ABC Corporation", 125000.00),
    ("XYZ Industries", 98000.00),
    ("Tech Solutions Inc", 75000.00),
    ("Global Enterprises", 62000.00),
    ("Smart Systems Ltd", 48000.00),
    ("Other", 192000.00)
]

Usage:

# Get top customers
customers = get_model("report.sale").sales_per_customer()

# Use for customer segmentation analysis

SQL Query:

SELECT c.name, SUM(o.amount_total) as amount
FROM sale_order o
JOIN contact c ON c.id=o.contact_id
WHERE o.state IN ('confirmed','done')
GROUP BY c.name
ORDER BY amount DESC


5. Opportunity Stage Analysis

Method: opport_stage(context={})

Analyzes sales opportunities by stage, calculating weighted value based on probability.

Data Source:

# Query: sale_opportunity + sale_stage
# States: 'open', 'won'
# Calculation: amount * probability / 100

Returns: list - List of tuples (stage_name, weighted_amount)

Example Output:

[
    ("Lead", 15000.00),          # 50 opps × 30% probability
    ("Qualified", 42000.00),     # 35 opps × 60% probability
    ("Proposal", 68000.00),      # 20 opps × 80% probability
    ("Negotiation", 85000.00),   # 15 opps × 90% probability
    ("Won", 120000.00)           # 12 opps × 100%
]

Usage:

# Get opportunity pipeline value
pipeline = get_model("report.sale").opport_stage()

# Display in funnel chart

SQL Query:

SELECT s.name,
       SUM(o.amount*o.probability/100) AS amount,
       COUNT(*) AS num
FROM sale_opportunity o
JOIN sale_stage s ON s.id=o.stage_id
WHERE o.state IN ('open','won')
GROUP BY s.name


6. Expected Revenue Forecast

Method: expected_revenue(context={})

Projects expected revenue for the next 6 months based on opportunity close dates and probabilities.

Data Source:

# Query: sale_opportunity
# States: 'open', 'won'
# Period: Next 6 months + future
# Calculation: amount * probability / 100

Returns: list - List of tuples (month_abbrev, projected_amount)

Example Output:

[
    ("Jan", 145000.00),
    ("Feb", 132000.00),
    ("Mar", 168000.00),
    ("Apr", 155000.00),
    ("May", 178000.00),
    ("Jun", 162000.00),
    ("Future", 245000.00)  # Beyond 6 months
]

Usage:

# Get revenue forecast
forecast = get_model("report.sale").expected_revenue()

# Use for budgeting and capacity planning

SQL Query:

SELECT date_trunc('month',o.date_close) AS month,
       SUM(o.amount*o.probability/100),
       COUNT(*)
FROM sale_opportunity o
WHERE o.state IN ('open','won')
GROUP BY month


7. Sales Per Day (Cumulative)

Method: get_sales_per_day(context={}, month={})

Compares cumulative daily sales for current month vs previous month.

Parameters: - month (str): Date string in YYYY-MM-DD format for the month to analyze

Returns: list - List of series dictionaries for charting

Example Output:

[
    {
        "name": "This Month",
        "data": [[1, 5000], [2, 12000], [3, 18000], ..., [15, 185000]],
        "color": "blue"
    },
    {
        "name": "Previous Month",
        "data": [[1, 4500], [2, 10000], [3, 15500], ..., [15, 165000]],
        "color": "orange"
    }
]

Usage:

# Get daily sales comparison
daily_sales = get_model("report.sale").get_sales_per_day(
    month="2026-01-01"
)

# Display in line chart to show growth trends

Behavior: - Calculates cumulative total day by day - Compares same day-of-month between periods - Returns data suitable for line chart visualization - Useful for identifying sales acceleration or deceleration


8. New Customer Acquisition

Method: get_new_customer(context={}, month={})

Counts new customers acquired in a specific month.

Parameters: - month (str): Date string in YYYY-MM-DD format (defaults to current month)

Returns: list - List with single metric dictionary

Example Output:

[
    {
        "name": "New Customer",
        "data": 23,
        "color": "blue"
    }
]

Usage:

# Get new customers this month
new_customers = get_model("report.sale").get_new_customer()

# Get new customers for specific month
new_customers = get_model("report.sale").get_new_customer(
    month="2026-01-01"
)

# Result: [{"name": "New Customer", "data": 23, "color": "blue"}]

SQL Query:

SELECT * FROM contact
WHERE create_time >= '{month_start}'
  AND create_time <= '{month_end}'


9. New Customer Sales

Method: get_sale_new_customer(context={}, month={})

Calculates total sales from customers acquired in a specific month.

Parameters: - month (str): Date string in YYYY-MM-DD format (defaults to current month)

Returns: list - List with single metric dictionary

Example Output:

[
    {
        "name": "New Customer Sale",
        "data": 45600.00,
        "color": "blue"
    }
]

Usage:

# Get sales from new customers this month
new_cust_sales = get_model("report.sale").get_sale_new_customer()

# Get sales from specific month's new customers
new_cust_sales = get_model("report.sale").get_sale_new_customer(
    month="2026-01-01"
)

Behavior: - Identifies customers created in specified month - Sums all their sales orders (all time, not just that month) - Useful for measuring customer acquisition quality - Helps calculate customer lifetime value for cohorts


10. Lead Conversion Rate

Method: get_conversion(context={}, month={})

Calculates the lead-to-customer conversion rate over the last 12 months.

Parameters: - month (str): End date for 12-month lookback period

Returns: list - List with single metric dictionary

Example Output:

[
    {
        "name": "Last 12 month conversion",
        "data": 34.57,  # Percentage
        "color": "blue"
    }
]

Usage:

# Get conversion rate
conversion = get_model("report.sale").get_conversion()

# Result: [{"name": "Last 12 month conversion", "data": 34.57, ...}]

Calculation:

# Conversion % = (new_leads / new_customers) * 100
# Rounded to 2 decimal places

Business Insight: - Higher percentage indicates better lead quality - Lower percentage may indicate need for lead qualification improvements - Benchmark against industry standards


11. Monthly Sales Total

Method: monthly_sale(context={}, month={})

Calculates total sales for a specific month.

Parameters: - month (str): Date string in YYYY-MM-DD format (defaults to current month)

Returns: list - List with single metric dictionary

Example Output:

[
    {
        "name": "Monthly Sale",
        "data": 215600.00,
        "color": "blue"
    }
]

Usage:

# Get current month sales
monthly_total = get_model("report.sale").monthly_sale()

# Get specific month sales
monthly_total = get_model("report.sale").monthly_sale(
    month="2026-01-01"
)

SQL Query:

SELECT SUM(amount_total_cur) as amount
FROM sale_order
WHERE create_time >= '{month_start}'
  AND create_time <= '{month_end}'


Helper Functions

get_past_months(num_months)

Purpose: Generates list of past month/year tuples for time series analysis.

Parameters: - num_months (int): Number of months to generate

Returns: list - Reversed list of (year, month) tuples

Example:

# Called in January 2026
result = get_past_months(6)
# Returns: [(2025, 8), (2025, 9), (2025, 10), (2025, 11), (2025, 12), (2026, 1)]


get_future_months(num_months)

Purpose: Generates list of future month/year tuples for forecasting.

Parameters: - num_months (int): Number of months to generate

Returns: list - List of (year, month) tuples

Example:

# Called in January 2026
result = get_future_months(6)
# Returns: [(2026, 1), (2026, 2), (2026, 3), (2026, 4), (2026, 5), (2026, 6)]


Data Sources

Primary Models Queried

Model Usage Join Keys
sale.order Main sales transactions id
sale.order.line Product-level detail order_idsale.order.id
product Product information idsale.order.line.product_id
product.categ Product categories idproduct.categ_id
contact Customer information idsale.order.contact_id
sale.opportunity Sales pipeline id
sale.stage Opportunity stages idsale.opportunity.stage_id
sale.lead Lead tracking id

Dashboard Visualizations

  1. Monthly Sales Trend
  2. Type: Line Chart
  3. Data: sales_per_month()
  4. Purpose: Show sales trajectory over time

  5. Product Performance

  6. Type: Pie Chart or Bar Chart
  7. Data: sales_per_product()
  8. Purpose: Identify best-selling products

  9. Category Analysis

  10. Type: Donut Chart
  11. Data: sales_per_product_categ()
  12. Purpose: Category revenue distribution

  13. Top Customers

  14. Type: Horizontal Bar Chart
  15. Data: sales_per_customer()
  16. Purpose: Customer segmentation

  17. Sales Funnel

  18. Type: Funnel Chart
  19. Data: opport_stage()
  20. Purpose: Pipeline visualization

  21. Revenue Forecast

  22. Type: Column Chart
  23. Data: expected_revenue()
  24. Purpose: Future revenue projection

  25. Daily Sales Comparison

  26. Type: Multi-Line Chart
  27. Data: get_sales_per_day()
  28. Purpose: Period-over-period comparison

  29. KPI Metrics

  30. Type: Metric Cards
  31. Data: monthly_sale(), get_new_customer(), get_conversion()
  32. Purpose: Key performance indicators

Common Use Cases

Use Case 1: Executive Sales Dashboard

# Generate comprehensive executive dashboard

# 1. Get monthly sales trend (6 months)
monthly_trend = get_model("report.sale").sales_per_month()

# 2. Get current month metrics
current_month = date.today().strftime("%Y-%m-01")
monthly_total = get_model("report.sale").monthly_sale(month=current_month)
new_customers = get_model("report.sale").get_new_customer(month=current_month)
new_cust_revenue = get_model("report.sale").get_sale_new_customer(month=current_month)

# 3. Get product and customer insights
top_products = get_model("report.sale").sales_per_product()
top_customers = get_model("report.sale").sales_per_customer()

# 4. Get pipeline and forecast
pipeline = get_model("report.sale").opport_stage()
forecast = get_model("report.sale").expected_revenue()

# 5. Get conversion metrics
conversion_rate = get_model("report.sale").get_conversion()

# Display all in unified dashboard
dashboard_data = {
    "kpis": {
        "monthly_sales": monthly_total[0]["data"],
        "new_customers": new_customers[0]["data"],
        "new_customer_revenue": new_cust_revenue[0]["data"],
        "conversion_rate": conversion_rate[0]["data"]
    },
    "trends": {
        "monthly": monthly_trend,
        "products": top_products,
        "customers": top_customers
    },
    "pipeline": {
        "stages": pipeline,
        "forecast": forecast
    }
}

Use Case 2: Month-over-Month Performance Analysis

# Compare current month with previous month

from datetime import date
from dateutil.relativedelta import relativedelta

# Current month
current_month = date.today().strftime("%Y-%m-01")
current_sales = get_model("report.sale").monthly_sale(month=current_month)
current_customers = get_model("report.sale").get_new_customer(month=current_month)

# Previous month
prev_month_date = date.today() - relativedelta(months=1)
prev_month = prev_month_date.strftime("%Y-%m-01")
prev_sales = get_model("report.sale").monthly_sale(month=prev_month)
prev_customers = get_model("report.sale").get_new_customer(month=prev_month)

# Calculate growth
sales_growth = ((current_sales[0]["data"] - prev_sales[0]["data"])
                / prev_sales[0]["data"] * 100)
customer_growth = ((current_customers[0]["data"] - prev_customers[0]["data"])
                   / prev_customers[0]["data"] * 100)

print(f"Sales Growth: {sales_growth:.2f}%")
print(f"Customer Growth: {customer_growth:.2f}%")

# Get daily comparison for detailed analysis
daily_comparison = get_model("report.sale").get_sales_per_day(month=current_month)

Use Case 3: Product Category Performance Review

# Analyze product category performance for current month

current_month = date.today().strftime("%Y-%m-01")

# Get category sales for current month
category_sales = get_model("report.sale").sales_per_product_categ(
    month=current_month
)

# Get product-level detail
product_sales = get_model("report.sale").sales_per_product()

# Calculate category metrics
total_sales = sum(amount for _, amount in category_sales)

category_analysis = []
for category_name, amount in category_sales:
    percentage = (amount / total_sales * 100) if total_sales > 0 else 0
    category_analysis.append({
        "category": category_name,
        "revenue": amount,
        "percentage": percentage
    })

# Display sorted by revenue
for cat in sorted(category_analysis, key=lambda x: x["revenue"], reverse=True):
    print(f"{cat['category']}: ${cat['revenue']:,.2f} ({cat['percentage']:.1f}%)")

Use Case 4: Sales Pipeline Health Check

# Analyze sales pipeline health and conversion

# Get opportunity distribution by stage
pipeline = get_model("report.sale").opport_stage()

# Get expected revenue forecast
forecast = get_model("report.sale").expected_revenue()

# Calculate pipeline metrics
total_pipeline_value = sum(amount for _, amount in pipeline)
next_month_forecast = forecast[0][1] if forecast else 0

# Calculate coverage ratio
current_month_sales = get_model("report.sale").monthly_sale()
current_sales_amount = current_month_sales[0]["data"]

pipeline_coverage = (total_pipeline_value / current_sales_amount
                     if current_sales_amount > 0 else 0)

print(f"Total Pipeline Value: ${total_pipeline_value:,.2f}")
print(f"Current Month Sales: ${current_sales_amount:,.2f}")
print(f"Pipeline Coverage Ratio: {pipeline_coverage:.2f}x")
print(f"Next Month Forecast: ${next_month_forecast:,.2f}")

# Alert if pipeline coverage is low
if pipeline_coverage < 3.0:
    print("⚠️ WARNING: Pipeline coverage below 3x threshold!")

Use Case 5: Customer Acquisition Analysis

# Analyze customer acquisition effectiveness

current_month = date.today().strftime("%Y-%m-01")

# Get new customer metrics
new_customers = get_model("report.sale").get_new_customer(month=current_month)
new_customer_sales = get_model("report.sale").get_sale_new_customer(month=current_month)

# Get conversion rate
conversion_data = get_model("report.sale").get_conversion()

# Calculate average revenue per new customer
num_new_customers = new_customers[0]["data"]
total_new_cust_sales = new_customer_sales[0]["data"]

avg_revenue_per_new_customer = (total_new_cust_sales / num_new_customers
                                 if num_new_customers > 0 else 0)

conversion_rate = conversion_data[0]["data"]

print(f"New Customers Acquired: {num_new_customers}")
print(f"Revenue from New Customers: ${total_new_cust_sales:,.2f}")
print(f"Average Revenue per New Customer: ${avg_revenue_per_new_customer:,.2f}")
print(f"Lead Conversion Rate: {conversion_rate:.2f}%")

# Calculate customer acquisition cost effectiveness
# (Assuming marketing spend is tracked separately)
marketing_spend = 15000  # Example
cost_per_acquisition = marketing_spend / num_new_customers if num_new_customers > 0 else 0
customer_lifetime_value_ratio = avg_revenue_per_new_customer / cost_per_acquisition

print(f"Cost per Acquisition: ${cost_per_acquisition:,.2f}")
print(f"CLV/CAC Ratio: {customer_lifetime_value_ratio:.2f}x")

Performance Tips

1. Optimize Date Range Queries

# Bad: Querying all time then filtering in Python
all_orders = get_model("sale.order").search_browse([])
recent_orders = [o for o in all_orders if o.date >= start_date]

# Good: Filter at database level (done by report methods)
# The report methods already apply date filters in SQL
monthly_sales = get_model("report.sale").monthly_sale(month="2026-01-01")

2. Cache Dashboard Data

# For frequently accessed dashboards, cache the results

from functools import lru_cache
from datetime import datetime

@lru_cache(maxsize=128)
def get_cached_dashboard(date_key):
    """Cache dashboard data for 1 hour"""
    return {
        "monthly_sales": get_model("report.sale").monthly_sale(),
        "top_products": get_model("report.sale").sales_per_product(),
        "top_customers": get_model("report.sale").sales_per_customer(),
        "timestamp": datetime.now()
    }

# Use with hourly cache key
cache_key = datetime.now().strftime("%Y-%m-%d-%H")
dashboard = get_cached_dashboard(cache_key)

3. Batch Multiple Report Calls

# When generating comprehensive reports, batch data retrieval

def get_full_dashboard_data(month=None):
    """Get all dashboard data in one function to minimize overhead"""

    if month is None:
        month = date.today().strftime("%Y-%m-01")

    report_model = get_model("report.sale")

    # Fetch all data
    data = {
        "monthly_trend": report_model.sales_per_month(),
        "monthly_total": report_model.monthly_sale(month=month),
        "products": report_model.sales_per_product(),
        "categories": report_model.sales_per_product_categ(month=month),
        "customers": report_model.sales_per_customer(),
        "pipeline": report_model.opport_stage(),
        "forecast": report_model.expected_revenue(),
        "new_customers": report_model.get_new_customer(month=month),
        "new_cust_sales": report_model.get_sale_new_customer(month=month),
        "conversion": report_model.get_conversion(),
        "daily_comparison": report_model.get_sales_per_day(month=month)
    }

    return data

# Single call gets all dashboard data
dashboard = get_full_dashboard_data()

Model Relationship Description
sale.order Data Source Main transaction records queried for sales metrics
sale.order.line Data Source Line-level product sales data
product Data Source Product information for analytics
product.categ Data Source Product categorization
contact Data Source Customer information
sale.opportunity Data Source Sales pipeline and forecast data
sale.stage Data Source Opportunity stage definitions
sale.lead Data Source Lead tracking for conversion metrics
report.sale.order Related Report Detailed product sales report
report.sale.profit Related Report Profitability analysis report
report.sale.commission Related Report Commission calculations

Best Practices

1. Use Appropriate Time Periods

# Bad: Requesting data without time boundaries
all_time_data = get_model("report.sale").sales_per_product()  # Could be slow

# Good: Use time-bounded methods or specify periods
monthly_data = get_model("report.sale").sales_per_product_categ(
    month="2026-01-01"
)

# For custom periods, query sale.order directly with filters
cond = [
    ["date", ">=", "2026-01-01"],
    ["date", "<=", "2026-03-31"],
    ["state", "in", ["confirmed", "done"]]
]
quarterly_orders = get_model("sale.order").search_browse(cond)

2. Interpret "Other" Category Correctly

# The "Other" category aggregates items beyond top 5
# To see detail, query the data source directly

products = get_model("report.sale").sales_per_product()

# To see all products (not just top 5):
cond = [["order_id.state", "in", ["confirmed", "done"]]]
all_lines = get_model("sale.order.line").search_browse(cond)

product_sales = {}
for line in all_lines:
    prod_name = line.product_id.name if line.product_id else "Unknown"
    product_sales.setdefault(prod_name, 0)
    product_sales[prod_name] += line.amount_cur or 0

# Sort and display all
for prod, amt in sorted(product_sales.items(), key=lambda x: x[1], reverse=True):
    print(f"{prod}: ${amt:,.2f}")

3. Validate Data Consistency

# Cross-check dashboard totals against source data

# Get monthly total from dashboard
dashboard_total = get_model("report.sale").monthly_sale(month="2026-01-01")

# Verify against direct query
cond = [
    ["create_time", ">=", "2026-01-01 00:00:00"],
    ["create_time", "<=", "2026-01-31 23:59:59"]
]
orders = get_model("sale.order").search_browse(cond)
actual_total = sum(o.amount_total_cur for o in orders)

# Compare
dashboard_amt = dashboard_total[0]["data"]
difference = abs(dashboard_amt - actual_total)

if difference > 0.01:  # Allow for rounding
    print(f"⚠️ Data inconsistency detected!")
    print(f"Dashboard: ${dashboard_amt:,.2f}")
    print(f"Actual: ${actual_total:,.2f}")

Troubleshooting

"No data returned for sales_per_day"

Cause: The month parameter is not provided, and there's a return statement when month is None.

Solution: Always provide the month parameter:

# Bad
daily_sales = get_model("report.sale").get_sales_per_day()  # Returns None

# Good
daily_sales = get_model("report.sale").get_sales_per_day(
    month=date.today().strftime("%Y-%m-01")
)

"Division by zero in conversion calculation"

Cause: No customers exist in the 12-month period, causing division by zero.

Solution: The model handles this internally, but you should validate:

conversion = get_model("report.sale").get_conversion()

if conversion and conversion[0]["data"] > 0:
    rate = conversion[0]["data"]
else:
    rate = 0.0
    print("No conversion data available")

"Unexpected data format from report method"

Cause: Different methods return different data structures (list of tuples vs list of dicts).

Solution: Check the return type for each method:

# Returns list of tuples
monthly_sales = get_model("report.sale").sales_per_month()
# Usage: for month_name, amount in monthly_sales:

# Returns list of dicts
monthly_total = get_model("report.sale").monthly_sale()
# Usage: monthly_total[0]["data"]


Integration Points

Dashboard Integration

Display dashboard data in web UI:

# In controller/view
def get_sales_dashboard(request):
    report = get_model("report.sale")

    data = {
        "monthly_sales": report.monthly_sale(),
        "new_customers": report.get_new_customer(),
        "top_products": report.sales_per_product(),
        "pipeline": report.opport_stage()
    }

    return render("sales_dashboard.html", data)

Export to Excel

import xlsxwriter

def export_dashboard_to_excel(filename):
    workbook = xlsxwriter.Workbook(filename)

    # Monthly sales sheet
    ws_monthly = workbook.add_worksheet("Monthly Sales")
    monthly_data = get_model("report.sale").sales_per_month()

    ws_monthly.write(0, 0, "Month")
    ws_monthly.write(0, 1, "Amount")

    for idx, (month, amount) in enumerate(monthly_data, start=1):
        ws_monthly.write(idx, 0, month)
        ws_monthly.write(idx, 1, amount)

    # Products sheet
    ws_products = workbook.add_worksheet("Top Products")
    product_data = get_model("report.sale").sales_per_product()

    ws_products.write(0, 0, "Product")
    ws_products.write(0, 1, "Amount")

    for idx, (product, amount) in enumerate(product_data, start=1):
        ws_products.write(idx, 0, product)
        ws_products.write(idx, 1, amount)

    workbook.close()

# Export dashboard
export_dashboard_to_excel("sales_dashboard.xlsx")

Version History

Last Updated: 2026-01-05 Model Version: report_sale.py Framework: Netforce


Additional Resources

  • Sales Order Documentation: sale.order
  • Opportunity Management Documentation: sale.opportunity
  • Product Analytics: report.sale.order
  • Profit Analysis: report.sale.profit
  • Commission Reports: report.sale.commission

Support & Feedback

For issues or questions about this module: 1. Verify sale orders have correct states ('confirmed' or 'done') 2. Check date ranges are properly formatted (YYYY-MM-DD) 3. Ensure products and customers are properly linked 4. Review database query logs for performance issues


This documentation is generated for developer onboarding and reference purposes.