Skip to content

Seller Documentation

Overview

The Seller module (seller) manages sales representatives, channel partners, and other sales personnel within the system. It provides comprehensive functionality for seller profile management, commission calculation, and integration with HR employee records and sales orders.


Model Information

Model Name: seller Display Name: Seller Key Fields: name, code

Features

  • ❌ Audit logging enabled (_audit_log)
  • ❌ Multi-company support (company_id)
  • ❌ Full-text content search (_content_search)
  • ❌ Unique key constraint
  • ✅ Commission calculation engine
  • ✅ HR employee integration
  • ✅ Multi-tier commission structure support
  • ✅ Customer-specific commission rates

Seller Types

The seller model supports different types of sales personnel to accommodate various business models:

Type Code Description
Internal internal Direct employees of the company (e.g., in-house sales team)
Channel Partner channel_partner External partners who sell on behalf of the company
Retails retails Retail store or outlet sellers
Consignment consignment Consignment-based sellers

Key Fields Reference

Basic Information Fields

Field Type Required Description
name Char Seller's full name or display name (searchable)
code Char Unique identifier code for the seller (searchable)
type Selection Type of seller (internal, channel_partner, retails, consignment)
description Text Additional notes or description about the seller (searchable)

Integration Fields

Field Type Description
employee_id Many2One Link to hr.employee record (optional) - allows integration with HR module

Relationship Fields

Field Type Description
commissions One2Many Collection of seller.commission records defining commission rules

Note: The seller model is referenced from sale.order and sale.quot through the seller_id field, automatically tracking which seller is responsible for each sale.


Commission Calculation Algorithm

Understanding the Commission Engine

The seller model includes a sophisticated commission calculation method (calc_commission) that computes total commissions earned by a seller over a specified date range.

How Commission Calculation Works

The commission calculation follows this algorithm:

1. Filter sales orders by seller and date range (only "confirmed" or "done" states)
2. Group order amounts by customer
3. For each customer:
   a. Find matching commission rule (customer-specific first, then general)
   b. Calculate amount above threshold
   c. Apply commission percentage
4. Sum all commission amounts

Commission Matching Logic

The system uses a priority-based matching algorithm:

  1. Customer-specific commissions are checked first
  2. If found, that commission rule is used
  3. If no customer-specific rule exists, the first general commission (no customer_id) is used
  4. Commission rules are ordered by sequence field

Threshold-Based Calculation

Commissions are only calculated on amounts above the minimum threshold:

commission_amount = (total_sales - min_amount) × (commission_percent / 100)

If total sales are below the threshold, no commission is earned for that customer.


API Methods

1. Create Seller

Method: create(vals, context)

Creates a new seller record.

Parameters:

vals = {
    "name": "John Smith",              # Required: Seller name
    "code": "JS001",                    # Optional: Seller code
    "type": "internal",                 # Optional: Seller type
    "employee_id": 5,                   # Optional: Link to HR employee
    "description": "Senior Sales Rep",  # Optional: Description
    "commissions": [                    # Optional: Commission rules
        ("create", {
            "commission_percent": 5.0,
            "min_amount": 0
        })
    ]
}

Returns: int - New seller record ID

Example:

# Create an internal seller with basic commission structure
seller_id = get_model("seller").create({
    "name": "John Smith",
    "code": "JS001",
    "type": "internal",
    "employee_id": 5,
    "commissions": [
        ("create", {
            "sequence": 1,
            "commission_percent": 5.0,
            "min_amount": 0
        }),
        ("create", {
            "sequence": 2,
            "commission_percent": 7.5,
            "min_amount": 100000
        })
    ]
})


2. Calculate Commission

Method: calc_commission(ids, date_from=None, date_to=None, context={})

Calculates total commission earned by a seller for a specified period based on confirmed/completed sales orders.

Parameters: - ids (list): Single-item list containing the seller ID - date_from (str): Optional start date in format "YYYY-MM-DD" (inclusive) - date_to (str): Optional end date in format "YYYY-MM-DD" (inclusive) - context (dict): Optional context dictionary

Behavior: - Only includes sales orders in "confirmed" or "done" state - Groups sales by customer before applying commission rules - Applies customer-specific commission rates when available - Falls back to general commission rates for customers without specific rules - Only calculates commission on amounts above the minimum threshold - Returns the total commission amount across all customers

Returns: Decimal - Total commission amount earned

Example:

# Calculate commission for January 2025
seller_id = 123
commission = get_model("seller").calc_commission(
    [seller_id],
    date_from="2025-01-01",
    date_to="2025-01-31"
)
print(f"Total commission: {commission}")

# Calculate commission for all time
total_commission = get_model("seller").calc_commission([seller_id])

# Calculate commission for Q1 2025
q1_commission = get_model("seller").calc_commission(
    [seller_id],
    date_from="2025-01-01",
    date_to="2025-03-31"
)

Detailed Algorithm:

# Step 1: Gather all confirmed/done sales for the seller in date range
sales = sale.order.search_browse([
    ["seller_id", "=", seller_id],
    ["state", "in", ["confirmed", "done"]],
    ["date", ">=", date_from],
    ["date", "<=", date_to]
])

# Step 2: Group sales amounts by customer
customer_totals = {}
for sale in sales:
    customer_id = sale.contact_id.id
    customer_totals[customer_id] += sale.amount_total

# Step 3: Calculate commission per customer
total_commission = 0
for customer_id, customer_total in customer_totals.items():
    # Find applicable commission rule (customer-specific first)
    commission_rule = find_matching_commission(seller, customer_id)

    if commission_rule:
        # Only pay commission on amount above threshold
        amount_above = customer_total - (commission_rule.min_amount or 0)
        commission_amt = amount_above * (commission_rule.commission_percent or 0) / 100
        total_commission += commission_amt

return total_commission

Search Functions

Search by Name

# Find sellers by name (case-insensitive partial match)
sellers = get_model("seller").search_browse([["name", "ilike", "%smith%"]])

Search by Code

# Find specific seller by code
seller = get_model("seller").search_browse([["code", "=", "JS001"]])

Search by Employee

# Find seller linked to specific employee
seller = get_model("seller").search_browse([["employee_id", "=", employee_id]])

Search by Type

# Find all internal sellers
internal_sellers = get_model("seller").search_browse([["type", "=", "internal"]])

# Find all channel partners
partners = get_model("seller").search_browse([["type", "=", "channel_partner"]])

Model Relationship Description
seller.commission One2Many (parent) Commission rules and rate structures for this seller
hr.employee Many2One Optional link to employee record for internal sellers
sale.order Many2One (inverse) Sales orders assigned to this seller
sale.quot Many2One (inverse) Sales quotations assigned to this seller
contact Indirect (via commissions) Customers with specific commission rates
shop Indirect Shop/location assignments (referenced elsewhere)

Common Use Cases

Use Case 1: Setting Up a New Seller with Tiered Commissions

# Create a seller with progressive commission tiers

# 1. Create the seller record
seller_id = get_model("seller").create({
    "name": "Jane Doe",
    "code": "JD001",
    "type": "internal",
    "employee_id": 42,  # Link to HR employee record
    "description": "Territory: North Region"
})

# 2. Add tiered commission structure
# Tier 1: 3% on sales up to 50,000
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 3.0,
    "min_amount": 0
})

# Tier 2: 5% on sales between 50,000 and 100,000
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 2,
    "commission_percent": 5.0,
    "min_amount": 50000
})

# Tier 3: 7% on sales above 100,000
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 3,
    "commission_percent": 7.0,
    "min_amount": 100000
})

# 3. Verify setup
seller = get_model("seller").browse(seller_id)
print(f"Seller: {seller.name}")
print(f"Commission tiers: {len(seller.commissions)}")
for com in seller.commissions:
    print(f"  {com.commission_percent}% above {com.min_amount}")

How This Works:

When calculating commissions for sales totaling 75,000 to a single customer: - The system finds the highest applicable tier where 75,000 >= min_amount - This would be Tier 2 (min_amount: 50,000) - Commission = (75,000 - 50,000) × 5% = 1,250


Use Case 2: Setting Up Customer-Specific Commission Rates

# Give special commission rates for key accounts

# 1. Create seller
seller_id = get_model("seller").create({
    "name": "Bob Johnson",
    "code": "BJ001",
    "type": "channel_partner"
})

# 2. Set general commission rate (default for all customers)
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 4.0,
    "min_amount": 0
})

# 3. Set special rate for key customer
key_customer_id = 789
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 2,
    "customer_id": key_customer_id,  # Customer-specific rule
    "commission_percent": 6.0,         # Higher rate for this customer
    "min_amount": 0
})

# 4. Another key customer with threshold
another_customer_id = 456
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 3,
    "customer_id": another_customer_id,
    "commission_percent": 7.5,
    "min_amount": 25000  # Only pay commission above 25,000
})

How Customer-Specific Rules Work:

When calculating commission: - Sales to customer 789: Uses 6% rate (customer-specific rule) - Sales to customer 456: Uses 7.5% rate on amounts above 25,000 - Sales to any other customer: Uses default 4% rate


Use Case 3: Calculating Monthly Commission Report

# Generate commission report for a seller for a specific month

seller_id = 123
month = "2025-01"

# Calculate commission for the month
commission = get_model("seller").calc_commission(
    [seller_id],
    date_from=f"{month}-01",
    date_to=f"{month}-31"
)

# Get seller details
seller = get_model("seller").browse(seller_id)

# Get sales breakdown by customer
sales = get_model("sale.order").search_browse([
    ["seller_id", "=", seller_id],
    ["state", "in", ["confirmed", "done"]],
    ["date", ">=", f"{month}-01"],
    ["date", "<=", f"{month}-31"]
])

# Group by customer
from collections import defaultdict
customer_sales = defaultdict(lambda: {"total": 0, "count": 0})

for sale in sales:
    cust_id = sale.contact_id.id
    cust_name = sale.contact_id.name
    customer_sales[cust_name]["total"] += sale.amount_total
    customer_sales[cust_name]["count"] += 1

# Print report
print(f"Commission Report for {seller.name}")
print(f"Period: {month}")
print(f"Total Commission: ${commission:,.2f}")
print("\nSales Breakdown:")
print("-" * 60)

for customer, data in sorted(customer_sales.items()):
    print(f"{customer:30s} {data['count']:3d} orders  ${data['total']:10,.2f}")

Use Case 4: Quarterly Performance Tracking

# Track seller performance across quarters

seller_id = 123

# Define quarters
quarters = [
    ("Q1 2025", "2025-01-01", "2025-03-31"),
    ("Q2 2025", "2025-04-01", "2025-06-30"),
    ("Q3 2025", "2025-07-01", "2025-09-30"),
    ("Q4 2025", "2025-10-01", "2025-12-31"),
]

seller = get_model("seller").browse(seller_id)
print(f"Performance Report: {seller.name}")
print("=" * 70)

for quarter_name, date_from, date_to in quarters:
    # Calculate commission for quarter
    commission = get_model("seller").calc_commission(
        [seller_id],
        date_from=date_from,
        date_to=date_to
    )

    # Get sales count and total
    sales = get_model("sale.order").search_browse([
        ["seller_id", "=", seller_id],
        ["state", "in", ["confirmed", "done"]],
        ["date", ">=", date_from],
        ["date", "<=", date_to]
    ])

    total_sales = sum(sale.amount_total for sale in sales)

    print(f"\n{quarter_name}")
    print(f"  Orders: {len(sales)}")
    print(f"  Total Sales: ${total_sales:,.2f}")
    print(f"  Commission: ${commission:,.2f}")
    if total_sales > 0:
        print(f"  Effective Rate: {(commission/total_sales*100):.2f}%")

Use Case 5: Migrating Seller to Different Employee

# Update seller when employee changes

seller_id = 123
new_employee_id = 456

# Update the seller record
get_model("seller").write([seller_id], {
    "employee_id": new_employee_id
})

# Optionally update description
old_seller = get_model("seller").browse(seller_id)
get_model("seller").write([seller_id], {
    "description": f"Transferred from previous employee on 2025-01-05"
})

print(f"Seller {old_seller.name} reassigned to employee {new_employee_id}")

Use Case 6: Finding Top Performers

# Identify top-performing sellers for a period

date_from = "2025-01-01"
date_to = "2025-12-31"

# Get all sellers
sellers = get_model("seller").search_browse([])

# Calculate commission for each
performance = []
for seller in sellers:
    commission = get_model("seller").calc_commission(
        [seller.id],
        date_from=date_from,
        date_to=date_to
    )

    if commission > 0:
        performance.append({
            "seller": seller.name,
            "code": seller.code,
            "type": seller.type,
            "commission": commission
        })

# Sort by commission (descending)
performance.sort(key=lambda x: x["commission"], reverse=True)

# Print top 10
print("Top 10 Sellers by Commission")
print("=" * 70)
for i, data in enumerate(performance[:10], 1):
    print(f"{i:2d}. {data['seller']:20s} ({data['code']:10s}) ${data['commission']:12,.2f}")

Commission Calculation Examples

Example 1: Single-Tier Commission

Setup: - Commission: 5% on all sales - No minimum threshold

Commission Rules:

{
    "sequence": 1,
    "commission_percent": 5.0,
    "min_amount": 0
}

Sales in January: - Customer A: $10,000 - Customer B: $15,000 - Customer C: $5,000 - Total: $30,000

Commission Calculation:

Customer A: (10,000 - 0) × 5% = $500
Customer B: (15,000 - 0) × 5% = $750
Customer C: (5,000 - 0) × 5% = $250

Total Commission: $1,500


Example 2: Multi-Tier Commission

Setup: - Tier 1: 3% on sales up to $50,000 (per customer) - Tier 2: 5% on sales from $50,000 to $100,000 - Tier 3: 7% on sales above $100,000

Commission Rules:

[
    {"sequence": 1, "commission_percent": 3.0, "min_amount": 0},
    {"sequence": 2, "commission_percent": 5.0, "min_amount": 50000},
    {"sequence": 3, "commission_percent": 7.0, "min_amount": 100000}
]

Sales in January: - Customer A: $75,000 - Customer B: $120,000 - Customer C: $30,000

Commission Calculation:

Customer A ($75,000):
  - Applies Tier 2 (highest tier where 75,000 >= min_amount)
  - Commission: (75,000 - 50,000) × 5% = $1,250

Customer B ($120,000):
  - Applies Tier 3 (highest tier where 120,000 >= min_amount)
  - Commission: (120,000 - 100,000) × 7% = $1,400

Customer C ($30,000):
  - Applies Tier 1 (highest tier where 30,000 >= min_amount)
  - Commission: (30,000 - 0) × 3% = $900

Total Commission: $3,550


Example 3: Customer-Specific Rates

Setup: - Default: 4% on all sales - Customer X: 6% on all sales (key account) - Customer Y: 8% on sales above $20,000 (strategic account)

Commission Rules:

[
    {"sequence": 1, "commission_percent": 4.0, "min_amount": 0},
    {"sequence": 2, "customer_id": X, "commission_percent": 6.0, "min_amount": 0},
    {"sequence": 3, "customer_id": Y, "commission_percent": 8.0, "min_amount": 20000}
]

Sales in January: - Customer X: $50,000 - Customer Y: $35,000 - Customer Z: $25,000

Commission Calculation:

Customer X ($50,000):
  - Uses customer-specific rule (6%)
  - Commission: (50,000 - 0) × 6% = $3,000

Customer Y ($35,000):
  - Uses customer-specific rule (8% above $20,000)
  - Commission: (35,000 - 20,000) × 8% = $1,200

Customer Z ($25,000):
  - Uses default rule (4%)
  - Commission: (25,000 - 0) × 4% = $1,000

Total Commission: $5,200


Example 4: Threshold-Based Commission

Setup: - Commission: 5% on sales above $10,000 per customer - No commission on sales below threshold

Commission Rules:

{
    "sequence": 1,
    "commission_percent": 5.0,
    "min_amount": 10000
}

Sales in January: - Customer A: $15,000 - Customer B: $8,000 - Customer C: $25,000

Commission Calculation:

Customer A ($15,000):
  - Above threshold: 15,000 - 10,000 = $5,000
  - Commission: 5,000 × 5% = $250

Customer B ($8,000):
  - Below threshold: 8,000 < 10,000
  - Commission: $0 (no commission earned)

Customer C ($25,000):
  - Above threshold: 25,000 - 10,000 = $15,000
  - Commission: 15,000 × 5% = $750

Total Commission: $1,000


Best Practices

1. Commission Structure Setup

# Good: Use sequence to control commission rule priority

# Step 1: Create general rules first (lower sequence numbers)
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,  # General rule
    "commission_percent": 4.0,
    "min_amount": 0
})

# Step 2: Add customer-specific rules (higher sequence numbers)
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 10,  # Customer-specific rule
    "customer_id": customer_id,
    "commission_percent": 6.0,
    "min_amount": 0
})

# Bad: Random sequence numbers without logic
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 99,  # Arbitrary number
    "commission_percent": 4.0
})

Why This Matters: The commission calculation engine uses the sequence field to order commission rules. While customer-specific rules take priority, proper sequencing makes the commission structure easier to understand and maintain.


2. Linking Sellers to Employees

# Good: Link internal sellers to HR employees for proper tracking

seller_id = get_model("seller").create({
    "name": "John Smith",
    "code": "JS001",
    "type": "internal",
    "employee_id": employee_id  # Link to HR record
})

# Bad: Creating internal seller without employee link
seller_id = get_model("seller").create({
    "name": "John Smith",
    "type": "internal"
    # No employee_id - can't link to HR data
})

Why This Matters: Linking sellers to employee records enables: - Unified reporting across HR and Sales - Automatic payroll integration - Employee hierarchy and territory management - Leave/absence tracking impact on sales


3. Commission Date Ranges

# Good: Use explicit date ranges for accurate reporting

commission = get_model("seller").calc_commission(
    [seller_id],
    date_from="2025-01-01",
    date_to="2025-01-31"
)

# Bad: Calculating commission without date boundaries
commission = get_model("seller").calc_commission([seller_id])
# Returns ALL-TIME commission (could be huge dataset)

Why This Matters: Always specify date ranges to: - Improve query performance - Get accurate period-specific results - Avoid processing unnecessary historical data - Enable consistent month-over-month comparisons


4. Seller Code Conventions

# Good: Use consistent, meaningful seller codes

sellers = [
    {"name": "John Smith", "code": "INT-001", "type": "internal"},
    {"name": "Jane Doe", "code": "INT-002", "type": "internal"},
    {"name": "ABC Corp", "code": "CP-001", "type": "channel_partner"},
    {"name": "XYZ Retail", "code": "RET-001", "type": "retails"}
]

# Bad: Inconsistent or meaningless codes
sellers = [
    {"name": "John Smith", "code": "A1"},
    {"name": "Jane Doe", "code": "seller2"},
    {"name": "ABC Corp", "code": "x"}
]

Why This Matters: Consistent seller codes: - Make reporting and filtering easier - Enable quick identification of seller types - Support automated integrations - Improve data quality and searchability


5. Testing Commission Structures

# Good: Test commission calculations before deploying

def test_seller_commission():
    # Create test seller
    seller_id = get_model("seller").create({
        "name": "Test Seller",
        "code": "TEST-001"
    })

    # Create test commission rules
    get_model("seller.commission").create({
        "seller_id": seller_id,
        "commission_percent": 5.0,
        "min_amount": 10000
    })

    # Create test sale order
    order_id = get_model("sale.order").create({
        "contact_id": customer_id,
        "seller_id": seller_id,
        "date": "2025-01-15",
        "state": "confirmed",
        "amount_total": 20000
    })

    # Calculate commission
    commission = get_model("seller").calc_commission(
        [seller_id],
        date_from="2025-01-01",
        date_to="2025-01-31"
    )

    # Verify: (20,000 - 10,000) × 5% = 500
    assert commission == 500, f"Expected 500, got {commission}"

    # Cleanup test data
    get_model("sale.order").delete([order_id])
    get_model("seller").delete([seller_id])

# Run test
test_seller_commission()

Performance Tips

1. Optimize Commission Calculations

  • Use date ranges: Always specify date_from and date_to to limit dataset size
  • Batch calculations: Calculate commissions for multiple periods at once if needed
  • Index seller_id: Ensure sale.order.seller_id field is indexed for fast lookups

2. Commission Rule Optimization

# Good: Minimal, well-organized commission rules
# 1 general rule + customer-specific overrides as needed

# Bad: Excessive overlapping rules
# Multiple rules with complex conditions that slow down matching

3. Large Volume Scenarios

For sellers with thousands of orders:

# Consider creating a materialized report table
# Run commission calculations in batch processes
# Use background jobs for historical commission reports


Integration with Sale Orders

How Sellers are Assigned to Sales

When creating a sale order, assign a seller:

order_id = get_model("sale.order").create({
    "contact_id": customer_id,
    "seller_id": seller_id,  # Assigns seller to this sale
    "date": "2025-01-15",
    "lines": [
        ("create", {
            "product_id": product_id,
            "qty": 10,
            "unit_price": 100
        })
    ]
})

Tracking Sales by Seller

# Get all sales for a specific seller
sales = get_model("sale.order").search_browse([
    ["seller_id", "=", seller_id],
    ["state", "in", ["confirmed", "done"]]
])

# Get sales statistics
total_orders = len(sales)
total_value = sum(sale.amount_total for sale in sales)
avg_order_value = total_value / total_orders if total_orders > 0 else 0

print(f"Seller: {seller.name}")
print(f"Total Orders: {total_orders}")
print(f"Total Value: ${total_value:,.2f}")
print(f"Average Order: ${avg_order_value:,.2f}")

Troubleshooting

"Commission calculation returns 0 for active seller"

Cause: One or more of these conditions: - No sale orders in specified date range - Sale orders not in "confirmed" or "done" state - No commission rules defined for the seller - Sales amounts below minimum thresholds

Solution:

# Debug step by step:

# 1. Check if seller has sales
sales = get_model("sale.order").search_browse([
    ["seller_id", "=", seller_id],
    ["date", ">=", date_from],
    ["date", "<=", date_to]
])
print(f"Found {len(sales)} sales")

# 2. Check sale states
for sale in sales:
    print(f"Order {sale.number}: state={sale.state}, amount={sale.amount_total}")

# 3. Check commission rules
seller = get_model("seller").browse(seller_id)
print(f"Commission rules: {len(seller.commissions)}")
for com in seller.commissions:
    print(f"  {com.commission_percent}% above {com.min_amount}")


"Customer-specific commission not being applied"

Cause: Commission rule matching logic prioritizes customer-specific rules, but requires exact customer_id match.

Solution:

# Verify customer IDs match exactly
seller = get_model("seller").browse(seller_id)
for com in seller.commissions:
    if com.customer_id:
        print(f"Customer-specific rule: customer_id={com.customer_id.id}")

# Check sale order customer IDs
sales = get_model("sale.order").search_browse([["seller_id", "=", seller_id]])
for sale in sales:
    print(f"Order {sale.number}: customer_id={sale.contact_id.id}")


"Commission calculation takes too long"

Cause: Large number of sale orders without date filtering, or inefficient database queries.

Solution: - Always specify date_from and date_to - Ensure sale.order.seller_id field is indexed - Consider creating summary tables for historical data - Use background jobs for large date ranges

# Bad: No date filter (processes all history)
commission = get_model("seller").calc_commission([seller_id])

# Good: Specific date range
commission = get_model("seller").calc_commission(
    [seller_id],
    date_from="2025-01-01",
    date_to="2025-01-31"
)

Testing Examples

Unit Test: Commission Calculation with Tiers

def test_tiered_commission():
    # Create test seller
    seller_id = get_model("seller").create({
        "name": "Test Seller",
        "code": "TEST-001"
    })

    # Create tiered commission structure
    # Tier 1: 3% on all sales
    get_model("seller.commission").create({
        "seller_id": seller_id,
        "sequence": 1,
        "commission_percent": 3.0,
        "min_amount": 0
    })

    # Tier 2: 5% on sales above 50,000
    get_model("seller.commission").create({
        "seller_id": seller_id,
        "sequence": 2,
        "commission_percent": 5.0,
        "min_amount": 50000
    })

    # Create test customer
    customer_id = get_model("contact").create({
        "name": "Test Customer"
    })

    # Create sale order for 75,000 (should use Tier 2)
    order_id = get_model("sale.order").create({
        "contact_id": customer_id,
        "seller_id": seller_id,
        "date": "2025-01-15",
        "state": "confirmed",
        "amount_total": 75000
    })

    # Calculate commission
    commission = get_model("seller").calc_commission(
        [seller_id],
        date_from="2025-01-01",
        date_to="2025-01-31"
    )

    # Expected: (75,000 - 50,000) × 5% = 1,250
    assert commission == 1250, f"Expected 1,250, got {commission}"

    print("Tiered commission test passed!")

    # Cleanup
    get_model("sale.order").delete([order_id])
    get_model("contact").delete([customer_id])
    get_model("seller").delete([seller_id])

Unit Test: Customer-Specific Commission

def test_customer_specific_commission():
    # Create test seller
    seller_id = get_model("seller").create({
        "name": "Test Seller",
        "code": "TEST-002"
    })

    # Create test customers
    customer_a_id = get_model("contact").create({"name": "Customer A"})
    customer_b_id = get_model("contact").create({"name": "Customer B"})

    # General commission: 4%
    get_model("seller.commission").create({
        "seller_id": seller_id,
        "sequence": 1,
        "commission_percent": 4.0,
        "min_amount": 0
    })

    # Customer A specific: 6%
    get_model("seller.commission").create({
        "seller_id": seller_id,
        "sequence": 2,
        "customer_id": customer_a_id,
        "commission_percent": 6.0,
        "min_amount": 0
    })

    # Create sales
    order_a_id = get_model("sale.order").create({
        "contact_id": customer_a_id,
        "seller_id": seller_id,
        "date": "2025-01-15",
        "state": "confirmed",
        "amount_total": 10000
    })

    order_b_id = get_model("sale.order").create({
        "contact_id": customer_b_id,
        "seller_id": seller_id,
        "date": "2025-01-15",
        "state": "confirmed",
        "amount_total": 10000
    })

    # Calculate commission
    commission = get_model("seller").calc_commission(
        [seller_id],
        date_from="2025-01-01",
        date_to="2025-01-31"
    )

    # Expected:
    # Customer A: 10,000 × 6% = 600
    # Customer B: 10,000 × 4% = 400
    # Total: 1,000
    assert commission == 1000, f"Expected 1,000, got {commission}"

    print("Customer-specific commission test passed!")

    # Cleanup
    get_model("sale.order").delete([order_a_id, order_b_id])
    get_model("contact").delete([customer_a_id, customer_b_id])
    get_model("seller").delete([seller_id])

Security Considerations

Permission Model

  • Create/Edit Sellers: Typically restricted to Sales Managers and HR
  • View Commission Data: May be restricted to seller themselves + management
  • Calculate Commissions: Should be audited for financial tracking

Data Access

  • Sellers should typically only see their own commission data
  • Management reports may aggregate data across all sellers
  • Commission rules may contain sensitive business logic
  • Integration with payroll systems requires secure data transfer

Version History

Last Updated: 2025-01-05 Model Version: seller.py (from contact.py with calc_commission method) Framework: Netforce


Additional Resources

  • Seller Commission Documentation: seller.commission
  • Shop Documentation: shop
  • Sale Order Documentation: sale.order
  • HR Employee Documentation: hr.employee

Support & Feedback

For issues or questions about this module: 1. Check seller.commission documentation for commission rule setup 2. Review sale order documentation for seller assignment 3. Verify sale order states (must be "confirmed" or "done") 4. Test commission calculations with known test data 5. Check date ranges and customer IDs for accuracy


This documentation is generated for developer onboarding and reference purposes.