Skip to content

Commit ef801d6

Browse files
authored
Merge pull request #52849 from frappe/mergify/bp/version-15-hotfix/pr-52842
refactor: `Fiscal Year` cleanup (backport #52842)
2 parents 266658c + bb8e5ad commit ef801d6

5 files changed

Lines changed: 89 additions & 71 deletions

File tree

erpnext/accounts/doctype/fiscal_year/fiscal_year.py

Lines changed: 32 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import frappe
66
from dateutil.relativedelta import relativedelta
7-
from frappe import _
7+
from frappe import _, cint
88
from frappe.model.document import Document
99
from frappe.utils import add_days, add_years, cstr, getdate
1010

@@ -33,24 +33,6 @@ def validate(self):
3333
self.validate_dates()
3434
self.validate_overlap()
3535

36-
if not self.is_new():
37-
year_start_end_dates = frappe.db.sql(
38-
"""select year_start_date, year_end_date
39-
from `tabFiscal Year` where name=%s""",
40-
(self.name),
41-
)
42-
43-
if year_start_end_dates:
44-
if (
45-
getdate(self.year_start_date) != year_start_end_dates[0][0]
46-
or getdate(self.year_end_date) != year_start_end_dates[0][1]
47-
):
48-
frappe.throw(
49-
_(
50-
"Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."
51-
)
52-
)
53-
5436
def validate_dates(self):
5537
self.validate_from_to_dates("year_start_date", "year_end_date")
5638
if self.is_short_year:
@@ -66,28 +48,20 @@ def validate_dates(self):
6648
frappe.exceptions.InvalidDates,
6749
)
6850

69-
def on_update(self):
70-
check_duplicate_fiscal_year(self)
71-
frappe.cache().delete_value("fiscal_years")
51+
def validate_overlap(self):
52+
fy = frappe.qb.DocType("Fiscal Year")
7253

73-
def on_trash(self):
74-
frappe.cache().delete_value("fiscal_years")
54+
name = self.name or self.year
7555

76-
def validate_overlap(self):
77-
existing_fiscal_years = frappe.db.sql(
78-
"""select name from `tabFiscal Year`
79-
where (
80-
(%(year_start_date)s between year_start_date and year_end_date)
81-
or (%(year_end_date)s between year_start_date and year_end_date)
82-
or (year_start_date between %(year_start_date)s and %(year_end_date)s)
83-
or (year_end_date between %(year_start_date)s and %(year_end_date)s)
84-
) and name!=%(name)s""",
85-
{
86-
"year_start_date": self.year_start_date,
87-
"year_end_date": self.year_end_date,
88-
"name": self.name or "No Name",
89-
},
90-
as_dict=True,
56+
existing_fiscal_years = (
57+
frappe.qb.from_(fy)
58+
.select(fy.name)
59+
.where(
60+
(fy.year_start_date <= self.year_end_date)
61+
& (fy.year_end_date >= self.year_start_date)
62+
& (fy.name != name)
63+
)
64+
.run(as_dict=True)
9165
)
9266

9367
if existing_fiscal_years:
@@ -110,44 +84,41 @@ def validate_overlap(self):
11084
frappe.throw(
11185
_(
11286
"Year start date or end date is overlapping with {0}. To avoid please set company"
113-
).format(existing.name),
87+
).format(frappe.get_desk_link("Fiscal Year", existing.name, open_in_new_tab=True)),
11488
frappe.NameError,
11589
)
11690

11791

118-
@frappe.whitelist()
119-
def check_duplicate_fiscal_year(doc):
120-
year_start_end_dates = frappe.db.sql(
121-
"""select name, year_start_date, year_end_date from `tabFiscal Year` where name!=%s""",
122-
(doc.name),
92+
def auto_create_fiscal_year():
93+
fy = frappe.qb.DocType("Fiscal Year")
94+
95+
# Skipped auto-creating Short Year, as it has very rare use case.
96+
# Reference: https://www.irs.gov/businesses/small-businesses-self-employed/tax-years (US)
97+
follow_up_date = add_days(getdate(), days=3)
98+
fiscal_year = (
99+
frappe.qb.from_(fy)
100+
.select(fy.name)
101+
.where((fy.year_end_date == follow_up_date) & (fy.is_short_year == 0))
102+
.run()
123103
)
124-
for fiscal_year, ysd, yed in year_start_end_dates:
125-
if (getdate(doc.year_start_date) == ysd and getdate(doc.year_end_date) == yed) and (
126-
not frappe.flags.in_test
127-
):
128-
frappe.throw(
129-
_(
130-
"Fiscal Year Start Date and Fiscal Year End Date are already set in Fiscal Year {0}"
131-
).format(fiscal_year)
132-
)
133104

134-
135-
@frappe.whitelist()
136-
def auto_create_fiscal_year():
137-
for d in frappe.db.sql(
138-
"""select name from `tabFiscal Year` where year_end_date = date_add(current_date, interval 3 day)"""
139-
):
105+
for d in fiscal_year:
140106
try:
141107
current_fy = frappe.get_doc("Fiscal Year", d[0])
142108

143-
new_fy = frappe.copy_doc(current_fy, ignore_no_copy=False)
109+
new_fy = frappe.new_doc("Fiscal Year")
110+
new_fy.disabled = cint(current_fy.disabled)
144111

145112
new_fy.year_start_date = add_days(current_fy.year_end_date, 1)
146113
new_fy.year_end_date = add_years(current_fy.year_end_date, 1)
147114

148115
start_year = cstr(new_fy.year_start_date.year)
149116
end_year = cstr(new_fy.year_end_date.year)
150117
new_fy.year = start_year if start_year == end_year else (start_year + "-" + end_year)
118+
119+
for row in current_fy.companies:
120+
new_fy.append("companies", {"company": row.company})
121+
151122
new_fy.auto_created = 1
152123

153124
new_fy.insert(ignore_permissions=True)

erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
"ignore_user_permissions": 1,
1616
"in_list_view": 1,
1717
"label": "Company",
18-
"options": "Company"
18+
"options": "Company",
19+
"reqd": 1
1920
}
2021
],
2122
"index_web_pages_for_search": 1,
2223
"istable": 1,
2324
"links": [],
24-
"modified": "2021-09-28 18:01:53.495929",
25+
"modified": "2026-02-20 23:02:26.193606",
2526
"modified_by": "Administrator",
2627
"module": "Accounts",
2728
"name": "Fiscal Year Company",
@@ -30,4 +31,4 @@
3031
"sort_field": "modified",
3132
"sort_order": "DESC",
3233
"track_changes": 1
33-
}
34+
}

erpnext/accounts/doctype/fiscal_year_company/fiscal_year_company.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class FiscalYearCompany(Document):
1414
if TYPE_CHECKING:
1515
from frappe.types import DF
1616

17-
company: DF.Link | None
17+
company: DF.Link
1818
parent: DF.Data
1919
parentfield: DF.Data
2020
parenttype: DF.Data
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<h4>{{ _("New Fiscal Year - {0}").format(doc.name) }}</h4>
2+
3+
<p>{{ _("A new fiscal year has been automatically created.") }}</p>
4+
5+
<p>{{ _("Fiscal Year Details") }}</p>
6+
7+
<table style="margin-bottom: 1rem; width: 70%">
8+
<tr>
9+
<td style="font-weight:bold; width: 40%">{{ _("Year Name") }}</td>
10+
<td>{{ doc.name }}</td>
11+
</tr>
12+
<tr>
13+
<td style="font-weight:bold; width: 40%">{{ _("Start Date") }}</td>
14+
<td>{{ frappe.format_value(doc.year_start_date) }}</td>
15+
</tr>
16+
<tr>
17+
<td style="font-weight:bold; width: 40%">{{ _("End Date") }}</td>
18+
<td>{{ frappe.format_value(doc.year_end_date) }}</td>
19+
</tr>
20+
{% if doc.companies|length > 0 %}
21+
<tr>
22+
<td style="vertical-align: top; font-weight: bold; width: 40%" rowspan="{{ doc.companies|length }}">
23+
{% if doc.companies|length < 2 %}
24+
{{ _("Company") }}
25+
{% else %}
26+
{{ _("Companies") }}
27+
{% endif %}
28+
</td>
29+
<td>{{ doc.companies[0].company }}</td>
30+
</tr>
31+
{% for idx in range(1, doc.companies|length) %}
32+
<tr>
33+
<td>{{ doc.companies[idx].company }}</td>
34+
</tr>
35+
{% endfor %}
36+
{% endif %}
37+
</table>
38+
39+
{% if doc.disabled %}
40+
<p>{{ _("The fiscal year has been automatically created in a Disabled state to maintain consistency with the previous fiscal year's status.") }}</p>
41+
{% endif %}
42+
43+
<p>{{ _("Please review the {0} configuration and complete any required financial setup activities.").format(frappe.utils.get_link_to_form("Fiscal Year", doc.name, frappe.bold("Fiscal Year"))) }}</p>
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"attach_print": 0,
33
"channel": "Email",
4-
"condition": "doc.auto_created",
4+
"condition": "doc.auto_created == 1",
55
"creation": "2018-04-25 14:19:05.440361",
66
"days_in_advance": 0,
77
"docstatus": 0,
@@ -11,19 +11,22 @@
1111
"event": "New",
1212
"idx": 0,
1313
"is_standard": 1,
14-
"message": "<h3>{{_(\"Fiscal Year\")}}</h3>\n\n<p>{{ _(\"New fiscal year created :- \") }} {{ doc.name }}</p>",
15-
"modified": "2018-04-25 14:30:38.588534",
14+
"message": "<h4>{{ _(\"New Fiscal Year - {0}\").format(doc.name) }}</h4>\n\n<p>{{ _(\"A new fiscal year has been automatically created.\") }}</p>\n\n<p>{{ _(\"Fiscal Year Details\") }}</p>\n\n<table style=\"margin-bottom: 1rem; width: 70%\">\n <tr>\n <td style=\"font-weight:bold; width: 40%\">{{ _(\"Year Name\") }}</td>\n <td>{{ doc.name }}</td>\n </tr>\n <tr>\n <td style=\"font-weight:bold; width: 40%\">{{ _(\"Start Date\") }}</td>\n <td>{{ frappe.format_value(doc.year_start_date) }}</td>\n </tr>\n <tr>\n <td style=\"font-weight:bold; width: 40%\">{{ _(\"End Date\") }}</td>\n <td>{{ frappe.format_value(doc.year_end_date) }}</td>\n </tr>\n {% if doc.companies|length > 0 %}\n <tr>\n <td style=\"vertical-align: top; font-weight: bold; width: 40%\" rowspan=\"{{ doc.companies|length }}\">\n {% if doc.companies|length < 2 %}\n {{ _(\"Company\") }}\n {% else %}\n {{ _(\"Companies\") }}\n {% endif %}\n </td>\n <td>{{ doc.companies[0].company }}</td>\n </tr>\n {% for idx in range(1, doc.companies|length) %}\n <tr>\n <td>{{ doc.companies[idx].company }}</td>\n </tr>\n {% endfor %}\n {% endif %}\n</table>\n\n{% if doc.disabled %}\n<p>{{ _(\"The fiscal year has been automatically created in a Disabled state to maintain consistency with the previous fiscal year's status.\") }}</p>\n{% endif %}\n\n<p>{{ _(\"Please review the {0} configuration and complete any required financial setup activities.\").format(frappe.utils.get_link_to_form(\"Fiscal Year\", doc.name, frappe.bold(\"Fiscal Year\"))) }}</p>",
15+
"message_type": "HTML",
16+
"modified": "2026-02-21 15:59:07.775679",
1617
"modified_by": "Administrator",
1718
"module": "Accounts",
1819
"name": "Notification for new fiscal year",
1920
"owner": "Administrator",
2021
"recipients": [
2122
{
22-
"email_by_role": "Accounts User"
23+
"receiver_by_role": "Accounts Manager"
2324
},
2425
{
25-
"email_by_role": "Accounts Manager"
26+
"receiver_by_role": "Accounts User"
2627
}
2728
],
28-
"subject": "Notification for new fiscal year {{ doc.name }}"
29+
"send_system_notification": 0,
30+
"send_to_all_assignees": 0,
31+
"subject": "{{ _(\"New Fiscal Year {0} - Review Required\").format(doc.name) }}"
2932
}

0 commit comments

Comments
 (0)