Systems Library / Sales Automation / How to Create Automated Deal Rotation and Assignment
Sales Automation crm pipeline

How to Create Automated Deal Rotation and Assignment

Route new deals to the right rep based on territory, capacity, and expertise.

Jay Banlasan

Jay Banlasan

The AI Systems Guy

Manual deal assignment wastes time and creates uneven workloads. This system automates deal assignment and rotation for your sales team based on territory, capacity, and expertise. I set this up for teams of 5 to 50 reps.

What You Need Before Starting

Step 1: Define Routing Rules

Set up rules for how deals get assigned. Territory, deal size, and industry all factor in.

ROUTING_RULES = {
    "territories": {
        "US-West": ["rep_alice", "rep_bob"],
        "US-East": ["rep_carol", "rep_dave"],
        "UK": ["rep_emma"],
    },
    "size_tiers": {
        "enterprise": {"min_amount": 50000, "reps": ["rep_alice", "rep_carol"]},
        "mid_market": {"min_amount": 10000, "reps": ["rep_bob", "rep_dave"]},
        "smb": {"min_amount": 0, "reps": ["rep_emma"]},
    },
    "max_active_deals": 25,
}

Step 2: Track Rep Capacity

Keep a live count of each rep's active deals. Nobody gets new deals when maxed out.

import sqlite3

def get_rep_capacity(rep_id):
    conn = sqlite3.connect("assignments.db")
    active = conn.execute(
        "SELECT COUNT(*) FROM deals WHERE owner = ? AND status = 'open'",
        (rep_id,)
    ).fetchone()[0]
    return ROUTING_RULES["max_active_deals"] - active

def get_available_reps(rep_list):
    available = []
    for rep in rep_list:
        capacity = get_rep_capacity(rep)
        if capacity > 0:
            available.append({"rep": rep, "capacity": capacity})
    return sorted(available, key=lambda x: -x["capacity"])

Step 3: Build the Assignment Engine

When a new deal comes in, find the right rep based on territory and capacity.

def assign_deal(deal):
    territory = deal.get("territory", "US-East")
    amount = deal.get("amount", 0)
    eligible_reps = ROUTING_RULES["territories"].get(territory, [])

    for tier_name, tier in ROUTING_RULES["size_tiers"].items():
        if amount >= tier["min_amount"]:
            eligible_reps = [r for r in eligible_reps if r in tier["reps"]]
            break

    available = get_available_reps(eligible_reps)
    if available:
        assigned_rep = available[0]["rep"]
        update_crm_owner(deal["id"], assigned_rep)
        return assigned_rep
    return None

Step 4: Handle the Webhook

Listen for new deal creation events from your CRM.

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhook/new-deal", methods=["POST"])
def handle_new_deal():
    deal = request.json
    assigned = assign_deal(deal)
    if assigned:
        return jsonify({"status": "assigned", "rep": assigned})
    else:
        notify_manager("No available reps for new deal")
        return jsonify({"status": "escalated"})

Step 5: Add Round-Robin Fallback

When multiple reps have equal capacity, rotate through them evenly.

def round_robin_select(available_reps, deal_type):
    conn = sqlite3.connect("assignments.db")
    last = conn.execute(
        "SELECT rep_id FROM assignment_log WHERE deal_type = ? ORDER BY created_at DESC LIMIT 1",
        (deal_type,)
    ).fetchone()

    if last:
        rep_ids = [r["rep"] for r in available_reps]
        if last[0] in rep_ids:
            idx = (rep_ids.index(last[0]) + 1) % len(rep_ids)
            return available_reps[idx]["rep"]
    return available_reps[0]["rep"]

What to Build Next

Add performance weighting. Reps with higher close rates on a given deal type should get priority for similar deals.

Related Reading

Want this system built for your business?

Get a free assessment. We will map every system your business needs and show you the ROI.

Get Your Free Assessment

Related Systems