Skip to content

Generate Sale Report Documentation

Overview

The Generate Sale Report module (gen.sale.report) is a utility wizard for batch report generation. It triggers the gen_report method on the sale.order model to generate reports from a specific start date, useful for scheduled report generation or batch processing.


Model Information

Model Name: gen.sale.report Display Name: Generate Sale Report Type: Transient Wizard Model (_transient = True)

Features

  • Single-field wizard for report generation
  • Triggers batch report generation on sale orders
  • Useful for scheduled/automated reporting
  • Date-based report generation
  • Simple interface for bulk operations

Key Fields Reference

Wizard Parameters

Field Type Required Default Description
date_from Date Yes First day of month Start date for report generation

API Methods

1. Generate Report

Method: gen_report(ids, context)

Triggers report generation on sale.order model from specified date.

Parameters:

ids = [wizard_id]  # Wizard instance ID
context = {}       # Optional context

Behavior: - Reads date_from from wizard record - Calls get_model("sale.order").gen_report(date_from) - Delegates actual report logic to sale.order model

Example:

# Generate reports for all orders from January 1st

wizard_id = get_model("gen.sale.report").create({
    "date_from": "2024-01-01"
})

get_model("gen.sale.report").gen_report([wizard_id])

print("Report generation triggered for orders from 2024-01-01")


Model Relationship Description
sale.order Target Model Model that implements actual report generation

Common Use Cases

Use Case 1: Manual Batch Report Generation

# Generate reports for specific period via wizard

from datetime import date

wizard_id = get_model("gen.sale.report").create({
    "date_from": "2024-01-01"
})

# Execute report generation
get_model("gen.sale.report").gen_report([wizard_id])

Use Case 2: Scheduled Report Generation

# Automated monthly report generation (called by scheduler)

from datetime import date
from dateutil.relativedelta import relativedelta

# First day of last month
last_month = date.today() - relativedelta(months=1)
first_day = last_month.strftime("%Y-%m-01")

wizard_id = get_model("gen.sale.report").create({
    "date_from": first_day
})

get_model("gen.sale.report").gen_report([wizard_id])

print(f"Monthly report generated for orders from {first_day}")

Use Case 3: Historical Report Regeneration

# Regenerate reports for past periods (data correction scenario)

from datetime import datetime
from dateutil.relativedelta import relativedelta

# Regenerate last 6 months of reports
start = datetime(2024, 1, 1)

for i in range(6):
    month_start = (start + relativedelta(months=i)).strftime("%Y-%m-01")

    wizard_id = get_model("gen.sale.report").create({
        "date_from": month_start
    })

    get_model("gen.sale.report").gen_report([wizard_id])

    print(f"Regenerated reports for {month_start}")

Use Case 4: Conditional Report Generation

# Generate reports only if orders exist from date

from datetime import date

date_from = "2024-01-01"

# Check if orders exist
order_count = get_model("sale.order").search_count([
    ["date", ">=", date_from]
])

if order_count > 0:
    wizard_id = get_model("gen.sale.report").create({
        "date_from": date_from
    })

    get_model("gen.sale.report").gen_report([wizard_id])

    print(f"Generated reports for {order_count} orders from {date_from}")
else:
    print(f"No orders found from {date_from}, skipping report generation")

Use Case 5: Integration with External Scheduler

# Called by external cron job or task scheduler

def generate_daily_reports():
    """
    Generate reports for yesterday's orders
    Called daily by external scheduler
    """
    from datetime import date, timedelta

    yesterday = (date.today() - timedelta(days=1)).strftime("%Y-%m-%d")

    try:
        wizard_id = get_model("gen.sale.report").create({
            "date_from": yesterday
        })

        get_model("gen.sale.report").gen_report([wizard_id])

        return {
            "status": "success",
            "message": f"Reports generated for {yesterday}"
        }

    except Exception as e:
        return {
            "status": "error",
            "message": str(e)
        }

# Call from scheduler
result = generate_daily_reports()
print(result["message"])

Implementation Notes

Wizard Pattern

This model follows the transient wizard pattern: 1. User (or system) creates wizard record with parameters 2. Wizard's action method is called 3. Wizard delegates to target model 4. Wizard record is discarded (transient)

Delegation to sale.order

The actual report generation logic resides in sale.order.gen_report():

# In gen_sale_report.py
def gen_report(self, ids, context={}):
    obj = self.browse(ids[0])
    date_from = obj.date_from
    get_model("sale.order").gen_report(date_from)  # Delegates here

This keeps the wizard simple and centralizes logic in the sale.order model.


Best Practices

1. Date Selection

# Use first day of period for consistency
date_from = "2024-01-01"  # Start of January

# Avoid mid-period dates unless specifically needed
date_from = "2024-01-15"  # May miss some orders

2. Error Handling

# Wrap in try-except for automated scenarios
try:
    wizard_id = get_model("gen.sale.report").create({
        "date_from": "2024-01-01"
    })
    get_model("gen.sale.report").gen_report([wizard_id])
    success = True
except Exception as e:
    print(f"Report generation failed: {e}")
    success = False
    # Log error, send alert, etc.

3. Batch Processing

# Process periods sequentially, not in parallel
# (Avoids database contention)

for period_start in period_dates:
    wizard_id = get_model("gen.sale.report").create({
        "date_from": period_start
    })
    get_model("gen.sale.report").gen_report([wizard_id])
    # Wait for completion before next period

Performance Considerations

1. Scope of Generation

  • The date_from parameter determines how many orders are processed
  • Very old dates may trigger processing of many historical orders
  • Consider incremental generation (monthly rather than yearly)

2. Timing

  • Run batch generation during off-peak hours
  • Avoid overlapping report generation jobs
  • Monitor execution time and adjust schedule

3. Resource Usage

  • Report generation may be resource-intensive
  • Check sale.order.gen_report() implementation for details
  • May involve database queries, file generation, etc.

Troubleshooting

"date_from is required"

Cause: Wizard created without date_from field Solution: - Always provide date_from when creating wizard - Check default is working (first day of month)

"Report generation appears to do nothing"

Cause: Actual logic is in sale.order.gen_report() method Solution: - Check if sale.order.gen_report() method exists - Review sale.order model for actual implementation - Check if method has any conditions that skip processing

"Reports generated multiple times"

Cause: Wizard called multiple times with same date Solution: - Check caller logic for duplicate calls - Implement idempotency in sale.order.gen_report() if needed - Add logging to track generation calls


UI Integration

This wizard is typically called from: 1. Manual Action: Menu item or button in UI 2. Scheduled Task: Automated periodic generation 3. Workflow: Triggered by specific events 4. API Call: External system integration

Example Menu Action

<record id="action_gen_sale_report" model="ui.action">
    <field name="name">Generate Sales Reports</field>
    <field name="model">gen.sale.report</field>
    <field name="view_cls">form</field>
    <field name="form_action">gen_report</field>
</record>

Version History

Last Updated: 2026-01-05 Model Version: gen_sale_report.py (23 lines) Framework: Netforce


Additional Resources

  • Sales Order Documentation: sale.order
  • Report Models: report.sale.* series
  • Transient Model Pattern: Netforce framework documentation

Notes

Minimal Implementation

This is one of the simplest models in the system: - Only 23 lines of code - Single field (date_from) - Single method (gen_report) - Pure delegation to sale.order

Purpose

Acts as a UI/API entry point for batch report generation, keeping the interface separate from the implementation logic.


This documentation is generated for developer onboarding and reference purposes.