Sales Operations ⚙️
Valstorm was built by a Software Engineer who specialized in developing the processes and tools for Sales Operations teams. On this page, we'll break down what we've learned about Sales Operations over the years and how you can apply those principles to your team, regardless of whether you're using Valstorm or competing tools.
The Brain of Sales Operations - Your CRM
A Customer Relationship Management (CRM) system is the backbone of any Sales Operations team. It stores all your customer data, tracks interactions, and helps manage your sales pipeline. Popular CRMs include Salesforce, HubSpot, and Zoho CRM. Valstorm also developed its own CRM, ValRM.
We won't focus on a specific CRM here, but rather on the general principles that apply to any CRM you choose. Regardless of your industry, these are the principles to follow.
What should the CRM actually do?
At its core, a CRM should help you manage your relationships with customers and prospects. This includes:
- Storing contact information (Leads, Contacts, Companies)
- Tracking interactions (calls, emails, meetings)
- Managing pipelines for different teams (sales, marketing, service, legal, etc.)
- Reporting and analytics to measure performance
- Automating as much of the above as possible
The truth is, while Salesforce and HubSpot can do all this, they often require heavy configuration. When you first purchase a major CRM, it can feel like a glorified spreadsheet that needs multiple apps and skilled consultants to become truly useful. HubSpot is easier to use out of the box but is often limited to marketing, while sales and service teams gravitate toward Salesforce.
Why We Harp on Configuration
Valstorm started as a consulting company. We've been there and done that. We've built custom CRMs for clients in various industries and have seen the pitfalls of improper configuration.
Following the plan laid out in this document will empower your team to spend far more time moving deals along and working with customers.
Understanding Objects and Records
CRMs are built around the concept of objects and records.
- An object is a type of data, such as a Lead, Contact, Company, or Opportunity.
- A record is a specific instance of that object, such as "John Doe" (a Contact record) or "Acme Corp" (a Company record).
Understanding that an object is just the best way to represent a category of data is crucial. As your team and departments grow, you will need to use more of them.
Leads Generate Opportunities, Opportunities Generate Revenue 💰
A lead is a person or company you can contact about a potential business operation. While leads can be used in marketing and service for partnerships or referrals, we will focus on the sales cycle.
A Lead has two outcomes: Qualified or Disqualified. If disqualified, they are no longer pursued. If a lead isn't ready now but might be in the future (e.g., in two years when your average deal cycle is one), they should be put On Hold and re-engaged later.
Once a lead is qualified, it converts into an opportunity, which is a potential sale tracked through your pipeline until it is either Won (resulting in revenue) or Lost.
The Core Data Model: Leads, Contacts, Companies
A common pitfall is treating leads as contacts. These objects should be separate entities in your CRM to properly track a prospect's journey.
- Companies: The organizations your contacts work for. Think of these as the umbrella.
- Contacts: Unique individuals who exist in the world, regardless of their employer or whether they are a current lead. A contact is a real person.
- Leads: Potential business prospects. A lead is linked to a Contact or a Company. A single Contact can have multiple leads associated with them over time.
This structure allows you to track a person's entire history with your business, even across different jobs or multiple purchase cycles.
Data Hygiene is Key 🔑
This process should be automated to prevent duplicate records, which can wreak havoc on your communication systems and metrics.
- If you have two contacts with the same email, who receives the message?
- If you have two opportunities with the same name, which one do you track?
This can be simplified by ensuring Contacts are unique.
- Lead to Contact: When a new lead comes in, check if a Contact already exists with the same email or phone number. If yes, link the new lead to the existing contact. If no, create a new contact.
- Prevent Duplicate Contacts: When a user tries to create a new contact, check if one already exists with the same email or phone number. If so, prevent creation and alert the user.
- Company Logic: Apply the same logic for companies, checking for duplicates based on name, address, or phone number before creating a new company record.
With this system, communications like calls, texts, and emails can all link to the right person and company, ensuring your metrics are accurate and your automation is reliable.
The Sales Team Should Live and Breathe Tasks ✅
Tasks are actionable steps. Many teams hate them because their completion isn't automated, turning them into ignored reminders. When set up correctly, the team should be able to follow tasks without much thought, performing the right action at the right time.
- Call the lead tomorrow. When you make the call, the task is automatically completed.
- Send a follow-up email next week. When you send the email, the task is automatically completed.
- Build a quote for the lead. When you send the quote, the task is automatically completed.
The goal is to ensure that all tasks, whether related to a lead, contact, or opportunity, are completed the day they are due. A systematic approach to tasks keeps your pipeline moving forward.
Structuring Your Lead Pipeline
Moving leads through a sales pipeline involves a few key stages that apply to almost any industry.
- New Lead: A lead has been identified but not yet contacted.
- Attempted Contact: The team has tried to contact the lead without a response. This status should be set automatically when your team calls, texts, or emails.
- Engaged: The lead has responded. This status should also be set automatically upon their reply.
- Nurture: The lead is interested but not yet ready to buy. This is a good time for marketing to step in with re-engagement campaigns or for a team member to add a human touch.
- Disqualified: The lead is not a fit or is not interested.
- Qualified: The lead has expressed serious interest and appears able to buy. It's time to generate an Opportunity!
For more detail, use a Stage Reason field. A lead might be in the Nurture stage for different reasons like Budget, Timing, or Researching. Use these reasons to further classify and automate your lead follow-up.
Using Opportunities
Opportunities are the next step after a lead is qualified. This is where the real sales process begins. An opportunity is the brain of the sale and should be linked to other objects like quotes, proposals, and contracts.
When should you convert a Lead to an Opportunity?
Convert a Lead once you identify that:
- They are a real person or company.
- They have the ability to buy.
- What you offer is a fit for their needs.
How to Structure Opportunities
While lead stages are fairly standard, opportunity pipelines can vary widely. Here are some general principles:
- Define Clear Stages: Create stages that reflect your actual sales process (e.g., Prospecting, Qualification, Proposal, Negotiation, Closed Won, Closed Lost).
- Use Stage Reasons: Further classify why an opportunity is in a certain stage for better reporting.
- Automate Actions: Trigger actions based on stage changes. For example, when an opportunity moves to "Proposal," automatically send a follow-up email with the proposal attached.
- Assign Team Roles: Attach team members to the Opportunity with their specific role in the deal to ensure accountability.
- Link Related Objects: Keep all quotes, contracts, and orders linked to the opportunity for a single source of truth.
Key Automations to Implement
Let's actually talk about some specific automations you should implement in your CRM to streamline sales operations. This will be broken down by object type since that majorly changes the process.
Lead Management
- Auto-Assign Leads: Distribute new leads to sales reps based on:
- Availability first! Your system should be real time, checking who is available at the moment a lead comes in to engage them. This is crucial for inbound leads.
- Lead Quality second! If you have a lead scoring system, use it to assign higher-quality leads to your best reps.
- Round Robin last! If neither of the above criteria apply, use a round-robin system. This should focus on balancing workload, not just cycling through names.
- Duplicate Prevention: Automatically check for existing contacts or companies before creating new records.
- Follow-Up Reminders: Automatically create follow-up tasks if a lead hasn't been contacted within a set timeframe (e.g., 24 hours).
- Status Updates: Automatically update lead status based on interactions (e.g., if a lead responds to an email, change status to "Engaged").
Lead Status Automations
Assume we have the following lead statuses:
- New
- Attempted Contact
- Engaged
- Nurture
- Disqualified
- Qualified
- New to Attempted Contact: When a lead is created, automatically set status to "New". When a sales rep makes the first contact attempt (call, email, text), automatically update status to "Attempted Contact".
- Attempted Contact to Engaged: If the lead responds to any communication (reply to email, answer call, respond to text, joins a meeting), automatically update status to "Engaged".
- Engaged to Nurture: If the lead expresses interest but is not ready to buy (e.g., says "not right now" or "need more info"), automatically update status to "Nurture".
- Engaged to Disqualified: If the lead indicates they are not interested or is not a fit (e.g., "not our target market"), automatically update status to "Disqualified".
- Nurture to Qualified: If the lead indicates they are ready to buy, requests a proposal or books a meeting then automatically update status to "Qualified".
- Qualified to Opportunity: When a lead is converted to an opportunity, automatically update status to "Qualified".
Automating the transitions between these statuses based on real-world interactions is key to maintaining a clean pipeline and ensuring timely follow-ups.
Here are some Valstorm record trigger examples to automate these status changes.
1. New to Attempted Contact
This After Create trigger on a Communication object (like a Call or Email) checks if the related lead is "New." If so, it updates the lead's status.
# Trigger on: Communication Object - After Create
from valstorm.dependencies import add_log, valstorm_client
def execute(new_data: list, current_user, **kwargs):
try:
lead_id = new_data[0].get('lead_id')
if not lead_id:
return new_data
# Fetch the related lead record
lead = valstorm_client.get_record('leads', lead_id)
# If the lead's status is 'New', update it
if lead and lead.get('status') == 'New':
valstorm_client.update_record('leads', lead_id, {'status': 'Attempted Contact'})
add_log(f"Lead {lead_id} status updated to Attempted Contact.", 'info')
except Exception as e:
add_log(f"Error in New to Attempted Contact trigger: {e}", 'error')
return new_data
2. Attempted Contact to Engaged
This After Update trigger on a Communication object fires when a response is logged. It then updates the lead's status to "Engaged."
# Trigger on: Communication Object - After Update
from valstorm.dependencies import add_log, valstorm_client
def execute(new_data: list, old_data: list, current_user, **kwargs):
try:
# Check if the 'responded' flag was just changed to True
if new_data[0].get('responded') and not old_data[0].get('responded'):
lead_id = new_data[0].get('lead_id')
if lead_id:
valstorm_client.update_record('leads', lead_id, {'status': 'Engaged'})
add_log(f"Lead {lead_id} status updated to Engaged.", 'info')
except Exception as e:
add_log(f"Error in Attempted Contact to Engaged trigger: {e}", 'error')
return new_data
3. Engaged to Nurture/Disqualified/Qualified
This After Update trigger on the Lead object itself manages the next steps. It checks for changes in specific fields to determine the correct new status.
# Trigger on: Lead Object - After Update
from valstorm.dependencies import add_log, valstorm_client
def execute(new_data: list, old_data: list, current_user, **kwargs):
lead = new_data[0]
previous_lead = old_data[0]
lead_id = lead.get('id')
try:
# Only proceed if the lead was 'Engaged'
if previous_lead.get('status') != 'Engaged':
return new_data
new_status = None
# Logic to move to Nurture
if lead.get('nurture_reason') and not previous_lead.get('nurture_reason'):
new_status = 'Nurture'
# Logic to move to Disqualified
elif lead.get('disqualification_reason') and not previous_lead.get('disqualification_reason'):
new_status = 'Disqualified'
# Logic to move to Qualified (e.g., a meeting is booked)
elif lead.get('meeting_booked_date') and not previous_lead.get('meeting_booked_date'):
new_status = 'Qualified'
if new_status:
valstorm_client.update_record('leads', lead_id, {'status': new_status})
add_log(f"Lead {lead_id} status updated to {new_status}.", 'info')
except Exception as e:
add_log(f"Error in Engaged status change trigger: {e}", 'error')
return new_data