Skip to content

Seller Commission Documentation

Overview

The Seller Commission module (seller.commission) defines commission rate structures and rules for sellers. It enables flexible commission configurations including tiered rates, customer-specific rates, minimum thresholds, and customer group-based commissions. This model works in conjunction with the seller model to calculate accurate commission payments.


Model Information

Model Name: seller.commission Display Name: Seller Commission Key Fields: seller_id, sequence

Features

  • ❌ Audit logging enabled (_audit_log)
  • ❌ Multi-company support (company_id)
  • ❌ Full-text content search (_content_search)
  • ❌ Unique key constraint
  • ✅ Customer-specific commission rates
  • ✅ Customer group-based commissions
  • ✅ Threshold-based commission activation
  • ✅ Sequential rule ordering

Key Fields Reference

Core Fields

Field Type Required Description
seller_id Many2One Reference to the seller this commission rule applies to (searchable)
sequence Integer Order in which rules are evaluated (lower numbers first)
commission_percent Decimal Commission percentage (e.g., 5.0 for 5%)
min_amount Decimal Minimum sales amount threshold before commission applies

Targeting Fields

Field Type Description
customer_id Many2One Specific customer this rule applies to (optional - leave empty for general rule)
customer_group_id Many2One Customer group this rule applies to (optional - for group-based commissions)

Understanding Commission Rules

Commission Rule Types

The seller.commission model supports three types of commission rules:

1. General Commission Rules

Applied to all customers unless a more specific rule exists.

{
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 4.0,
    "min_amount": 0
    # No customer_id or customer_group_id
}

2. Customer-Specific Commission Rules

Applied only to sales for a specific customer.

{
    "seller_id": seller_id,
    "sequence": 2,
    "customer_id": customer_id,  # Specific customer
    "commission_percent": 6.0,
    "min_amount": 0
}

3. Customer Group Commission Rules

Applied to all customers in a specific group.

{
    "seller_id": seller_id,
    "sequence": 3,
    "customer_group_id": group_id,  # Customer group
    "commission_percent": 5.5,
    "min_amount": 0
}

Commission Matching Priority

When calculating commissions, the system matches rules in this priority order:

  1. Customer-specific rules (customer_id is set)
  2. Customer group rules (customer_group_id is set)
  3. General rules (neither customer_id nor customer_group_id is set)

Within each category, rules are ordered by the sequence field (lower numbers first).


Threshold-Based Commissions

How Minimum Amount Works

The min_amount field creates a threshold that must be exceeded before commission is earned:

  • Sales below threshold: No commission paid
  • Sales at or above threshold: Commission paid on amount above threshold

Calculation Formula

if total_sales >= min_amount:
    commission = (total_sales - min_amount) × (commission_percent / 100)
else:
    commission = 0

Example

Commission rule: 5% on sales above $10,000

# Scenario 1: Sales = $15,000
commission = (15,000 - 10,000) × 5% = $250

# Scenario 2: Sales = $8,000
commission = $0  # Below threshold

# Scenario 3: Sales = $10,000
commission = (10,000 - 10,000) × 5% = $0

API Methods

1. Create Commission Rule

Method: create(vals, context)

Creates a new commission rule for a seller.

Parameters:

vals = {
    "seller_id": seller_id,           # Required: Seller this rule applies to
    "sequence": 1,                     # Optional: Evaluation order
    "commission_percent": 5.0,         # Optional: Commission percentage
    "min_amount": 0,                   # Optional: Minimum threshold
    "customer_id": customer_id,        # Optional: Specific customer
    "customer_group_id": group_id      # Optional: Customer group
}

Returns: int - New commission rule ID

Example:

# Create general commission rule
rule_id = get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 4.0,
    "min_amount": 0
})


2. Update Commission Rule

Method: write(ids, vals, context)

Updates existing commission rules.

Example:

# Update commission percentage
get_model("seller.commission").write([rule_id], {
    "commission_percent": 5.5
})

# Update minimum threshold
get_model("seller.commission").write([rule_id], {
    "min_amount": 20000
})


3. Delete Commission Rule

Method: delete(ids, context)

Deletes commission rules.

Example:

# Remove a commission rule
get_model("seller.commission").delete([rule_id])


Common Use Cases

Use Case 1: Single-Tier General Commission

Scenario: All sellers earn 5% on all sales with no minimum threshold.

# Create seller
seller_id = get_model("seller").create({
    "name": "John Smith",
    "code": "JS001"
})

# Create single commission rule
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 5.0,
    "min_amount": 0
})

Result: Seller earns 5% on every sale to any customer.


Use Case 2: Multi-Tier Commission Structure

Scenario: Progressive commission rates based on sales volume per customer.

seller_id = get_model("seller").create({
    "name": "Jane Doe",
    "code": "JD001"
})

# 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 from $50,000 to $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
})

How It Works: - Customer with $30,000 in sales: Uses Tier 1 → $30,000 × 3% = $900 - Customer with $75,000 in sales: Uses Tier 2 → ($75,000 - $50,000) × 5% = $1,250 - Customer with $150,000 in sales: Uses Tier 3 → ($150,000 - $100,000) × 7% = $3,500


Use Case 3: Customer-Specific VIP Rates

Scenario: Key accounts receive preferential commission rates to incentivize focus.

seller_id = get_model("seller").create({
    "name": "Bob Wilson",
    "code": "BW001"
})

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

# VIP Customer A: 7% commission
vip_customer_a_id = 123
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 10,
    "customer_id": vip_customer_a_id,
    "commission_percent": 7.0,
    "min_amount": 0
})

# VIP Customer B: 8% on sales above $25,000
vip_customer_b_id = 456
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 11,
    "customer_id": vip_customer_b_id,
    "commission_percent": 8.0,
    "min_amount": 25000
})

Result: - Sales to Customer A: 7% on all sales - Sales to Customer B: 8% on sales above $25,000 - Sales to any other customer: 4% on all sales


Use Case 4: Threshold-Based Commission (No Small Orders)

Scenario: Only pay commission on significant sales to focus seller efforts.

seller_id = get_model("seller").create({
    "name": "Alice Johnson",
    "code": "AJ001"
})

# Only pay commission on orders above $5,000
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 6.0,
    "min_amount": 5000
})

Result: - Order for $10,000: Commission = ($10,000 - $5,000) × 6% = $300 - Order for $3,000: Commission = $0 (below threshold)


Use Case 5: Customer Group-Based Commissions

Scenario: Different commission rates for wholesale vs retail customers.

seller_id = get_model("seller").create({
    "name": "Chris Brown",
    "code": "CB001"
})

# Get customer groups
wholesale_group_id = get_model("contact.group").search([["name", "=", "Wholesale"]])[0]
retail_group_id = get_model("contact.group").search([["name", "=", "Retail"]])[0]

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

# Wholesale customers: 3% (lower margin)
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 2,
    "customer_group_id": wholesale_group_id,
    "commission_percent": 3.0,
    "min_amount": 0
})

# Retail customers: 6% (higher margin)
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 3,
    "customer_group_id": retail_group_id,
    "commission_percent": 6.0,
    "min_amount": 0
})

Result: - Sales to wholesale customers: 3% commission - Sales to retail customers: 6% commission - Sales to ungrouped customers: 4% default commission


Use Case 6: Updating Commission Rates

Scenario: Annual commission structure adjustment.

# Find all commission rules for a seller
seller_id = 123
rules = get_model("seller.commission").search_browse([
    ["seller_id", "=", seller_id]
])

# Increase all rates by 0.5%
for rule in rules:
    new_rate = rule.commission_percent + 0.5
    get_model("seller.commission").write([rule.id], {
        "commission_percent": new_rate
    })

print(f"Updated {len(rules)} commission rules for seller")

Use Case 7: Seasonal/Promotional Higher Rates

Scenario: Create temporary higher commission rate for a promotional period.

# Add temporary high commission rule
promo_rule_id = get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 0,  # Highest priority
    "commission_percent": 10.0,
    "min_amount": 0
})

# After promotion ends, remove the rule
get_model("seller.commission").delete([promo_rule_id])

Note: This example demonstrates creating/deleting rules. In practice, you might want to use date-based filtering in your commission calculation logic.


Commission Calculation Examples

Example 1: Simple Flat Rate

Commission Rules:

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

Sales: - Customer A: $20,000 - Customer B: $30,000

Calculation:

Customer A: 20,000 × 5% = $1,000
Customer B: 30,000 × 5% = $1,500
Total Commission: $2,500


Example 2: Tiered Structure

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: - Customer A: $40,000 - Customer B: $80,000 - Customer C: $120,000

Calculation:

Customer A ($40,000):
  - Uses Tier 1 (highest applicable where 40,000 >= min_amount)
  - Commission: 40,000 × 3% = $1,200

Customer B ($80,000):
  - Uses Tier 2 (highest applicable where 80,000 >= min_amount)
  - Commission: (80,000 - 50,000) × 5% = $1,500

Customer C ($120,000):
  - Uses Tier 3 (highest applicable where 120,000 >= min_amount)
  - Commission: (120,000 - 100,000) × 7% = $1,400

Total Commission: $4,100


Example 3: Mixed Rules (General + Customer-Specific)

Commission Rules:

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

Sales: - Customer 100: $50,000 - Customer 200: $35,000 - Customer 300: $25,000

Calculation:

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

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

Customer 300 ($25,000):
  - Uses general rule (4%)
  - Commission: 25,000 × 4% = $1,000

Total Commission: $5,200


Best Practices

1. Use Sequence Numbers Strategically

# Good: Logical sequence numbering
# General rules: 1-9
# Customer group rules: 10-99
# Customer-specific rules: 100+

get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,  # General rule
    "commission_percent": 4.0
})

get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 50,  # Group rule
    "customer_group_id": group_id,
    "commission_percent": 5.0
})

get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 100,  # Customer-specific rule
    "customer_id": customer_id,
    "commission_percent": 6.0
})

# Bad: Random sequence numbers
# Makes it hard to understand rule priority

Why This Matters: Organized sequence numbering makes commission structures easier to understand, maintain, and debug.


2. Always Have a Default General Rule

# Good: Start with a general rule
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 1,
    "commission_percent": 4.0,  # Default for all customers
    "min_amount": 0
})

# Then add exceptions
get_model("seller.commission").create({
    "seller_id": seller_id,
    "sequence": 100,
    "customer_id": vip_customer_id,
    "commission_percent": 7.0
})

# Bad: Only customer-specific rules
# Customers without specific rules get no commission

Why This Matters: A default general rule ensures all sales generate commission unless explicitly configured otherwise.


3. Document Commission Structures

# Good: Use descriptive comments or descriptions

# Create tiered structure with documentation
tiers = [
    {
        "sequence": 1,
        "commission_percent": 3.0,
        "min_amount": 0,
        "description": "Base tier: 3% on all sales"
    },
    {
        "sequence": 2,
        "commission_percent": 5.0,
        "min_amount": 50000,
        "description": "Mid tier: 5% on sales above $50k"
    },
    {
        "sequence": 3,
        "commission_percent": 7.0,
        "min_amount": 100000,
        "description": "Top tier: 7% on sales above $100k"
    }
]

for tier in tiers:
    get_model("seller.commission").create({
        "seller_id": seller_id,
        **tier
    })

Why This Matters: Clear documentation helps future administrators understand the commission logic and business rules.


4. Test Commission Calculations

# Good: Verify commission rules work as expected

def verify_commission_structure(seller_id):
    # Get all rules
    rules = get_model("seller.commission").search_browse([
        ["seller_id", "=", seller_id]
    ])

    print(f"Commission Rules for Seller {seller_id}:")
    print("-" * 60)

    for rule in rules:
        rule_type = "General"
        if rule.customer_id:
            rule_type = f"Customer: {rule.customer_id.name}"
        elif rule.customer_group_id:
            rule_type = f"Group: {rule.customer_group_id.name}"

        print(f"Seq {rule.sequence:3d} | {rule_type:20s} | "
              f"{rule.commission_percent}% above ${rule.min_amount:,.0f}")

verify_commission_structure(seller_id)

Why This Matters: Regular verification prevents commission calculation errors and ensures rules match business agreements.


5. Avoid Overlapping Rules

# Good: Clear, non-overlapping tiers
tiers = [
    {"min_amount": 0, "commission_percent": 3.0},
    {"min_amount": 50000, "commission_percent": 5.0},
    {"min_amount": 100000, "commission_percent": 7.0}
]

# Confusing: Overlapping thresholds with different rates
# Can lead to unexpected commission calculations
overlapping = [
    {"min_amount": 0, "commission_percent": 3.0},
    {"min_amount": 40000, "commission_percent": 4.0},  # Overlaps with tier above
    {"min_amount": 50000, "commission_percent": 5.0}   # Creates confusion
]

Why This Matters: The system selects the highest applicable tier, so overlapping rules should increase commission rates, not create confusion.


Model Relationship Description
seller Many2One The seller this commission rule belongs to
contact Many2One Optional customer this rule specifically applies to
contact.group Many2One Optional customer group this rule applies to
sale.order Indirect Sales orders used in commission calculation

Search Functions

Search by Seller

# Get all commission rules for a specific seller
rules = get_model("seller.commission").search_browse([
    ["seller_id", "=", seller_id]
])

Search by Customer

# Find customer-specific commission rules
customer_rules = get_model("seller.commission").search_browse([
    ["customer_id", "=", customer_id]
])

Search General Rules

# Find general commission rules (not customer-specific)
general_rules = get_model("seller.commission").search_browse([
    ["customer_id", "=", None]
])

Troubleshooting

"Seller not earning expected commission"

Cause: Commission rules may not be configured correctly, or sales may be below minimum thresholds.

Solution:

# Check seller's commission rules
seller_id = 123
rules = get_model("seller.commission").search_browse([
    ["seller_id", "=", seller_id]
])

if not rules:
    print("ERROR: No commission rules found for seller!")
else:
    print(f"Found {len(rules)} commission rules:")
    for rule in rules:
        print(f"  - {rule.commission_percent}% above ${rule.min_amount:,.0f}")
        if rule.customer_id:
            print(f"    (Customer-specific: {rule.customer_id.name})")


"Customer-specific rule not being applied"

Cause: Customer ID mismatch or sequence order issue.

Solution:

# Verify customer-specific rules
customer_id = 456
rules = get_model("seller.commission").search_browse([
    ["seller_id", "=", seller_id],
    ["customer_id", "=", customer_id]
])

if rules:
    print(f"Found customer-specific rule: {rules[0].commission_percent}%")
else:
    print("No customer-specific rule found - will use general rule")


"Commission changes not taking effect"

Cause: Existing sales orders may have already been calculated, or caching issues.

Solution: - Commission rules affect future calculations only - Re-run commission calculation for the period - Verify rule changes were saved correctly

# Verify rule was updated
rule = get_model("seller.commission").browse(rule_id)
print(f"Current rate: {rule.commission_percent}%")

Performance Tips

1. Minimize Number of Rules

  • Keep commission structures as simple as possible
  • Use tiered structures instead of many overlapping rules
  • Consolidate similar customer rules using customer groups

2. Optimize Rule Ordering

  • Use sequence numbers to ensure most common rules are checked first
  • General rules should have lower sequence numbers
  • Customer-specific exceptions should have higher sequence numbers

3. Regular Cleanup

  • Remove obsolete commission rules
  • Archive or delete rules for inactive sellers
  • Consolidate redundant rules

Testing Examples

Unit Test: Commission Rule Creation

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

    # Create commission rule
    rule_id = get_model("seller.commission").create({
        "seller_id": seller_id,
        "sequence": 1,
        "commission_percent": 5.0,
        "min_amount": 10000
    })

    # Verify rule was created
    rule = get_model("seller.commission").browse(rule_id)
    assert rule.seller_id.id == seller_id
    assert rule.commission_percent == 5.0
    assert rule.min_amount == 10000

    print("Commission rule creation test passed!")

    # Cleanup
    get_model("seller.commission").delete([rule_id])
    get_model("seller").delete([seller_id])

Security Considerations

Permission Model

  • Create/Edit Commission Rules: Restricted to Sales Managers
  • View Commission Data: May be restricted based on user role
  • Delete Commission Rules: Requires manager approval

Data Access

  • Commission rules contain sensitive business logic
  • Commission percentages should be confidential
  • Access should be logged for audit purposes

Version History

Last Updated: 2025-01-05 Model Version: seller_commission.py Framework: Netforce


Additional Resources

  • Seller Documentation: seller
  • Sale Order Documentation: sale.order
  • Contact Documentation: contact
  • Contact Group Documentation: contact.group

Support & Feedback

For issues or questions about this module: 1. Verify commission rules are properly configured 2. Check sequence numbers for correct priority 3. Ensure min_amount thresholds are set appropriately 4. Test calculations with known test data 5. Review seller documentation for commission calculation algorithm


This documentation is generated for developer onboarding and reference purposes.