DODIL BLOG
DocsLog inSign up

Modules / CRM

Sales & customer relationships

Who your customers are, what you are trying to sell them, and where each deal stands — shared by the whole sales team instead of living in one person's spreadsheet or inbox.

People ask for it as: “track our customers”, “a sales pipeline”, “stop losing leads”, “who is talking to which client”, “quotes and discounts”, “an app for my sales team”

Who uses it

RoleDoesSees
Sales repworks their own accounts, leads and deals; drafts quotesonly what they own
Sales managersees the whole team's book, reassigns work, owns the forecasteverything in the team
Deal desk / commercial directorapproves quotes above the discount threshold, sets the discount policyevery quote
Marketingruns campaigns, imports lists, reads attributioncampaigns, leads, attribution — not deal amounts unless granted
The systemscheduled and event-driven work — scoring, forecasting, sequences, rollupseverything, through its own service account

What it has to do

Reference user stories. Each has a test written into it — the given / when / then — which becomes an automated check once it is built. Expect to keep some, change some and drop some.

Things people do

  • CRM-01As a sales rep, I want to see only the accounts and deals I own, so that my book is not buried under everyone else's.

    Given reps Tom and Sofia each own accounts · when Tom opens Accounts, or opens one of Sofia's accounts by URL · then he sees only his own; Sofia's returns not found (not forbidden, which would confirm it exists)

    Sales rep · screen: Accounts · reference: partial — crm-suite-app ships the owner_scope helper; wiring it into each owned read is a build step, and many customers choose 'everyone sees everything' instead

    Usually different per customer: whether rows are owned at all — ask, and record the answer

  • CRM-02As a sales rep, I want to log a call or email against a contact in one step, so that the next person who picks up the account knows what was said.

    Given a contact on an account I own · when I log an activity with a subject and a note · then it appears on the contact, the account and the open deal, newest first

    Sales rep · screen: Account · reference: implemented

  • CRM-03As a sales rep, I want to turn a qualified lead into an account, contact and opportunity at once, so that I do not re-type the same company three times.

    Given a lead with a company domain · when I convert it · then one account (reused if the domain already exists), one contact, one opportunity in the first stage; converting again changes nothing

    Sales rep · screen: Lead · reference: implemented

  • CRM-04As a sales rep, I want to move a deal through our stages, so that the pipeline shows where it really is.

    Given an open opportunity in "discovery" · when I move it to "proposal" · then its probability and forecast category follow the stage definition, and the change is visible to my manager immediately

    Sales rep · screen: Pipeline board · reference: implemented

    Usually different per customer: the stage names, their order and their probabilities are the most commonly changed thing in a CRM

  • CRM-05As a sales rep, I want to build a quote from our price book with line discounts, so that the customer gets a consistent price.

    Given an opportunity and an active price book · when I add three products with a 5% discount on one · then the quote totals are computed by the system, not typed, and the quote is a draft

    Sales rep · screen: Quote builder · reference: implemented

  • CRM-06As the commercial director, I want quotes above our discount threshold routed to me, so that margin is protected without chasing approvals by email.

    Given a threshold of 15% and a quote with an 18% effective discount · when the rep submits it · then it is needs_approval, it appears in my queue, and the rep cannot approve it; above the maximum discount it is refused outright

    Deal desk / commercial director · screen: Approvals · reference: implemented

    Usually different per customer: the thresholds, and whether approval is one level or a chain (manager, then director)

  • CRM-07As a sales rep, I want an approved quote to be locked, so that what the customer signed is what finance invoices.

    Given an approved quote · when anyone edits a line · then the edit is refused with a reason, and a new revision must be created instead

    Sales rep · screen: Quote builder · reference: implemented

  • CRM-08As a sales manager, I want to see every open deal across a corporate group on one screen, so that a discount given to one subsidiary is not quoted back to another.

    Given three subsidiaries of one group owned by different reps · when I open any one of them · then I see all three sites' pipeline and past discounts

    Sales manager · screen: Account · reference: implemented

  • CRM-09As a sales manager, I want a weighted forecast by rep and by period, so that I can commit a number to leadership.

    Given open deals with stages and close dates · when I open the forecast for this quarter · then I see open, weighted and committed amounts per rep, and I can override a category with a reason

    Sales manager · screen: Forecast · reference: implemented

  • CRM-12As a sales rep, I want my tasks grouped into overdue, today and this week, so that I start the day knowing what is late.

    Given tasks assigned to me with due dates · when I open Home · then I see counts and lists for overdue, today and this week

    Sales rep · screen: Home · reference: implemented

  • CRM-13As a marketer, I want to import a list of contacts from a spreadsheet, so that a trade-show list becomes leads the same day.

    Given a CSV with name, email and company · when I import it twice · then each person exists once; rows with no email are reported, not silently dropped

    Marketing · screen: Accounts · reference: implemented

  • CRM-14As a sales rep, I want to find customers similar to one we just won, so that I know who to call next.

    Given a won account · when I ask for lookalikes · then I get a ranked list of accounts I can see, excluding existing customers

    Sales rep · screen: Account · reference: implemented

Things that happen on their own

  • CRM-10every 6 hoursThe system re-scores open leads against the current scoring rules, so that the call list reflects this morning's activity rather than last week's.

    Given a lead that opened a pricing email an hour ago · when the next run completes · then its score reflects it, the run is recorded, and running it twice changes nothing

    · reference: route exists (POST /leads/{id}/score); the schedule does not — Ignite has no scheduler

  • CRM-11when a quote is approved or rejectedThe system notifies the rep who submitted it, so that nobody refreshes a queue waiting.

    Given a quote in needs_approval · when the director approves it · then the submitting rep is told, once

    · reference: not implemented — no notification channel in the reference

  • CRM-15nightlyThe system snapshots the forecast, so that "what did we think on the 1st" can be answered at quarter end.

    Given open pipeline · when the nightly run completes · then one snapshot per rep, period and category exists for that date; a re-run replaces it rather than doubling it

    · reference: route exists (POST /forecast/recompute); the schedule does not

  • CRM-16nightlyThe system flags deals that have gone quiet, so that a manager sees risk before the close date passes.

    Given a deal with no activity for 21 days in a late stage · when the nightly run completes · then it is marked at risk with the reason

    · reference: route exists (POST /opportunities/{id}/risk); the rule and schedule are yours

  • CRM-17when a contact is enrolled in a sequence, then on each step's delayThe system sends the next step of an outreach sequence when it is due, and stops when the contact replies.

    Given a contact enrolled in a three-step sequence · when step one's delay elapses · then step one is sent once; a reply stops the enrollment

    · reference: implemented as a polled engine — needs an always-on worker or an external clock

Things that cross into other modules

  • CRM-20when a quote is acceptedThe system creates a draft invoice in Finance for the same customer and amount, so that nothing is re-keyed.

    Given an accepted quote · when Finance opens drafts · then the invoice references the quote and the same business partner; posting it is refused if the period is closed

    · owned by ar · reference: not implemented — requires the AR module

  • CRM-21when a rep opens an accountAs a sales rep, I want to see whether the customer has overdue invoices, so that I do not offer a discount to someone who has not paid.

    Given a customer with an invoice 40 days past due · when I open the account · then I see the overdue amount (read-only), and the quote builder warns me

    · owned by ar · reference: not implemented — and the join does not exist yet either: GL's subledger_items carries a free-text party, not bp_id, so either it gains bp_id or invoicing serves this read from its own route (see ar AR-12)

  • CRM-22when a new company is createdThe system creates the company once in the shared customer master, so that finance and sales mean the same customer.

    Given business-partner is installed · when a rep converts a lead for a new domain · then a business partner exists (created or reused), and the CRM account points at it

    · owned by business-partner · reference: implemented (POST /partners/promote)

How things move

lead

new → working → qualified → disqualified → converted

  • new → working by rep
  • working → qualified by rep or system · when score >= policy.threshold_qualify
  • new / working → disqualified by rep · needs reason
  • qualified → converted by rep · creates account + contact + opportunity (CRM-03)

opportunity

defined per customer in pipeline_stages (name, order, probability, forecast category, won/closed flags)

  • any open → any open by rep or manager
  • any open → closed_won by rep · customer_varies: often creates the order/invoice (CRM-20)
  • any open → closed_lost by rep · needs loss_reason

quote

draft → needs_approval → approved → rejected → accepted → expired

  • draft → approved by system · when effective discount <= approval_threshold_pct
  • draft → needs_approval by system · when approval_threshold_pct < discount <= max_discount_pct
  • draft → rejected by system · when discount > max_discount_pct
  • needs_approval → approved / rejected by deal_desk
  • approved → accepted by rep · locked (CRM-07); triggers CRM-20
  • draft / approved → expired by system · when valid_until passed

task

open → done → cancelled

  • open → done / cancelled by assignee or manager
  • done / cancelled → open by assignee or manager

What it keeps

ThingMeaningIdentified byShared?
accounta company you sell to (one row per site/legal entity)org_domain in the reference; bp_id when business-partner is installedreferences business_partner
contacta person at an accountemailmodule-owned
leada person or company not yet worked into a deallead_id (derive it from email or domain so a re-import is idempotent)module-owned
opportunitya specific deal you are trying to winopportunity_idmodule-owned
activitya call, email, meeting or noteactivity_idmodule-owned
pipeline stageone step of YOUR sales process, as datapipeline:namemodule-owned (configuration)
productsomething you sellproduct_id (or SKU)SHARED — sales quotes it, invoicing bills it, purchasing buys it
price booka price list for a currency/region, with per-product pricesprice_book_id; entry_idmodule-owned
quotea priced offer with linesquote_id; quote_line_idmodule-owned
discount policythe thresholds that decide what auto-approvespolicy_idmodule-owned (configuration; changing it is a management act)
lead scorehow good a lead is, and why (BANT or MEDDIC)lead_idmodule-owned (derived)
campaigna marketing push, its members and touchpointscampaign_id; member_id; touchpoint_idmodule-owned
taska to-do for a person, attached to any recordtask_idmodule-owned (a candidate for a shared "work" module later)
forecast snapshotthe forecast as it stood on a datesnapshot_idmodule-owned (derived)
sequence (optional)an automated outreach cadenceflow_id; step_id; enrollment_idmodule-owned

The most expensive mistake is a CRM-only customer list. If invoicing or purchasing is on the roadmap at all, install business-partner first and let CRM reference it.

What runs on its own

StoryWhenWhat
CRM-10every 6 hoursre-score open leads
CRM-15nightlyPOST /forecast/recompute
CRM-16nightlyrisk rule over late-stage opportunities
CRM-17continuous (per-step delays)sequence engine
CRM-11on quote decisionnotify submitter

Questions that shape your version

Read these out and let the customer correct one — people rarely recall a policy on demand and can always react to one. Standard is a named authority you can look up and hold us to. Commonly seen is exactly that: arrangements we have met, with no survey behind them. A customer doing none of them is not doing it wrong.

  1. What are the steps of your sales process, and how likely is a deal to close at each?
    b2b considered sale
    qualify, discovery, proposal, negotiation, closed — five or six stages
    transactional
    two or three: enquiry, quote, won
    warning
    a stage nobody can define the EXIT criteria for is a stage that will not be updated
  2. Who can give what discount, and who approves above that?
    common
    a rep discounts to ~10%, a manager to ~25%, anything beyond needs the owner
    note
    the numbers matter less than there being exactly one threshold per approver
  3. Does each rep only see their own customers, or does everyone see everything?
  4. Do you sell to groups of companies (parents and subsidiaries)?
  5. Do you send quotes and invoices from this system, or elsewhere?
  6. What do you use today, and what must come across on day one?
  7. Do you run marketing campaigns or outreach sequences?
  8. How do you qualify a lead?
    smaller teams
    budget, authority, need, timing (BANT) — four fields on the lead
    enterprise
    MEDDIC, because the economic buyer and the paper process are the risk
    self serve
    usage or firmographic score, not a questionnaire

What you can change yourself

These are settings, not code: someone in your team changes them on a screen, without a developer and without a release.

For builders

Known gaps in the reference

© 2026 DODILHomeDocsConsole