ERP

Implementing ERPNext: A Practical Guide to the System, Its Document Model, and Core Workflows

ERPNext is built on the Frappe Framework, a metadata-driven, low-code platform. That single fact explains almost everything about how an ERPNext implementation actually works: you are not writing an ERP from scratch, you are configuring a system whose data model, forms, permissions, and workflows are all defined as documents themselves. Understanding that document model is the fastest way to go from "we installed ERPNext" to "we run our business on ERPNext."

This post covers three things: a practical implementation roadmap, the document model that underlies every module (Sales, Buying, Stock, Accounts, HR), and sample sequence diagrams for the two workflows every implementation eventually has to get right — order-to-cash and procure-to-pay.

1. How an ERPNext implementation actually unfolds

Most successful ERPNext rollouts move through five phases. Timelines below assume a single-entity, small-to-mid-size company; multi-company or manufacturing-heavy implementations run longer.

Phase 1 — Business discovery (2–4 weeks). Stakeholder workshops per department, mapping of current processes, a gap analysis against ERPNext’s standard modules, and a Business Requirements Document (BRD) that lists module-by-module requirements. This is where you decide what’s a configuration change versus a custom DocType.

Phase 2 — Module configuration (4–8 weeks). Company setup, chart of accounts, fiscal year, users and roles, then module-by-module configuration: Selling, Buying, Stock, Accounts, HR. Master data goes in here too — customers, suppliers, items, price lists, warehouses.

Phase 3 — Customization and integration (3–6 weeks). Gaps identified in discovery get closed with custom fields, client/server scripts, custom print formats and reports, and Workflow documents for approval chains. Integrations (payment gateways, e-commerce, banking, shipping, tax authorities) are built or configured here.

Phase 4 — Testing and training (3–4 weeks). Unit and integration testing of configured flows, user acceptance testing with real transactions, and role-based training — finance users, warehouse users, sales users, and HR users each need different walkthroughs because they touch different DocTypes.

Phase 5 — Go-live and support. Final data migration, opening balances, a parallel-run or hard cutover, and a hypercare period (typically the first 1–2 weeks post-launch) with dedicated support before handing off to standard support.

Total: 3–6 months for a typical mid-market implementation. The variable is almost always Phase 3 — the more your processes diverge from ERPNext’s defaults, the more custom DocTypes, scripts, and workflow states you need, and each of those needs its own testing pass.

2. The document model: everything is a DocType

In the Frappe Framework, a DocType is simultaneously a database table definition, a form, a permission boundary, and (often) a piece of business logic. When you create a DocType, Frappe generates a backing table (prefixed tab, so the Sales Order DocType lives in tabSales Order), a list view, and a form view — with no additional front-end code required.

A few concepts matter more than the rest once you’re implementing rather than just using the system:

  • DocField — a single field definition (type, label, validation, permission level) inside a DocType. A DocType’s structure is just a list of DocFields.
  • Meta — a DocType is itself stored as a DocType (DocType describes DocType). This reflexivity is why Customize Form can add fields to standard doctypes like Sales Order without touching source code — you’re editing metadata, not code.
  • Child Table / Table DocType — a DocType marked istable that only ever exists nested inside a parent document, with no list view of its own. Sales Order Item is a child table of Sales Order; each row is one line item.
  • Link Field — a foreign-key-style field that references another DocType by name, giving you referential relationships (a Sales Order links to a Customer; a Sales Order Item links to an Item) without hand-written joins.
  • Submittable documents and docstatus — transaction DocTypes like Sales Order, Delivery Note, and Purchase Invoice carry a docstatus field: 0 = Draft, 1 = Submitted, 2 = Cancelled. Submission is what triggers downstream effects — stock movement, GL postings — and submitted documents become largely immutable, which is what gives ERPNext’s accounting an audit trail instead of an editable spreadsheet.
  • Naming series — controls how document IDs are generated (SO-.YYYY.-.##### for Sales Order, for example), configurable per company or fiscal year.
  • Workflow — itself a DocType, used to layer custom approval states (Draft → Pending Approval → Approved) on top of a target DocType without writing code.

Document model diagram: the metadata layer

classDiagram
    class DocType {
        +name: string
        +module: string
        +istable: bool
        +is_submittable: bool
        +autoname: string
    }
    class DocField {
        +fieldname: string
        +fieldtype: string
        +label: string
        +reqd: bool
        +options: string
    }
    class Document {
        +doctype: string
        +name: string
        +docstatus: int
        +owner: string
        +validate()
        +on_submit()
        +on_cancel()
    }
    class Workflow {
        +document_type: string
        +states: WorkflowState[]
        +transitions: WorkflowTransition[]
    }

    DocType "1" --> "*" DocField : defines
    DocType "1" --> "*" Document : instantiates
    Workflow "1" --> "1" DocType : governs
    Document "1" --> "*" Document : child table rows

Document model diagram: the sales cycle data

erDiagram
    CUSTOMER ||--o{ SALES_ORDER : places
    SALES_ORDER ||--|{ SALES_ORDER_ITEM : contains
    ITEM ||--o{ SALES_ORDER_ITEM : referenced_by
    SALES_ORDER ||--o{ DELIVERY_NOTE : fulfilled_by
    DELIVERY_NOTE ||--|{ DELIVERY_NOTE_ITEM : contains
    SALES_ORDER ||--o{ SALES_INVOICE : billed_by
    SALES_INVOICE ||--|{ SALES_INVOICE_ITEM : contains
    SALES_INVOICE ||--o{ PAYMENT_ENTRY : settled_by
    SALES_INVOICE ||--o{ GL_ENTRY : posts
    DELIVERY_NOTE ||--o{ STOCK_LEDGER_ENTRY : posts

Every arrow here is a Link Field or a child-table relationship defined in metadata, not a hand-coded join — which is exactly why Customize Form, Report Builder, and the Query Report tool can all traverse these relationships without a developer writing SQL.

3. Sample sequence diagram: order-to-cash

This is the flow discovery workshops spend the most time on, because "when does revenue get recognized" and "when does stock leave the warehouse" are usually where a client’s actual process diverges from ERPNext’s default.

sequenceDiagram
    actor Customer
    actor SalesUser as Sales User
    participant ERPNext as ERPNext (Frappe)
    participant Warehouse
    actor Accounts as Accounts User

    Customer->>SalesUser: Request pricing
    SalesUser->>ERPNext: Create Quotation
    ERPNext-->>SalesUser: Quotation (docstatus=0 Draft)
    SalesUser->>Customer: Send Quotation
    Customer->>SalesUser: Approve

    SalesUser->>ERPNext: Create Sales Order from Quotation
    ERPNext-->>SalesUser: Sales Order (Draft)
    SalesUser->>ERPNext: Submit Sales Order
    ERPNext->>ERPNext: docstatus 0 → 1 (Submitted)
    ERPNext-->>Warehouse: Order visible for fulfillment

    Warehouse->>ERPNext: Create Delivery Note from Sales Order
    ERPNext-->>Warehouse: Delivery Note (Draft)
    Warehouse->>ERPNext: Submit Delivery Note
    ERPNext->>ERPNext: Post Stock Ledger Entry (qty -N)
    ERPNext->>ERPNext: Update Sales Order % Delivered

    Accounts->>ERPNext: Create Sales Invoice from Delivery Note
    ERPNext-->>Accounts: Sales Invoice (Draft)
    Accounts->>ERPNext: Submit Sales Invoice
    ERPNext->>ERPNext: Post GL Entry (Debit Receivable / Credit Income)

    Customer->>Accounts: Remit payment
    Accounts->>ERPNext: Create Payment Entry against Sales Invoice
    ERPNext->>ERPNext: Reconcile GL Entry, close outstanding amount
    ERPNext-->>Accounts: Invoice status = Paid

Notes worth calling out to a client during Phase 2 configuration:

  • Delivery Note is optional. A service business can go Sales Order → Sales Invoice directly; nothing about the document model forces the stock step.
  • The submit action is the trigger, not the save. Draft documents (docstatus=0) can be edited freely and don’t touch the ledger. This is the single most common training gap — users who "save" a Delivery Note and wonder why stock didn’t move.
  • Percent-delivered and percent-billed are computed fields on Sales Order, updated automatically as linked documents submit — this is what powers the "over-delivery" and "over-billing" guard rails.

4. Sample sequence diagram: procure-to-pay

sequenceDiagram
    actor Dept as Requesting Dept
    actor Buyer as Purchase User
    participant ERPNext as ERPNext (Frappe)
    actor Supplier
    participant Warehouse
    actor Accounts as Accounts User

    Dept->>ERPNext: Create Material Request
    ERPNext-->>Buyer: Material Request pending

    opt Multiple suppliers to compare
        Buyer->>ERPNext: Create Request for Quotation (RFQ)
        ERPNext-->>Supplier: RFQ sent
        Supplier->>ERPNext: Submit Supplier Quotation
        Buyer->>ERPNext: Compare Supplier Quotations
    end

    Buyer->>ERPNext: Create Purchase Order (from RFQ or Material Request)
    ERPNext-->>Buyer: Purchase Order (Draft)
    Buyer->>ERPNext: Submit Purchase Order
    ERPNext->>Supplier: PO issued

    Supplier->>Warehouse: Ship goods
    Warehouse->>ERPNext: Create Purchase Receipt from Purchase Order
    Warehouse->>ERPNext: Submit Purchase Receipt
    ERPNext->>ERPNext: Post Stock Ledger Entry (qty +N)
    ERPNext->>ERPNext: Update PO % Received

    Accounts->>ERPNext: Create Purchase Invoice from Purchase Receipt
    Accounts->>ERPNext: Submit Purchase Invoice
    ERPNext->>ERPNext: Post GL Entry (Debit Expense/Stock / Credit Payable)

    Accounts->>ERPNext: Create Payment Entry against Purchase Invoice
    ERPNext->>ERPNext: Reconcile GL Entry, close outstanding amount
    ERPNext-->>Supplier: Payment released

Two configuration decisions to make explicit during discovery, since they change this diagram:

  • RFQ / Supplier Quotation comparison is optional — skip it entirely for organizations with pre-negotiated or single-source suppliers, and go straight from Material Request to Purchase Order.
  • The order of Purchase Receipt and Purchase Invoice is not fixed. Some organizations invoice before goods arrive (invoice-first), others receive-first. ERPNext supports both; you configure which is the default in Buying Settings, but individual transactions can deviate.

5. What this means for your implementation checklist

Because the document model is consistent across modules, most of the implementation work is pattern repetition rather than novel design:

  1. Map each business process to a document chain, the way the two diagrams above do. Identify which steps are mandatory, which are optional, and which need a Workflow DocType layered on top for approvals.
  2. Decide submission gates. For every submittable DocType, agree who has the role to submit it and what should be true before they do (stock available, credit limit checked, budget approved).
  3. Extend, don’t fork. Prefer Customize Form (adding DocFields to a standard DocType) over creating parallel custom DocTypes — it keeps you compatible with core reports and future ERPNext upgrades.
  4. Get naming series and numbering right before go-live. Renaming a series after real transactions exist is disruptive; agree the format (SO-.YYYY.-.##### etc.) during Phase 2, not Phase 5.
  5. Test the linked-document chain end to end, not each DocType in isolation — most UAT defects in ERPNext implementations show up in the hand-off between documents (a Delivery Note that won’t submit because the Sales Order’s stock reservation logic disagrees with warehouse settings, for example), not within a single form.

Get the document model right and the sequence diagrams above are less "how ERPNext works" and more "how your business already works, expressed in Frappe’s metadata."


Sources: