A document gets its name once, when it is first saved. After that the name never changes, so the pattern you choose decides what your invoice numbers look like for years.
Set a pattern and two dates below, and see the next names, the counter that was used, and when it restarts.
Try it
What name comes next?
Choose a pattern and the dates. The key is the text before the # run: it decides when the counter restarts.
Pattern
Frappe version
Fiscal year starts
- Next name
SINV-2026-2027-00001- Counter key in tabSeries
SINV-2026-2027-- Date used for YY, YYYY, MM, DD
- 2 Apr 2027
- Fiscal Year used for FY
- 2026-2027
- The next three names
SINV-2026-2027-00001,SINV-2026-2027-00002,SINV-2026-2027-00003- The counter restarts
- When the next Fiscal Year starts (1 Apr 2027).
Sample Fiscal Years
| Name | Starts | Ends |
|---|---|---|
| 2025-2026 | 1 Apr 2025 | 31 Mar 2026 |
| 2026-2027 | 1 Apr 2026 | 31 Mar 2027 |
| 2027-2028 | 1 Apr 2027 | 31 Mar 2028 |
Sample dates and company abbreviation (SC); your site has its own Fiscal Year rows. Frappe v16.52.0, ERPNext v16.50.0.
How does a DocType pick its name?
In this order. A before_naming hook. Auto-increment or UUID, if the DocType uses them. An amended name, such as SINV-00001-1. The first matching Document Naming Rule. The controller's autoname() method. Then the DocType's own naming option: field:, naming_series:, prompt, format: or a pattern with #. If nothing named it, a ten-character hash.
How does a series count?
A pattern is split on dots. SINV-.YYYY.-.##### is the text SINV-, the year, the text -, and a five-digit number. The counter lives in a table called tabSeries, and its key is everything before the first run of #: here SINV-2027-. Same key, same counter. A new key starts at 1.
That is the whole rollover rule, and it has a consequence. A year placed after the number, as in CHQ-.#####./.YY., never changes the key, so the counter never restarts. If you leave the number out, Frappe adds .##### for you.
Which year do you get?
On v16, YY, YYYY, MM, DD and JJJ come from ERPNext's own parser. They use the moment the document is created, not its posting date, unless "Use Posting Datetime for Naming Documents" is ticked in Global Defaults. On v15 they use today's date and there is no such setting.
FY is different. It looks up the Fiscal Year that contains the document's posting date for its company, and returns that Fiscal Year's name, 2026-2027 for an April-to-March year. TFY shortens it to 26-27, and ABBR is the company abbreviation.
An invoice posted on 31 March 2027 but entered on 2 April 2027 is PINV-2026-2027-00123 on PINV-.FY.-.#####. On PINV-.YYYY.-.##### it takes the entry date's year, 2027. Entered on 2 January 2027 for 28 December 2026, YYYY gives 2027 by default and 2026 with the setting ticked.
How does the fiscal year itself roll over?
A Fiscal Year is a document named by its year field. A daily maintenance job, auto_create_fiscal_year, looks for a year that ends in three days and creates the next one from it, named by the start year, or start-end when the year spans two. It needs the scheduler (chapter 5).
If no Fiscal Year covers a date, saving a document with that date fails with "is not in any active Fiscal Year". Years may not overlap unless they are limited to different companies, and a normal year ends one year less a day after it starts.
What if you need to change a series mid-year?
Document Naming Settings can set the counter by hand (System Manager only, and the change is logged as a Version). Frappe's own code warns that setting it wrongly "can result in unusable transactions". Deleting the newest document steps the counter back by one, so a gap appears only when an older document is deleted.
Where this comes from
Read at Frappe v16.52.0 and ERPNext v16.50.0. “(v15)” marks Frappe v15.123.0 and “(ERPNext v15)” marks ERPNext v15.122.0. Each link opens that file at that tag, on that line.
model/naming.py:141–198 · model/naming.py:210–234 · model/naming.py:57–78 · model/naming.py:87–109 · model/naming.py:408–423 · model/naming.py:350–360 · model/naming.py:362–381 · model/naming.py:360–362 · erpnext/hooks.py:453–457 (ERPNext) · erpnext/hooks.py:405–407 (ERPNext v15) · model/naming.py:346–352 (v15) · accounts/utils.py:1590–1598 (ERPNext) · accounts/utils.py:88–92 (ERPNext) · accounts/utils.py:1608–1622 (ERPNext) · global_defaults/global_defaults.json:96–101 (ERPNext) · fiscal_year/fiscal_year.json:4 (ERPNext) · fiscal_year/fiscal_year.py:98–132 (ERPNext) · erpnext/hooks.py:495–499 (ERPNext) · accounts/utils.py:130–141 (ERPNext) · fiscal_year/fiscal_year.py:42–95 (ERPNext) · model/naming.py:125–134 · document_naming_settings/document_naming_settings.py:209–226 · model/naming.py:426–478 · model/naming.py:236–257