Skip to main content

Manufacturing & distribution

ERPNext Landed Cost Voucher: How to Add Freight & Duty to Item Cost (2026)

Use the ERPNext Landed Cost Voucher to add freight, customs duty and insurance to item valuation: how it works, how to make one, how to split charges.

Updated 29 Oct 202610 min readBy ManojFirst published 11 Jul 2026

An ERPNext Landed Cost Voucher adds extra purchase costs (freight, customs duty, insurance, clearing charges) to the valuation of the items you received, so your inventory value and cost of goods sold reflect the landed cost, not just the supplier's invoice price. You create it against a Purchase Receipt (or a Purchase Invoice that updates stock) and choose how the charges are split across items. Purchase and stock setup as a whole is in our complete guide to setting up ERPNext.

If you import goods or pay significant freight, the price on the supplier invoice is not what the stock costs you. Duty, shipping, insurance and clearing agent fees add to it, by an amount that depends on the goods, the route and the duty rate. Booking those as plain expenses keeps them out of your item cost and understates your cost of goods sold. The Landed Cost Voucher fixes that.

The point of a Landed Cost Voucher is truthful inventory valuation: it puts the costs of getting goods to your warehouse into the item's cost, so margins and COGS are real. I lead ERPNext and Frappe programmes at MithTech, a team of Frappe specialists in Bengaluru, and we set these up for importers and distributors.

Try it: what is your real per-unit cost?

Set the numbers to your last consignment. If the additional costs come out to more than a small share of the supplier invoice, booking them as plain expenses instead of an LCV overstates your gross margin on those goods.

CalculatorTrue Landed Cost Calculator

Live calculator: supplier invoice + freight + duty + insurance + CHA + inland = true landed cost and per-unit landed cost.

₹
units
₹
%
%
₹
₹
Supplier invoice
₹5,00,000
True landed cost
₹6,32,500
Per-unit landed
₹633

Additional cost is 26.5% of the supplier invoice. Booking these as plain expenses hides that from item cost and understates COGS by the same amount. Indicative figures — verify against the actual freight / customs / CHA bills.

Additional cost (freight + duty + ins + CHA + inland): ₹1,32,500

Open this calculator on a page of its own

What is a Landed Cost Voucher in ERPNext?

A Landed Cost Voucher is a document that spreads additional purchase costs (freight, customs duty, insurance, handling) across the items on a Purchase Receipt, raising each item's valuation rate. It exists because the real cost of stock is the supplier price plus what you spent getting the goods into your warehouse, and those costs usually arrive on separate bills from freight forwarders and clearing agents.

Once posted, the voucher raises the valuation of the received items by their share of the landed costs. Your inventory is then valued at landed cost, and when the items sell, the cost of goods sold includes freight and duty. This is what turns a rough margin into an accurate one for any business that imports or pays material inbound logistics.

Skimmable summary: A Landed Cost Voucher distributes freight, duty, insurance, and handling across received items, raising their valuation to landed cost. Inventory and cost of goods sold then reflect the real cost of getting goods to your warehouse, which is what Ind AS 2, IAS 2, ASC 330, FRS 102 and CAS 1 ask for.

How do I create a Landed Cost Voucher in ERPNext?

You create a Landed Cost Voucher in ERPNext by opening a new Landed Cost Voucher, selecting the relevant Purchase Receipt, adding the extra charges, choosing a distribution method, and submitting. The voucher then updates each item's valuation with its share of those charges. It should be posted while the items are still in stock so the cost attaches correctly.

Click through the demo below: each step shows what you do in the UI and what the ERPNext v16 controller does with your input, cited to file and line in the local checkout.

InteractiveLCV Step-Through Demo

Four-step click-through: New LCV → Fetch PR → Fill Charges → Distribute and Submit, with the source-file citation for each stage.

Step 1 of 4

Open a new Landed Cost Voucher

Stock module → Landed Cost Voucher → New. Set Posting Date and Company. The naming series MAT-LCV-.YYYY.- is pre-wired.

What ERPNext does under the hood

Skeleton document with an empty purchase_receipts child table, taxes child table, and distribute_charges_based_on set to 'Qty' by default.

apps/erpnext/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.json (naming_series MAT-LCV-.YYYY.-)

Here is the same sequence as a Steps block for readers who prefer the linear form:

1

Open a new Landed Cost Voucher

Stock module → Landed Cost Voucher → New. Set Company and Posting Date. Naming series MAT-LCV-.YYYY.- is pre-wired in landed_cost_voucher.json.

2

Fetch the Purchase Receipt

In the Purchase Receipts child table add rows pointing at the GRN(s) you're landing costs against. Click Get Items From Purchase Receipts — the server method at landed_cost_voucher.py:56 pulls items via get_pr_items (landed_cost_voucher.py:421) and copies base_rate / base_amount into the LCV Item table.

3

Fill the Taxes & Charges child table

One row per charge (freight, basic customs duty, insurance, CHA, inland transport), each with a Description, an Expense Account and the Amount. Use the account the forwarder's or agent's bill is booked to, often Expenses Included In Valuation, so the two net off. validate_expense_accounts (landed_cost_voucher.py:178) refuses accounts belonging to a different company when perpetual inventory is enabled.

4

Choose distribution method and submit

Pick Distribute Charges Based On: Amount, Qty or Distribute Manually (the three values on the DocType). On submit, update_landed_cost at landed_cost_voucher.py:307 re-writes item.landed_cost_voucher_amount on the linked PR, then calls update_stock_ledger and make_gl_entries with via_landed_cost_voucher=True, and finally repost_future_sle_and_gle so units already consumed pick up the corrected valuation.

Skimmable summary: Create a Landed Cost Voucher, fetch the Purchase Receipt, add each charge (freight, duty, insurance) in the charges table with its expense account, pick a distribution method, and submit. ERPNext updates item valuations, reposts SLEs and re-books GL entries, even for units already sold.

How are landed costs distributed across items?

Landed costs are distributed across items in ERPNext by Amount, Qty, or Distribute Manually, and the method you pick changes how fairly the cost lands on each item. Distribution by Amount spreads charges in proportion to each item's value; distribution by Qty spreads them per unit; Distribute Manually lets you assign exact shares when neither default is fair.

The core set_applicable_charges_on_item method at landed_cost_voucher.py:202 is where the split happens: it reads the enum value, scrubs it to a field name, and multiplies each item's share by the total charge. Weight-based distribution isn't in core; you need a small custom script that overrides this method to read total_weight instead.

Which method fits which charge type? Pick a charge below and the picker will tell you which basis to use on the LCV.

InteractiveDistribution Method Picker

Pick a charge type (freight, insurance, customs, CHA, inland, bank) — get the recommended ERPNext Distribute Charges Based On value and one-line rationale.

Recommended method

Ocean / air freight → Qty (or weight, if items vary)

Freight is priced by weight or volume, not by invoice value.

Distribute Charges Based On: QtyWeight → custom script needed

Core ERPNext supports Amount / Qty / Distribute Manually out of the box (see landed_cost_voucher.py:44). Weight-based distribution needs a custom script that overrides set_applicable_charges_on_item.

Skimmable summary: Landed costs distribute by Amount (value share), Qty (per unit), or Distribute Manually. Freight and inland transport go by Qty (or weight if you customise), insurance / customs / CHA / bank charges by Amount. Weight distribution requires a custom script.

When should I use a Landed Cost Voucher?

Use a Landed Cost Voucher whenever the extra costs of receiving goods are big enough to matter to your item cost: chiefly imports with customs duty and freight, or any purchase with substantial inbound logistics. If freight and duty are trivial, booking them as expenses is fine; once they materially change item cost, they belong in valuation.

Importers are the clearest case: duty, ocean or air freight, insurance, and clearing agent fees together can be a large share of cost, and leaving them out makes every margin report wrong. Distributors with heavy inbound freight benefit too; the wider setup is covered in my ERP guide for distributors and wholesalers, and the wider inventory picture in the ERPNext inventory management guide. For manufacturers, landed raw-material cost then flows into finished-goods costing and any standard costing variance analysis you run.

Skimmable summary: Use a Landed Cost Voucher when inbound costs materially affect item cost — imports with duty and freight, or heavy inbound logistics. Trivial charges can stay as expenses; significant ones belong in valuation so margins and COGS stay accurate.

Automation: seed the LCV, catch the mistakes

A common waste in a busy imports team is retyping freight, CHA and duty figures from a clearing agent's PDF into a manual LCV every week. Three small automations remove most of that. None needs a paid service; they run on your bench scheduler or a self-hosted n8n.

Code recipeLCV Automation Recipe

Three automations to copy: a Server Script that seeds a draft LCV on GRN submit, a Client Script that warns on missing charge accounts, and an n8n workflow that surfaces clearing-agent PDFs into Slack.

On Purchase Receipt submit, seed a draft Landed Cost Voucher with the freight/CHA charges already known from the item metadata or a linked freight PI. Accounts opens the draft, verifies figures and submits.

lcv_server.py
# Server Script → DocType Event → Purchase Receipt → on_submit
import frappe
from frappe.utils import flt

def after_purchase_receipt_submit(doc, method=None):
    if doc.currency == frappe.db.get_default("currency"):
        # skip pure-domestic GRNs unless you want LCV for them too
        return

    # Skip if we've already seeded one for this PR
    if frappe.db.exists("Landed Cost Voucher Purchase Receipt", {
        "receipt_document": doc.name, "docstatus": ["!=", 2]
    }):
        return

    lcv = frappe.new_doc("Landed Cost Voucher")
    lcv.company = doc.company
    lcv.posting_date = doc.posting_date
    lcv.distribute_charges_based_on = "Amount"
    lcv.append("purchase_receipts", {
        "receipt_document_type": "Purchase Receipt",
        "receipt_document": doc.name,
        "supplier": doc.supplier,
        "posting_date": doc.posting_date,
        "grand_total": doc.base_grand_total,
    })

    # ---- Fill in your actual heads here -----------------------------------
    #  These accounts must exist under the company's Indirect Expenses.
    #  Left as placeholders — swap for your chart-of-accounts codes.
    charges = [
        {"description": "Ocean freight",     "expense_account": "Freight & Forwarding - YC", "amount": 0.0},
        {"description": "Customs BCD",       "expense_account": "Customs Duty - YC",         "amount": 0.0},
        {"description": "CHA / clearing",    "expense_account": "Clearing Charges - YC",     "amount": 0.0},
        {"description": "Insurance premium", "expense_account": "Insurance - Import - YC",   "amount": 0.0},
    ]
    for c in charges:
        lcv.append("taxes", c)

    lcv.get_items_from_purchase_receipts()
    lcv.insert(ignore_permissions=True)  # DRAFT — accounts reviews & submits
    frappe.msgprint(f"Draft LCV {lcv.name} created against {doc.name}")

Deploy them in this order: the n8n workflow makes sure the charge amounts land in a place someone will see, the Server Script pre-fills the draft so accounts only has to check and submit, and the Client Script stops the two errors that most often waste a submit attempt.

Landed cost leads into a family of ERPNext costing questions, each with its own post:

At a glance

What to know
Made againstA submitted Purchase Receipt, or a Purchase Invoice with Update Stock
Goes into item costFreight, basic customs duty, insurance, clearing and inland transport
Usually stays outGST you can claim as input tax, including IGST on imports
Split methodsAmount, Qty or Distribute Manually; weight needs a custom script
On submitValuation rates updated, stock ledger and GL reposted, including units already sold

Frequently asked questions

+What is a Landed Cost Voucher used for in ERPNext?

It adds extra purchase costs (freight, customs duty, insurance and clearing charges) to the valuation of received items so inventory is valued at landed cost. It is created against a Purchase Receipt and distributes the charges across items, which makes COGS and margins accurate for importers and distributors.

+How do I add freight or customs duty to item cost in ERPNext?

Create a Landed Cost Voucher, fetch the Purchase Receipt for the shipment, and enter each charge in the Taxes & Charges table with its expense account. Choose Distribute Charges Based On (Amount / Qty / Manual) and submit. ERPNext raises each item's valuation rate by its share, so the cost is embedded in stock rather than booked as a plain expense.

+Can I add landed cost after the items are already sold?

Yes. update_landed_cost at landed_cost_voucher.py:307 reposts future SLEs, so units already consumed pick up the corrected valuation and the delta flows to COGS. The caveat is closed accounting periods: if your policy blocks reposting into them, book a manual Journal Entry in the current period instead.

+What distribution method should I use for landed costs?

Match the method to how the charge was incurred: Amount for value-based charges (customs BCD, insurance, CHA, bank), Qty for per-unit or per-weight charges (ocean freight, inland transport), and Distribute Manually only when neither default is fair. The picker above names the ERPNext value for each case.

+Which ERPNext version do the file references in this post apply to?

The code paths cited — landed_cost_voucher.py:56, landed_cost_voucher.py:307, stock_controller.py:1101, purchase_receipt.py:626 — are from the ERPNext v16 checkout (git tag v16.22.0-495-gde591661b9, effectively v16.28.x). The same functions exist in v14 and v15 with cosmetic differences; the LCV DocType itself has been stable since v11.

+Does the Landed Cost Voucher affect accounting as well as stock?

Yes. Submitting an LCV re-runs make_gl_entries(via_landed_cost_voucher=True) on the linked Purchase Receipt, which credits each charge's expense account (make_landed_cost_gl_entries at purchase_receipt.py:626) and debits the inventory account by the same amount. Stock valuation and general ledger stay consistent.

+What happens if we skip the LCV and just expense freight and duty?

Inventory sits on the balance sheet at the supplier invoice value, so it is understated. Freight and duty hit the P&L in the period you paid them, not the period the goods sell, and if they are booked below gross margin, COGS is understated and gross margin per item looks better than it is. Period-to-period margins stop being comparable. Where the amounts are material, it also departs from the "cost of purchase" rule in Ind AS 2, IAS 2, ASC 330 and FRS 102 §13.

Your next step

Import-heavy business? Get landed cost right.

Next step · Manufacturing & distribution

Now see how ERPNext runs a plant like yours

How we set up ERPNext for manufacturers, from bills of materials and job work to costing and the shop floor.

Comments & ratings

No comments yet. Start a new discussion.

0

Manoj · Published on 11 July 2026

Worked with us? Leave a Google review

Questions about this? Talk to the team.

Book a 30-minute Google Meet, WhatsApp us, or send a message. The engineer who works on this replies.

Send us a message
Your details go to our team's CRM and are used only to reply.