What is Export Management
What is Export Management
Export Management is a costing-to-order application built on ERPNext that replaces a commodity exporter's Excel price sheet with a structured, end-to-end pipeline: from an initial customer Opportunity through vendor sourcing, combination costing, customer quotation, sales order, procurement, and shipment execution.

It is built for bulk commodity exporters (the primary example in the demo is rice). The core problem it solves is that commodity export pricing is dynamic — rice prices change, sea freight fluctuates, port charges vary — and a spreadsheet cannot enforce a disciplined workflow, prevent stale rates from reaching a customer quote, or link a quote back to the purchase orders that execute it. Export Management makes every step traceable and keeps the numbers consistent from the first vendor RFQ to the final Purchase Order.
The end-to-end pipeline
Opportunity
└─▶ Export Costing ─▶ RFQs (one per quotable charge row)
─▶ vendor Supplier Quotations
─▶ Pull Vendor Rates
─▶ Generate Combinations (auto-applies cheapest)
─▶ set Selling Price / Bag
─▶ Quotation (per bag, in destination currency / CFA)
─▶ Sales Order → costing flips to Won
─▶ Purchase Orders (one per winning Supplier Quotation)
─▶ Export Shipment
Each step is a discrete action in ERPNext, linked by document references. Nothing is computed twice independently — the Quotation's line items come from the costing, the Purchase Orders come from the winning Supplier Quotations behind the selected combination. If a number changes upstream, you regenerate; the chain stays consistent.
Step-by-step walkthrough
1. Opportunity
A qualified lead lives in ERPNext as an Opportunity. From there, Create ▸ Export Costing scaffolds a new costing pre-filled with the customer and their currency. You can also create an Export Costing directly, without an Opportunity, if the inquiry arrives outside the CRM.
2. Export Costing — the central document
The Export Costing is the hub of the entire pipeline. Every other document (RFQs, combinations, quotation, sales order, POs, shipment) is linked back to it.
You set up the costing in three layers:
| Layer | How it gets there |
|---|---|
| Item lines — commodity, packaging, container count | Added manually; gross/net MT and total bags compute from the packaging spec |
| Fixed charges — CFS, surveyor, ECTN, BL, insurance, POD, etc. | Loaded from a Costing Template; these do not change with vendor selection |
| Variable heads — Procurement Cost, Bags, Sea Freight, CFS Handling, Container | Added automatically as empty rows (₹0 until a combination is applied) |
Variable heads are what vendors quote. Fixed heads are constants the exporter controls. The distinction matters: a Costing Template holds fixed costs only — it does not pin a loading port or container type, because those are decided during sourcing.
Procurement cost is split per item: in a mixed load (rice + cashew), each commodity gets its own charge row because mills price rice and cashew independently.
Gotcha: A fresh costing's margin is meaningless until you Generate Combinations. Variable heads start at ₹0, so the landed cost is artificially low. Do not quote a customer from an uncombined costing.
3. Request for Quotation (RFQ)
Create ▸ Requests for Quotation opens a dialog where you select which cost categories to source. The system creates one RFQ per quotable charge row — for a single-commodity load this is one RFQ per category; for a mixed load (rice + cashew) you get a separate procurement RFQ for each item's charge row. Rice sourcing goes to mills, freight sourcing goes to forwarders. Vendors never see each other's heads on a combined sheet.
Each RFQ carries a single item row: the commodity item for goods heads (so the eventual PO actually buys the rice), or a synthetic service item for service heads (freight, handling, etc.).
Vendors can respond in two ways:
| Method | How it works |
|---|---|
| Guest link | On a submitted RFQ → Guest Quote Links → copy /quote/<token>. Vendor enters rates in a no-login browser page and submits. Revoke by clearing the token on the RFQ supplier row. |
| The RFQ email's "Submit your Quotation" button links to the same guest page. |
Both paths produce a Supplier Quotation in ERPNext. Vendors can quote per-port rates (ex-works vs. delivered-at-port) or a blank-port wildcard that applies to any loading port.
4. Pull Rates
Combinations ▸ Pull Vendor Rates snapshots the submitted Supplier Quotation rates onto the costing, stored as raw rates per charge head, per item, and per port. This is a deliberate checkpoint — rates are not applied automatically on SQ submission, because you may receive quotes from multiple vendors and want to compare them all before anything changes on the costing.
5. Generate Combinations
Combinations ▸ Generate Combinations is where the engine does its work:
- It builds every valid vendor × port combination across all variable heads.
- For each combination, it computes the full landed cost — not cheapest-per-head, but cheapest-per-combination. (Picking the cheapest vendor for each head independently can produce an infeasible combination if a freight vendor only quotes Cotonou but your rice mill only delivers ex-works from a port they do not cover.)
- It ranks all combinations, opens the Combination Comparison report (rank 1 highlighted in green), and auto-applies the cheapest to the costing.
- The costing immediately carries real rates in all variable head rows.
To override the auto-pick: open any combination → Select This Combination.
Regenerating after new quotes arrive deselects the old pick, rebuilds all combinations, re-applies the new cheapest, and resets the per-MT figure so it recomputes from fresh cost.
Port wildcard rule: A vendor rate with a blank loading port is an any-port / ex-works wildcard — it is eligible for any combination. A port-specific rate beats a wildcard for that port.
6. Selling Price and Margin
With a combination applied, the costing shows real landed cost per bag and your margin:
Margin = Selling Price / Bag − Landed Cost / Bag
You enter the Selling Price / Bag at the top of the costing form in the destination currency (e.g. XOF / CFA). Change the price and save — margin updates immediately.
7. Quotation
Create ▸ Quotation produces an ERPNext Quotation priced the way the buyer buys: per bag, in the destination currency (example: 5,400 bags × 15,500 XOF). The system converts to INR using the CFA-per-EUR peg configured in Export Settings.
- View Quotation jumps to the linked document.
- Regenerate Quotation deletes the existing draft and rebuilds it from current numbers. A submitted quotation (already sent to the customer) cannot be overwritten — cancel it first.
The costing's status advances to Quoted when the quotation is created (unless it is already Won or Lost).
8. Sales Order and the Won transition
When the customer accepts, submit the Quotation and then create the Sales Order from it via Create ▸ Sales Order → submit. The costing automatically flips to Won on Sales Order submission. The transition is triggered by the Sales Order's on_submit hook, which resolves the linked costing through the Quotation. A Sales Order created outside this chain (not from the Quotation) will not trigger the costing flip.
9. Purchase Orders
On a Won costing → Create ▸ Purchase Orders. The system generates one draft PO per winning Supplier Quotation (not one per vendor — a vendor may have won on multiple heads via separate SQs). Quantities are derived from the costing: rice in MT, freight in containers. Each PO is raised under the correct company.
Traceability: Each PO traces back to exactly one Supplier Quotation, and each SQ traces back to the costing. The audit chain is clean from customer order to supplier commitment.
10. Export Shipment
Create ▸ Export Shipment is available only on a Won costing. It creates an execution document carrying the container details, port of loading, port of discharge, and a standard document checklist (Commercial Invoice, Packing List, Proforma, etc.). Print formats are built in.
11. Revisions
If you need to re-quote with different numbers, Create ▸ Revision creates a new Export Costing chained to the original (same revision_of root), with status reset to Draft and all vendor/quotation links cleared. The original record is untouched — the full pricing history is preserved for audit.
Status flow
Draft → Rates Received → Costing Selected → Quoted → Won
→ Lost
| Status | Meaning |
|---|---|
| Draft | Costing is being set up; no vendor rates yet |
| Rates Received | At least one Supplier Quotation has been pulled |
| Costing Selected | A combination has been applied; real landed cost is on the costing |
| Quoted | A Quotation has been sent to the customer |
| Won | A Sales Order has been submitted against this costing |
| Lost | The deal was lost; set manually |
Auto-transitions never downgrade Won or Lost. Regenerating combinations, re-creating a quotation, or any other action will not pull a Won costing back to an earlier status. If you need to re-work a Won costing's numbers, create a Revision.
Demo sites and login
| Site name (bench) | Purpose |
|---|---|
export.localhost |
Development and test (served at port 8010); may contain in-progress or broken data |
exportdemo.localhost |
Clean demo with fully seeded data (a Won costing, rival-port costings, submitted vendor quotes) |
Login for both: Administrator / Frappe@123
To reseed the demo at any time:
bench --site <site> migrate
bench --site <site> execute export_management.export_management.demo.seed.run
The seed is idempotent — it bootstraps the Company, UOMs, price lists, fiscal year, masters, submitted vendor quotes, a Won costing with shipment, and rival-port costings so the Combination Comparison report has something meaningful to show.
Key design decisions
Why one RFQ per quotable charge row, not one combined RFQ?
Vendors must never see each other's heads. A mill should not see what you are paying for freight; a forwarder should not see your procurement cost. The one-RFQ-per-row rule enforces this separation structurally, not just by convention. For a single-commodity load this produces one RFQ per category; for a multi-commodity load each item's procurement row gets its own RFQ.
Why combinations instead of cheapest-per-head?
Choosing the cheapest vendor independently for each head can produce a combination that is physically impossible — a freight vendor who only quotes Cotonou cannot be combined with a mill that only delivers ex-works from Abidjan. The combination engine builds feasible groupings first, then ranks by total landed cost.
Why does the quotation price in bags, not MT?
Buyers in CFA markets purchase by the bag. A 50 kg bag of rice is the unit the buyer recognises on their invoice. The internal costing works in MT for weight calculations, but the customer-facing Quotation is per bag in destination currency. The per-MT figure on the costing is retained as an internal reference only.
Why does the Selling Price / Bag live on the costing, not the quotation?
The margin calculation (selling price minus landed cost) must happen on the costing, before a quotation is created, so the exporter can verify they are not quoting at a loss. The quotation is generated from the costing, not the other way around.
What lives in later sections
This page is a high-level orientation. Deeper mechanics — the Costing Template schema, the combination engine's port-matching logic, the guest quote token flow, FX rate configuration, the CFA-per-EUR peg, Export Settings fields, and the document checklist — are covered in their own sections.