Why Generic ERP Advice Breaks SaaS Companies
Most ERP guides treat every business like a widget company. Buy raw materials, manufacture finished goods, ship them to a customer, invoice once, collect payment, done. If that is the universe an ERP was designed for, then a SaaS company is an alien planet. Your inventory is zero. Your cost of goods sold is mostly compute and headcount. Your revenue is a recurring promise spread across 12 to 36 months of future deliverables. Your customers do not "receive goods" — they log in, consume, upgrade, downgrade, pause, cancel, churn, reactivate, and occasionally call support at 2am.
At Octura Solutions, we are an Odoo Ready Partner that also runs our own SaaS products, so this is not theory for us. We have lived the monthly close for a recurring-revenue business, we have debugged deferred revenue schedules that did not tie to Stripe, and we have watched finance teams try to calculate ARR from a general ledger that was never designed to tell them. This guide is the playbook we wish existed when we started — a field-tested blueprint for implementing Odoo as the saas erp of record for a modern subscription business.
Over the next 4,000 words we will cover the operational requirements unique to SaaS, the Odoo modules that actually deliver on them, how to track MRR, ARR, churn, LTV, and CAC inside Odoo itself, a deep-dive on Stripe integration including webhooks and dunning, a composite case study of a $4M ARR company that consolidated its stack, and transparent US/Canada pricing for a 10-user implementation. If you are evaluating whether Odoo can be your subscription business erp, this guide answers the question with specifics.
The Unique Operational Requirements of a SaaS Business
Before picking tools, get honest about the problems. A SaaS finance and operations stack has to solve a set of problems that traditional ERPs were never designed for. Every one of the items below is a line item your implementation must address, either natively or through configuration. If your consultant shrugs at any of these, they are the wrong partner.
Recurring Billing and Proration
Customers do not sign up on the first of the month. They sign up on the 14th, upgrade on the 22nd, add three seats on the 28th, and expect a single invoice that cleanly prorates every change. Your system needs to compute partial-period charges to the cent, handle mid-cycle plan changes, and keep the next billing date stable regardless of mid-period activity. Odoo's Subscriptions module handles this natively once the plan templates are configured correctly — we cover the details below.
Revenue Recognition Under ASC 606
Under ASC 606 (IFRS 15 for our Canadian and international readers), you cannot recognize subscription revenue at the moment you invoice. A $12,000 annual contract invoiced on April 1 has to be recognized at $1,000 per month for twelve months, with the uninvoiced portion sitting in a deferred revenue liability account. Multiply that across hundreds of contracts with different start dates, mid-term upgrades, and partial refunds, and you have a reconciliation nightmare — unless your saas accounting system handles revenue schedules automatically. Odoo 18+ supports automated deferred revenue schedules at the invoice line level, which is the correct architecture for this problem.
Churn Math That Finance and Go-to-Market Both Trust
Gross churn, net churn, logo churn, revenue churn, cohort churn — each answers a different question. A CFO cares about net dollar retention because it drives valuation. A VP of Customer Success cares about logo churn because it measures the team's performance. A head of product cares about cohort churn because it reveals onboarding gaps. Your ERP needs to produce these numbers from a single source of truth so that finance, CS, and product stop arguing about whose spreadsheet is right.
MRR, ARR, LTV, and CAC Without a Spreadsheet Army
The four letters that run a SaaS company. MRR (monthly recurring revenue) is the normalized contract value per month. ARR is MRR times twelve, with the caveat that you only count committed recurring revenue, not one-time fees. LTV (lifetime value) is gross profit per customer divided by churn rate. CAC (customer acquisition cost) is fully-loaded sales and marketing spend divided by new customers won. An ERP that requires you to export CSVs and reconstruct these in Excel every month is not a SaaS ERP — it is an accounting system with aspirations.
Dunning for Failed Payments
Roughly 5-10% of recurring charges fail on the first attempt, mostly from expired cards, insufficient funds, or issuer declines. If you do not retry intelligently and email the customer before you churn them, you lose revenue that was not actually churn — it was involuntary churn, and it is recoverable. A mature SaaS stack defines a dunning sequence: retry on days 1, 3, 5, and 7 with escalating emails, then pause service on day 14. Odoo's payment provider layer plus a small automation module delivers this out of the box.
Multi-Tier Plans and Feature Gates
Starter, Growth, Scale, Enterprise. Per-seat, per-feature, per-usage. Every SaaS eventually lands on a pricing matrix with at least three tiers and several add-ons. Your ERP needs to represent these as subscription templates with discrete product lines, and your app needs to read entitlements from a source — Odoo's Product and Subscription models are a perfectly acceptable source of truth if you expose them through a small internal API.
Usage Metering
Even tier-based SaaS products often have a metered dimension — API calls, AI tokens, seats, GB stored, messages sent. Usage must be captured in your application, aggregated daily, and pushed into Odoo so it can be invoiced at the end of the billing period. Odoo 18+ supports usage-based pricing via the product.template "type = service" plus a custom subscription.usage line ingestion, or through direct billing in Stripe synced back to Odoo invoices. Either pattern works; the choice depends on whether Stripe or Odoo is your billing system of record.
Where does billing live — Stripe or Odoo? If Stripe is your billing system of record, Odoo becomes a downstream ledger that syncs invoices and revenue schedules from Stripe. If Odoo is your billing system of record, Stripe is just a payment processor. Both architectures work. Pick one on day one and never confuse the teams about which system tells the truth.
The Critical Odoo Modules for a SaaS Implementation
Odoo ships with 40+ official apps. A SaaS implementation does not need all of them. Below is the tight stack we deploy for subscription businesses, with the role each module plays and the configuration gotchas we have learned from real projects.
Subscriptions — The Heart of the Stack
The Subscriptions module (sale_subscription in Odoo source) is where recurring billing lives. A Subscription record links a customer to one or more recurring product lines with a billing cadence (monthly, quarterly, annual), a payment method, and an automatic renewal policy. When the next invoice date arrives, a scheduled action generates the invoice, charges the stored payment method via the configured payment provider, and updates the subscription's next renewal date.
Configure subscription templates per plan: one template per pricing tier, with the recurrence, invoicing email sequence, and automatic payment behavior set at the template level. The critical field is recurring_rule_type — monthly, yearly — and recurring_interval, which multiplies the rule. For a monthly plan, rule type is monthly and interval is 1. For a plan billed every 3 months, rule type is monthly and interval is 3. Get this wrong and you will bill annual customers every month.
Invoicing and Accounting with Deferred Revenue
The Accounting module (Enterprise) is the ledger where all subscription invoices land. The configuration that matters most for SaaS is enabling automatic deferred revenue on the subscription product templates. Set the product's Income Account to a deferred revenue liability account (for example, 2400 — Deferred Revenue), and set the Deferred Revenue Method to Monthly with a duration matching the subscription length.
With that configuration, every invoice line automatically creates a deferred revenue schedule: the invoice posts to 2400 Deferred Revenue on the credit side, and a scheduled journal entry reclassifies 1/N of the amount to 4000 Subscription Revenue on the first of each month for the duration of the contract. Your balance sheet shows accurate liability. Your P&L shows accurate revenue. Your auditor shows up at year-end and goes home in an hour.
CRM — The Pipeline Before the Subscription
Before someone becomes a subscription, they are a lead, then an opportunity. The CRM module tracks the pre-sale pipeline. For SaaS, configure pipeline stages that mirror your funnel: Lead, Demo Scheduled, Demo Completed, Trial Started, Proposal Sent, Closed Won, Closed Lost. The winning pattern: when an opportunity is closed-won, a server action auto-creates the subscription from a template tied to the opportunity's won product, and the CRM record is linked to the new subscription via origin.
Sales with Subscription Templates
The Sales module bridges CRM and Subscriptions. A sales quotation contains a subscription template line; when the quote is signed (via the Odoo eSign integration or a portal acceptance), the quote is confirmed, a subscription is created from the template, and the first invoice is emitted. This is the natural flow for B2B SaaS with contracts; for self-serve PLG signups, you bypass Sales and create the subscription directly from the signup form.
Website and Customer Portal
The Website module powers your marketing site and product pricing pages. The Portal gives authenticated customers a self-service area where they can view invoices, update payment methods, download receipts, upgrade or downgrade plans, and cancel. Do not underestimate the portal — a well-configured portal deflects 40-60% of billing-related support tickets. The one customization we always apply: replace the default portal "Cancel" action with a two-step flow that surfaces a retention offer before confirming cancellation.
Helpdesk — The Support Layer
Helpdesk handles inbound customer support tickets. For SaaS, configure a team per product with SLA policies that differentiate by plan tier — Enterprise gets a 2-hour first response, Growth gets 8 hours, Starter gets 24. The SLA clock reads the customer's subscription tier directly, so there is no manual classification. Tie Helpdesk to the customer record so that every ticket agents open shows the customer's MRR, plan, payment status, and recent invoices in the sidebar. Context makes support faster.
Marketing Automation — The Lifecycle Layer
Marketing Automation runs your lifecycle email campaigns: welcome sequences, trial nurture, onboarding milestones, renewal reminders, cancel win-back. Segment campaigns use the subscription state and MRR bands as filters, so a "renewal at risk" campaign can target every subscription where next renewal is in 30 days, MRR is above $500, and last login was more than 14 days ago. The segmentation surface is the same object graph your finance team queries — one source of truth for both GTM and finance.
Optional but Recommended: Documents, Sign, Project
Documents stores signed MSAs and DPAs tied to the customer. Sign handles the MSA signature flow at close. Project runs customer onboarding and implementation projects for higher-touch plans. These are not strictly required but they remove three more point tools from your stack.
| Odoo Module | SaaS Role | Edition | Must-Have? |
|---|---|---|---|
| Subscriptions | Recurring billing engine | Enterprise | Yes |
| Accounting | Deferred revenue, close, reporting | Enterprise | Yes |
| Invoicing | Invoice generation, payment capture | Enterprise / CE | Yes |
| CRM | Pre-sale pipeline | Enterprise / CE | Yes |
| Sales | Quote-to-subscription flow | Enterprise / CE | Yes |
| Website + Portal | Marketing site and self-service | Enterprise / CE | Yes |
| Helpdesk | Customer support with SLA | Enterprise | Yes |
| Marketing Automation | Lifecycle campaigns | Enterprise | Strong yes |
| Documents + Sign | Contract storage + eSignature | Enterprise | Optional |
Tracking SaaS Metrics Inside Odoo (MRR, ARR, Churn, LTV, CAC)
The reason most SaaS teams believe Odoo cannot do saas metrics odoo is that they never configured the analytic layer. Out of the box, Odoo's subscription module ships with a dashboard showing MRR, churn, and ARR — but the numbers only match reality once analytic accounts, tags, and cohort definitions are set up correctly.
MRR and ARR via Analytic Accounts and Tags
Every subscription line carries a recurring_monthly field that normalizes the line's value to a monthly figure regardless of billing frequency. Sum recurring_monthly across all active subscriptions and you have MRR. Multiply by 12 and you have ARR. To break MRR down by plan, country, cohort, or product line, tag every subscription product with analytic tags: plan:growth, country:us, channel:organic, cohort:2026-q1. Then build a pivot view on sale.subscription grouped by the tags you care about.
For the ARR waterfall (new, expansion, contraction, churn), create a subscription change log model that captures every MRR-moving event with a type and delta. A server action on the subscription write() method emits a row into this log every time recurring_total changes. The log becomes your waterfall view, broken down by month.
Churn Cohorts via BI Dashboards
Cohort churn analysis requires grouping customers by signup month and measuring what percentage remains active N months later. Odoo's native Dashboards module (Enterprise) supports cohort pivots natively: set the row axis to subscription start date grouped by month, the column axis to months since start, and the measure to count(active subscriptions). The resulting triangle is your retention curve — paste it straight into a board meeting.
For deeper analysis, connect Odoo to a BI tool (Metabase, Superset, Lightdash) via the PostgreSQL read replica. A 40-line SQL query against sale_subscription and account_move produces cohort retention, net dollar retention, and expansion MRR broken down by any dimension. We maintain a reference repo of SaaS SQL patterns for Odoo's schema that we share with implementation clients.
LTV and CAC via Google Ads and CRM Attribution
LTV is gross profit per customer divided by gross churn rate. Gross profit per customer is average MRR times (1 minus COGS-as-percent-of-revenue) times 12 divided by churn rate. Odoo has every input: MRR per customer lives on the subscription, COGS lives in the accounting chart (cloud infrastructure, payment fees, support costs allocated per customer), churn lives in the subscription state transitions.
CAC is trickier because it requires attribution. Connect Odoo's CRM to Google Ads (and LinkedIn Ads, Meta Ads) via UTM capture: every lead record stores the utm_source, utm_medium, and utm_campaign from the landing page form submission. When a lead converts to a subscription, the CRM's source tag flows through to the subscription, and CAC = ad spend per campaign divided by closed-won subscriptions tagged with that campaign. Odoo's UTM module is CE-available and does exactly this when you connect it to the website forms module.
PQL Lead Scoring
A Product-Qualified Lead (PQL) is a self-serve trial user whose product behavior indicates they are ready to pay. PQL scoring is a weighted sum of in-app signals: number of seats invited, number of core actions taken, days since signup, feature activation milestones, etc. To drive PQLs from your SaaS app into Odoo CRM, expose a scoring endpoint from your app and have Odoo poll it daily, or push events into Odoo via an internal API. When a PQL score crosses a threshold, a CRM opportunity is created with the user's account and assigned to an AE. Odoo's crm.lead has a probability field that is perfect for storing the score.
Odoo's out-of-the-box MRR dashboard counts MRR from subscription lines, not from recognized revenue. If a customer is on a paid plan but their payment has failed and they are in dunning, the dashboard still counts their MRR as active until the subscription is closed. Reconcile the dashboard against the deferred revenue rollforward monthly so you know how much "MRR" is actually collectible.
Stripe Deep-Dive: Webhooks, Subscription Sync, Dunning, and Stripe Tax
Stripe is the default payment processor for 80%+ of the SaaS companies we work with. Odoo's Stripe payment provider handles one-time and recurring card capture out of the box, but a production SaaS deployment needs more than "the card charged." You need bi-directional sync of subscription state, webhook-driven failure handling, automated dunning, and tax calculation across jurisdictions.
Architecture: Who Owns the Subscription
Pick one: Odoo owns the subscription, Stripe is the payment processor. Or Stripe owns the subscription (via Stripe Billing), Odoo syncs invoices from Stripe. In our deployments we prefer Odoo as source of truth because it keeps revenue recognition, accounting, and subscription state in one system. Odoo creates the Stripe Customer and PaymentMethod via the API, then charges the card on each recurring invoice through the payment provider.
Webhook Handling
Even with Odoo as the subscription master, Stripe still emits webhooks for events Odoo must react to: charge.succeeded, charge.failed, payment_method.detached, customer.subscription.deleted (if you use Stripe-side subscriptions for self-serve), and invoice.payment_failed. Expose a webhook endpoint on your Odoo instance at /payment/stripe/webhook (Odoo's Stripe module registers this route already; extend it to dispatch custom event types). Verify the Stripe signature on every inbound request; reject any request without a valid signature header.
Payment Failures and the Dunning Flow
When a recurring charge fails, Stripe emits invoice.payment_failed. Your webhook handler should update the subscription state to payment_failed, queue a retry at day 1, day 3, day 5, and day 7, and send an escalating email sequence from Marketing Automation (reminder, urgent, final notice). After the fourth failed retry, transition the subscription to past_due, revoke app access via an API call back to your SaaS, and move to the win-back sequence. This flow recovers 40-60% of failed charges in our deployments — money that would otherwise churn silently.
Stripe Tax for US/Canada Nexus
US sales tax for SaaS is a mess: 25+ states tax SaaS, each with its own economic nexus threshold, and the list changes every year. Canadian GST/HST/PST adds a second compliance layer. Stripe Tax calculates the correct tax per transaction based on the customer's billing address and your nexus footprint. In Odoo, enable the Stripe Tax integration: every invoice is sent to Stripe's tax API, tax is calculated and returned, and the invoice posts with the correct tax lines to the correct liability accounts. You still file returns via Stripe's registration partners or a third party (TaxJar, Avalara), but the calculation and audit trail live in Odoo.
from odoo import models
from odoo.http import request
import stripe, logging
_logger = logging.getLogger(__name__)
class StripeController(models.AbstractModel):
_inherit = 'payment.provider'
def _handle_stripe_payment_failed(self, payload):
invoice_id = payload['data']['object']['metadata'].get('odoo_invoice_id')
if not invoice_id:
return
invoice = self.env['account.move'].browse(int(invoice_id))
subscription = invoice.subscription_id
if not subscription:
return
# Transition to dunning
subscription.write({'stage_id': self.env.ref(
'sale_subscription.stage_payment_failed').id})
# Queue retries via cron (day 1, 3, 5, 7)
self.env['sale.subscription.dunning'].create({
'subscription_id': subscription.id,
'invoice_id': invoice.id,
'attempt': 1,
'next_retry': fields.Datetime.now() + timedelta(days=1),
})
# Trigger Marketing Automation sequence
self.env['marketing.campaign'].search([
('tag_ids.name', '=', 'dunning_sequence'),
]).action_trigger(subscription.partner_id)
_logger.warning(
"Dunning started for subscription %s (invoice %s)",
subscription.code, invoice.name,
)Case Study: A $4M ARR B2B SaaS Consolidates Onto Odoo
The following is a composite case drawn from several real engagements. Details are anonymized and blended to protect client confidentiality, but every number is drawn from actual implementations we have run.
The company: a 20-user B2B SaaS at $4M ARR, selling a workflow automation product to mid-market finance teams. Revenue mix: 60% annual contracts paid upfront, 40% monthly. Three pricing tiers, usage-metered API add-on, multi-seat with per-seat pricing.
The before stack: Chargebee for subscription billing ($599/mo), QuickBooks Online for accounting ($200/mo), HubSpot CRM Pro ($1,600/mo), Zendesk Support ($1,140/mo), ChartMogul for SaaS metrics ($500/mo), Zapier glue ($420/mo). Monthly spend roughly $4,460, or $53,500/yr. Close cycle: 8 business days. Close pain: the finance team exported CSVs from Chargebee, reconciled to QuickBooks by hand, emailed MRR numbers from ChartMogul that never tied to QuickBooks revenue, and debugged Zapier failures between HubSpot and QuickBooks for 4-6 hours every month.
The migration: 10 weeks, $48K implementation. We moved subscriptions and customer payment methods from Chargebee to Odoo Subscriptions (exporting via Chargebee API, importing via sale.subscription create, re-attaching Stripe customers via the existing cus_* IDs). We mapped QuickBooks chart of accounts to Odoo's chart, migrated three years of GL history via the bank statement import, and rebuilt revenue recognition schedules from the contract-level deferred balance. HubSpot contacts and pipeline moved into Odoo CRM with a custom ETL. Zendesk tickets archived to read-only, new tickets landed in Odoo Helpdesk.
The after stack: Odoo Enterprise (20 users), Stripe ($0/mo base), domain and hosting. Monthly software cost roughly $500. Annual savings: $53,500 minus $6,000 = $47,500/yr on software, plus 20 hours/month of reclaimed finance time. Close cycle went from 8 days to 2 days because revenue recognition, cash application, and subscription metrics all lived in the same database. ARR, net retention, and cohort churn were queryable in a single dashboard instead of three different tools.
Pricing: What a 10-User SaaS Odoo Implementation Costs in 2026
For a 10-user SaaS company migrating from a Chargebee/QuickBooks-style stack, a typical Odoo implementation runs $28,000 to $55,000 and takes 8 to 12 weeks. The range depends on contract complexity (more tiers, more usage metrics, more custom pricing rules push the number up), historical data migration depth (three years of invoices takes longer than one), and integration count (Stripe alone is cheap; Stripe + Salesforce + Slack + a custom PLG app is not).
Odoo Enterprise licensing for 10 users is roughly $300/user/month list, often discounted to $240-270 through a Ready Partner like us. That is $2,400-3,000/month in licensing on top of implementation. For a complete breakdown with Community edition comparisons and hosting options, see our Odoo Pricing 2026 guide. For international or multi-entity setups, also review Multi-Currency Accounting in Odoo 19.
Frequently Asked Questions
Odoo is a full ERP with native subscription billing, deferred revenue, CRM, helpdesk, marketing automation, and a website portal. For a SaaS business, it replaces the Chargebee + QuickBooks + HubSpot + Zendesk + ChartMogul stack with a single database. It is a real saas erp, not an accounting system with bolt-ons.
Yes, via the Deferred Revenue feature on product templates. Set the product's income account to a deferred revenue liability and choose monthly deferral; every invoice line auto-generates a revenue schedule that reclassifies to revenue over the contract term. It is ASC 606 compliant when configured correctly.
Chargebee is a specialist billing platform with slightly more out-of-the-box billing features (complex coupons, revenue recognition exports, multi-subscription hierarchies). Odoo's Subscriptions module covers 90% of those features and comes bundled with accounting, CRM, support, and marketing. For SaaS under $20M ARR, Odoo consolidates better and costs less.
Yes. The Subscriptions dashboard shows MRR, ARR, churn, and net retention natively. Tagging products with analytic tags (plan, country, cohort) gives you dimensional breakdowns. For deeper cohort and retention analysis, connect a BI tool (Metabase, Superset) to the Postgres read replica and query subscription state transitions directly.
Odoo ships an official Stripe payment provider that handles card capture, tokenization, recurring charges, 3DS authentication, and webhook ingestion. For SaaS you extend it with custom webhook handlers for dunning, subscription sync, and Stripe Tax calculation. See the Stripe section above for the full architecture.
Yes, and we recommend it for most SaaS businesses. Odoo owns the subscription, generates invoices, computes tax, and stores the customer. Stripe is called at charge time via the payment provider, and its webhooks are used for failure handling. Accounting, revenue recognition, and reporting all live in Odoo.
Stripe Tax integrates with Odoo to calculate SaaS sales tax across 25+ US states and Canadian GST/HST/PST. Each invoice is sent to Stripe Tax for calculation, the returned tax amount posts to the correct liability accounts, and the audit trail stays in Odoo. You still file returns via Stripe registrations or Avalara/TaxJar.
8 to 12 weeks for a 10-user SaaS with a standard stack migration (subscriptions from Chargebee, accounting from QuickBooks, CRM from HubSpot). More complex pricing, multi-entity structures, or custom integrations can push it to 16 weeks.
Odoo supports usage-based billing via subscription usage lines: your SaaS pushes metered units (API calls, tokens, GB, seats) into Odoo daily, and at invoice time the subscription adds a metered line priced at your per-unit rate. Alternatively, use Stripe metered billing and sync invoices back to Odoo as accounting records.
Yes. As an Odoo Ready Partner that also runs our own SaaS products, Octura Solutions offers a free 45-minute review of your current stack: Chargebee, QuickBooks, HubSpot, Zendesk, ChartMogul, Zapier — whatever you are running today. We map it against an Odoo consolidation and give you an honest cost and complexity estimate. Book the review here.