How to Perform Period Closing and Financial Year End in ERPNext: The Complete PCV Guide

The Period Closing Voucher (PCV) in ERPNext locks accounting periods by generating general ledger entries that carry profit and loss balances forward to a designated closing account, effectively sealing the financial year when the period end date matches the fiscal year end.

The period closing and financial year end process in the frappe/erpnext repository centers on the Period Closing Voucher doctype. This document orchestrates validation, GL entry generation, and period sealing to ensure immutable financial records once a fiscal year closes.

Understanding the Period Closing Voucher Workflow

The PCV process spans ten distinct validation and execution phases defined in erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py.

Step 1: Determine the Accounting Period

The system calculates the closure range automatically. The validate_start_and_end_date() method (lines 49-68) sets the Period Start Date to the day after the last closed PCV for the same fiscal year and company, or the fiscal year start if no prior PCV exists. The Period End Date cannot exceed the fiscal year end date.

Step 2: Enforce Year-End Dependencies

Before creating a PCV for a new fiscal year, the check_if_previous_year_closed() method (lines 70-99) verifies that all general ledger entries from the previous year have been properly closed. This prevents gaps in the accounting chain and ensures sequential closure.

Step 3: Block Overlapping Closures

The block_if_future_closing_voucher_exists() method (lines 101-109) prevents users from creating overlapping vouchers. If any future PCV with a later period_end_date exists, the current voucher cannot be saved or submitted, maintaining chronological integrity.

Step 4: Validate the Closing Account

The closing account must be a Liability or Equity account with a currency matching the company default. The check_closing_account_type() (lines 18-24) and check_closing_account_currency() (lines 26-31) methods enforce these constraints before submission.

Step 5-6: Generate General Ledger Entries

Upon submission via on_submit() (lines 32-38), the voucher status changes to In Progress and triggers GL entry generation. The get_pcv_gl_entries() method calls three helper functions: get_gle_for_pl_account(), get_gle_for_closing_account(), and get_gle_for_closing_entry() (lines 85-165) to:

  • Reverse profit-and-loss (P&L) accounts
  • Transfer net balances to the Closing Account
  • Create closing entries for balance-sheet accounts

Step 7-8: Commit and Finalize Entries

The process_gl_and_closing_entries() helper (lines 64-73) executes make_gl_entries() and make_closing_entries(), which creates Account Closing Balance records in account_closing_balance.py. Success updates gle_processing_status to Completed; failures store the error traceback in error_message (lines 74-84).

Step 9: Cancellation and Reversal

Cancelling a PCV triggers process_cancellation and cancel_gl_entries() (lines 40-55), reversing GL entries and removing linked closing balances. The system blocks cancellation if future PCVs exist to prevent accounting gaps.

Step 10: Seal the Financial Year

When the final PCV's period_end_date equals the fiscal year's year_end_date and processing completes, the fiscal year is effectively closed. The validate_accounting_period_on_doc_save() function in accounting_period.py (line 97) subsequently blocks any posting dates beyond this point.

Creating a Period Closing Voucher via Python

You can programmatically create and submit a PCV using the Frappe Python API:

import frappe
from frappe.utils import getdate

# Define fiscal year and company

fy = "2025-2026"
company = "My Company"

# Calculate automatic start/end dates

period_start, period_end = frappe.get_attr(
    "erpnext.accounts.doctype.period_closing_voucher.period_closing_voucher.get_period_start_end_date"
)(fy, company)

# Create the PCV document

pcv = frappe.get_doc({
    "doctype": "Period Closing Voucher",
    "company": company,
    "fiscal_year": fy,
    "period_start_date": period_start,
    "period_end_date": period_end,
    "closing_account_head": "Closing Account - MYC",  # Must be Liability or Equity

    "remarks": f"Closing period {period_start} to {period_end}"
})

# Insert and submit to trigger background processing

pcv.insert()
pcv.submit()
print(f"Submitted PCV {pcv.name}")

Using the REST API for Financial Year End

For external integrations, create the voucher via REST:

curl -X POST https://erp.example.com/api/resource/Period%20Closing%20Voucher \
     -H "Authorization: token <api_key>:<api_secret>" \
     -H "Content-Type: application/json" \
     -d '{
           "company": "My Company",
           "fiscal_year": "2025-2026",
           "period_start_date": "2025-01-01",
           "period_end_date": "2025-12-31",
           "closing_account_head": "Closing Account - MYC",
           "remarks": "Year-end close"
         }'

To execute the closure, submit the document by calling:

POST /api/resource/Period%20Closing%20Voucher/{name}/actions/submit

Monitoring PCV Processing Status

Check whether GL entries have posted successfully:

pcv = frappe.get_doc("Period Closing Voucher", "PCV-2025-2026-001")
print(pcv.gle_processing_status)   # Returns: In Progress / Completed / Failed

if pcv.error_message:
    print("Processing error:", pcv.error_message)

Core Implementation Files

The period closing and financial year end logic spans these critical files in the frappe/erpnext repository:

Summary

  • The Period Closing Voucher (PCV) is the sole mechanism in ERPNext for executing period closing and financial year end operations.
  • Validation occurs in period_closing_voucher.py through methods like validate_start_and_end_date() and check_if_previous_year_closed().
  • The Closing Account must be a Liability or Equity account matching the company currency, enforced by check_closing_account_type().
  • GL generation runs via get_pcv_gl_entries(), transferring P&L balances and creating Account Closing Balance records.
  • Processing status tracks via gle_processing_status (In Progress → Completed/Failed).
  • Once the final PCV reaches the fiscal year end date and completes processing, subsequent transactions are blocked by accounting_period.py validation.

Frequently Asked Questions

What is a Period Closing Voucher in ERPNext?

A Period Closing Voucher (PCV) is a document type in ERPNext that formally closes a range of accounting periods by generating general ledger entries. According to the source code in period_closing_voucher.py, it reverses profit-and-loss account balances, transfers the net amount to a designated closing account, and creates immutable closing balance records that prevent backdated modifications.

Can I post transactions after closing a financial year in ERPNext?

No. Once the final PCV for a fiscal year is submitted and its gle_processing_status shows Completed, the validate_accounting_period_on_doc_save() method in accounting_period.py blocks any new documents with posting dates after the closed period. You must cancel the existing PCV to reopen the period, which reverses all associated GL entries via process_cancellation.

What type of account should I select as the Closing Account?

The Closing Account must be a Liability or Equity account, as enforced by check_closing_account_type() in lines 18-24 of period_closing_voucher.py. Additionally, check_closing_account_currency() (lines 26-31) validates that the account currency matches the company default currency. Typically, this is a "Closing Account" or "Profit/Loss Appropriation" account.

How do I check if my Period Closing Voucher processed successfully?

Query the gle_processing_status field on the PCV document. As implemented in process_gl_and_closing_entries() (lines 74-84), this field displays In Progress during background processing, Completed upon successful GL entry creation, or Failed with the specific error message stored in error_message.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →