blob: f52e517f73085149cd5a0df3e1ec84c49fee7d21 [file] [log] [blame]
Anand Doshi885e0742015-03-03 14:55:30 +05301# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
Rushabh Mehtae67d1fb2013-08-05 14:59:54 +05302# License: GNU General Public License v3. See license.txt
Nabin Haitbf495c92013-01-30 12:49:08 +05303
Chillar Anand915b3432021-09-02 16:44:59 +05304
Nabin Hait004c1ed2022-01-31 13:20:18 +05305import copy
Nabin Hait5b0ec642022-01-31 18:07:04 +05306
7import frappe
Rushabh Mehta793ba6b2014-02-14 15:47:51 +05308from frappe import _
Nabin Haite2c200a2015-05-28 13:00:37 +05309from frappe.model.meta import get_field_precision
Chillar Anand915b3432021-09-02 16:44:59 +053010from frappe.utils import cint, cstr, flt, formatdate, getdate, now
11
12import erpnext
13from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
14 get_accounting_dimensions,
15)
Nabin Haitb9bc7d62016-05-16 14:38:47 +053016from erpnext.accounts.doctype.budget.budget import validate_expense_against_budget
Chillar Anand915b3432021-09-02 16:44:59 +053017
Nabin Haitbf495c92013-01-30 12:49:08 +053018
Ankush Menat494bd9e2022-03-28 18:52:46 +053019class ClosedAccountingPeriod(frappe.ValidationError):
20 pass
Nabin Haitbf495c92013-01-30 12:49:08 +053021
Ankush Menat494bd9e2022-03-28 18:52:46 +053022
23def make_gl_entries(
24 gl_map,
25 cancel=False,
26 adv_adj=False,
27 merge_entries=True,
28 update_outstanding="Yes",
29 from_repost=False,
30):
Nabin Hait2e296fa2013-08-28 18:53:11 +053031 if gl_map:
32 if not cancel:
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053033 validate_accounting_period(gl_map)
Nabin Hait2e296fa2013-08-28 18:53:11 +053034 gl_map = process_gl_map(gl_map, merge_entries)
nabinhaitc3432922014-07-29 18:06:18 +053035 if gl_map and len(gl_map) > 1:
Nabin Haita77b8c92020-12-21 14:45:50 +053036 save_entries(gl_map, adv_adj, update_outstanding, from_repost)
Deepesh Garg4c8d15b2021-04-26 15:24:34 +053037 # Post GL Map proccess there may no be any GL Entries
38 elif gl_map:
Ankush Menat494bd9e2022-03-28 18:52:46 +053039 frappe.throw(
40 _(
41 "Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."
42 )
43 )
Nabin Hait2e296fa2013-08-28 18:53:11 +053044 else:
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +053045 make_reverse_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
Anand Doshi652bc072014-04-16 15:21:46 +053046
Ankush Menat494bd9e2022-03-28 18:52:46 +053047
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053048def validate_accounting_period(gl_map):
Ankush Menat494bd9e2022-03-28 18:52:46 +053049 accounting_periods = frappe.db.sql(
50 """ SELECT
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053051 ap.name as name
52 FROM
53 `tabAccounting Period` ap, `tabClosed Document` cd
54 WHERE
55 ap.name = cd.parent
56 AND ap.company = %(company)s
57 AND cd.closed = 1
58 AND cd.document_type = %(voucher_type)s
59 AND %(date)s between ap.start_date and ap.end_date
Ankush Menat494bd9e2022-03-28 18:52:46 +053060 """,
61 {
62 "date": gl_map[0].posting_date,
63 "company": gl_map[0].company,
64 "voucher_type": gl_map[0].voucher_type,
65 },
66 as_dict=1,
67 )
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053068
69 if accounting_periods:
Ankush Menat494bd9e2022-03-28 18:52:46 +053070 frappe.throw(
71 _(
72 "You cannot create or cancel any accounting entries with in the closed Accounting Period {0}"
73 ).format(frappe.bold(accounting_periods[0].name)),
74 ClosedAccountingPeriod,
75 )
76
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053077
Nabin Hait19f8fa52021-02-22 22:27:22 +053078def process_gl_map(gl_map, merge_entries=True, precision=None):
Nabin Hait6099af52022-01-31 17:24:50 +053079 if not gl_map:
80 return []
81
Nabin Hait004c1ed2022-01-31 13:20:18 +053082 gl_map = distribute_gl_based_on_cost_center_allocation(gl_map, precision)
83
Nabin Haitbf495c92013-01-30 12:49:08 +053084 if merge_entries:
Nabin Hait19f8fa52021-02-22 22:27:22 +053085 gl_map = merge_similar_entries(gl_map, precision)
Anand Doshi602e8252015-11-16 19:05:46 +053086
Nabin Hait004c1ed2022-01-31 13:20:18 +053087 gl_map = toggle_debit_credit_if_negative(gl_map)
Deepesh Garg5ba3b282021-11-25 15:42:30 +053088
Nabin Hait27994c22013-08-26 16:53:30 +053089 return gl_map
Anand Doshi652bc072014-04-16 15:21:46 +053090
Ankush Menat494bd9e2022-03-28 18:52:46 +053091
Nabin Hait004c1ed2022-01-31 13:20:18 +053092def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
Ankush Menat494bd9e2022-03-28 18:52:46 +053093 cost_center_allocation = get_cost_center_allocation_data(
94 gl_map[0]["company"], gl_map[0]["posting_date"]
95 )
Nabin Hait004c1ed2022-01-31 13:20:18 +053096 if not cost_center_allocation:
97 return gl_map
Deepesh Garg5ba3b282021-11-25 15:42:30 +053098
Nabin Hait004c1ed2022-01-31 13:20:18 +053099 new_gl_map = []
100 for d in gl_map:
101 cost_center = d.get("cost_center")
102 if cost_center and cost_center_allocation.get(cost_center):
103 for sub_cost_center, percentage in cost_center_allocation.get(cost_center, {}).items():
104 gle = copy.deepcopy(d)
105 gle.cost_center = sub_cost_center
106 for field in ("debit", "credit", "debit_in_account_currency", "credit_in_company_currency"):
107 gle[field] = flt(flt(d.get(field)) * percentage / 100, precision)
108 new_gl_map.append(gle)
109 else:
110 new_gl_map.append(d)
111
112 return new_gl_map
113
Ankush Menat494bd9e2022-03-28 18:52:46 +0530114
Nabin Hait004c1ed2022-01-31 13:20:18 +0530115def get_cost_center_allocation_data(company, posting_date):
116 par = frappe.qb.DocType("Cost Center Allocation")
117 child = frappe.qb.DocType("Cost Center Allocation Percentage")
118
119 records = (
Ankush Menat494bd9e2022-03-28 18:52:46 +0530120 frappe.qb.from_(par)
121 .inner_join(child)
122 .on(par.name == child.parent)
Nabin Hait004c1ed2022-01-31 13:20:18 +0530123 .select(par.main_cost_center, child.cost_center, child.percentage)
124 .where(par.docstatus == 1)
125 .where(par.company == company)
126 .where(par.valid_from <= posting_date)
127 .orderby(par.valid_from, order=frappe.qb.desc)
128 ).run(as_dict=True)
129
130 cc_allocation = frappe._dict()
131 for d in records:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530132 cc_allocation.setdefault(d.main_cost_center, frappe._dict()).setdefault(
133 d.cost_center, d.percentage
134 )
Nabin Hait5b0ec642022-01-31 18:07:04 +0530135
Nabin Hait004c1ed2022-01-31 13:20:18 +0530136 return cc_allocation
Deepesh Garg5ba3b282021-11-25 15:42:30 +0530137
Ankush Menat494bd9e2022-03-28 18:52:46 +0530138
Nabin Hait19f8fa52021-02-22 22:27:22 +0530139def merge_similar_entries(gl_map, precision=None):
Nabin Haitbf495c92013-01-30 12:49:08 +0530140 merged_gl_map = []
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530141 accounting_dimensions = get_accounting_dimensions()
Nabin Haitbf495c92013-01-30 12:49:08 +0530142 for entry in gl_map:
Anand Doshi652bc072014-04-16 15:21:46 +0530143 # if there is already an entry in this account then just add it
Nabin Haitbf495c92013-01-30 12:49:08 +0530144 # to that entry
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530145 same_head = check_if_in_list(entry, merged_gl_map, accounting_dimensions)
Nabin Haitbf495c92013-01-30 12:49:08 +0530146 if same_head:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530147 same_head.debit = flt(same_head.debit) + flt(entry.debit)
148 same_head.debit_in_account_currency = flt(same_head.debit_in_account_currency) + flt(
149 entry.debit_in_account_currency
150 )
Nabin Hait2e296fa2013-08-28 18:53:11 +0530151 same_head.credit = flt(same_head.credit) + flt(entry.credit)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530152 same_head.credit_in_account_currency = flt(same_head.credit_in_account_currency) + flt(
153 entry.credit_in_account_currency
154 )
Nabin Haitbf495c92013-01-30 12:49:08 +0530155 else:
156 merged_gl_map.append(entry)
Anand Doshi652bc072014-04-16 15:21:46 +0530157
thefalconx33bfc43d32019-12-13 15:09:51 +0530158 company = gl_map[0].company if gl_map else erpnext.get_default_company()
159 company_currency = erpnext.get_company_currency(company)
Nabin Hait19f8fa52021-02-22 22:27:22 +0530160
161 if not precision:
162 precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
thefalconx33bfc43d32019-12-13 15:09:51 +0530163
Nabin Hait815a49e2013-08-07 17:00:01 +0530164 # filter zero debit and credit entries
Ankush Menat494bd9e2022-03-28 18:52:46 +0530165 merged_gl_map = filter(
166 lambda x: flt(x.debit, precision) != 0 or flt(x.credit, precision) != 0, merged_gl_map
167 )
Achilles Rasquinha908289d2018-03-08 13:10:51 +0530168 merged_gl_map = list(merged_gl_map)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530169
Nabin Haitbf495c92013-01-30 12:49:08 +0530170 return merged_gl_map
171
Ankush Menat494bd9e2022-03-28 18:52:46 +0530172
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530173def check_if_in_list(gle, gl_map, dimensions=None):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530174 account_head_fieldnames = [
175 "voucher_detail_no",
176 "party",
177 "against_voucher",
178 "cost_center",
179 "against_voucher_type",
180 "party_type",
181 "project",
182 "finance_book",
183 ]
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530184
185 if dimensions:
186 account_head_fieldnames = account_head_fieldnames + dimensions
187
Nabin Haitbb777562013-08-29 18:19:37 +0530188 for e in gl_map:
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530189 same_head = True
190 if e.account != gle.account:
191 same_head = False
Ankush91527152021-08-11 11:17:50 +0530192 continue
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530193
194 for fieldname in account_head_fieldnames:
195 if cstr(e.get(fieldname)) != cstr(gle.get(fieldname)):
196 same_head = False
Ankush91527152021-08-11 11:17:50 +0530197 break
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530198
199 if same_head:
200 return e
Nabin Haitbf495c92013-01-30 12:49:08 +0530201
Ankush Menat494bd9e2022-03-28 18:52:46 +0530202
Nabin Hait004c1ed2022-01-31 13:20:18 +0530203def toggle_debit_credit_if_negative(gl_map):
204 for entry in gl_map:
205 # toggle debit, credit if negative entry
206 if flt(entry.debit) < 0:
207 entry.credit = flt(entry.credit) - flt(entry.debit)
208 entry.debit = 0.0
209
210 if flt(entry.debit_in_account_currency) < 0:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530211 entry.credit_in_account_currency = flt(entry.credit_in_account_currency) - flt(
212 entry.debit_in_account_currency
213 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530214 entry.debit_in_account_currency = 0.0
215
216 if flt(entry.credit) < 0:
217 entry.debit = flt(entry.debit) - flt(entry.credit)
218 entry.credit = 0.0
219
220 if flt(entry.credit_in_account_currency) < 0:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530221 entry.debit_in_account_currency = flt(entry.debit_in_account_currency) - flt(
222 entry.credit_in_account_currency
223 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530224 entry.credit_in_account_currency = 0.0
225
226 update_net_values(entry)
227
228 return gl_map
229
Ankush Menat494bd9e2022-03-28 18:52:46 +0530230
Nabin Hait004c1ed2022-01-31 13:20:18 +0530231def update_net_values(entry):
232 # In some scenarios net value needs to be shown in the ledger
233 # This method updates net values as debit or credit
234 if entry.post_net_value and entry.debit and entry.credit:
235 if entry.debit > entry.credit:
236 entry.debit = entry.debit - entry.credit
Ankush Menat494bd9e2022-03-28 18:52:46 +0530237 entry.debit_in_account_currency = (
238 entry.debit_in_account_currency - entry.credit_in_account_currency
239 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530240 entry.credit = 0
241 entry.credit_in_account_currency = 0
242 else:
243 entry.credit = entry.credit - entry.debit
Ankush Menat494bd9e2022-03-28 18:52:46 +0530244 entry.credit_in_account_currency = (
245 entry.credit_in_account_currency - entry.debit_in_account_currency
246 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530247
248 entry.debit = 0
249 entry.debit_in_account_currency = 0
250
Ankush Menat494bd9e2022-03-28 18:52:46 +0530251
Nabin Haita77b8c92020-12-21 14:45:50 +0530252def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
253 if not from_repost:
254 validate_cwip_accounts(gl_map)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530255
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530256 process_debit_credit_difference(gl_map)
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530257
258 if gl_map:
259 check_freezing_date(gl_map[0]["posting_date"], adv_adj)
260
Nabin Haitbf495c92013-01-30 12:49:08 +0530261 for entry in gl_map:
Nabin Haita77b8c92020-12-21 14:45:50 +0530262 make_entry(entry, adv_adj, update_outstanding, from_repost)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530263
Ankush Menat494bd9e2022-03-28 18:52:46 +0530264
Nabin Haita77b8c92020-12-21 14:45:50 +0530265def make_entry(args, adv_adj, update_outstanding, from_repost=False):
Nabin Haitddc3bb22020-03-17 17:04:18 +0530266 gle = frappe.new_doc("GL Entry")
267 gle.update(args)
Anand Doshi6dfd4302015-02-10 14:41:27 +0530268 gle.flags.ignore_permissions = 1
Nabin Haita77b8c92020-12-21 14:45:50 +0530269 gle.flags.from_repost = from_repost
Nabin Hait19f8fa52021-02-22 22:27:22 +0530270 gle.flags.adv_adj = adv_adj
Ankush Menat494bd9e2022-03-28 18:52:46 +0530271 gle.flags.update_outstanding = update_outstanding or "Yes"
Nabin Haitaeba24e2013-08-23 15:17:36 +0530272 gle.submit()
Anand Doshi652bc072014-04-16 15:21:46 +0530273
Nabin Haita77b8c92020-12-21 14:45:50 +0530274 if not from_repost:
275 validate_expense_against_budget(args)
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530276
Ankush Menat494bd9e2022-03-28 18:52:46 +0530277
Anurag Mishra7e1987e2019-08-05 10:18:57 +0530278def validate_cwip_accounts(gl_map):
Ankush91527152021-08-11 11:17:50 +0530279 """Validate that CWIP account are not used in Journal Entry"""
280 if gl_map and gl_map[0].voucher_type != "Journal Entry":
281 return
Maricad00c5982019-11-12 19:17:43 +0530282
Ankush Menat494bd9e2022-03-28 18:52:46 +0530283 cwip_enabled = any(
284 cint(ac.enable_cwip_accounting)
285 for ac in frappe.db.get_all("Asset Category", "enable_cwip_accounting")
286 )
Ankush91527152021-08-11 11:17:50 +0530287 if cwip_enabled:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530288 cwip_accounts = [
289 d[0]
290 for d in frappe.db.sql(
291 """select name from tabAccount
292 where account_type = 'Capital Work in Progress' and is_group=0"""
293 )
294 ]
Anurag Mishra7e1987e2019-08-05 10:18:57 +0530295
Ankush91527152021-08-11 11:17:50 +0530296 for entry in gl_map:
297 if entry.account in cwip_accounts:
298 frappe.throw(
Ankush Menat494bd9e2022-03-28 18:52:46 +0530299 _(
300 "Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry"
301 ).format(entry.account)
302 )
303
Anurag Mishra7e1987e2019-08-05 10:18:57 +0530304
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530305def process_debit_credit_difference(gl_map):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530306 precision = get_field_precision(
307 frappe.get_meta("GL Entry").get_field("debit"),
308 currency=frappe.get_cached_value("Company", gl_map[0].company, "default_currency"),
309 )
Anand Doshi602e8252015-11-16 19:05:46 +0530310
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530311 voucher_type = gl_map[0].voucher_type
312 voucher_no = gl_map[0].voucher_no
313 allowance = get_debit_credit_allowance(voucher_type, precision)
314
315 debit_credit_diff = get_debit_credit_difference(gl_map, precision)
316 if abs(debit_credit_diff) > allowance:
317 raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_no)
318
319 elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
320 make_round_off_gle(gl_map, debit_credit_diff, precision)
321
322 debit_credit_diff = get_debit_credit_difference(gl_map, precision)
323 if abs(debit_credit_diff) > allowance:
324 raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_no)
325
326
327def get_debit_credit_difference(gl_map, precision):
Nabin Haite2c200a2015-05-28 13:00:37 +0530328 debit_credit_diff = 0.0
329 for entry in gl_map:
330 entry.debit = flt(entry.debit, precision)
331 entry.credit = flt(entry.credit, precision)
332 debit_credit_diff += entry.debit - entry.credit
Anand Doshi602e8252015-11-16 19:05:46 +0530333
Nabin Haite2c200a2015-05-28 13:00:37 +0530334 debit_credit_diff = flt(debit_credit_diff, precision)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530335
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530336 return debit_credit_diff
337
338
339def get_debit_credit_allowance(voucher_type, precision):
340 if voucher_type in ("Journal Entry", "Payment Entry"):
Nabin Haitfb24a272016-02-18 19:18:07 +0530341 allowance = 5.0 / (10**precision)
342 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530343 allowance = 0.5
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530344
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530345 return allowance
Anand Doshi602e8252015-11-16 19:05:46 +0530346
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530347
348def raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_no):
349 frappe.throw(
350 _("Debit and Credit not equal for {0} #{1}. Difference is {2}.").format(
351 voucher_type, voucher_no, debit_credit_diff
352 )
353 )
Anand Doshi602e8252015-11-16 19:05:46 +0530354
Ankush Menat494bd9e2022-03-28 18:52:46 +0530355
Nabin Hait34c551d2019-07-03 10:34:31 +0530356def make_round_off_gle(gl_map, debit_credit_diff, precision):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530357 round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
358 gl_map[0].company
359 )
Zarrar3523b772018-08-14 16:28:14 +0530360 round_off_account_exists = False
Nabin Hait80069a62015-05-28 19:19:59 +0530361 round_off_gle = frappe._dict()
Zarrar3523b772018-08-14 16:28:14 +0530362 for d in gl_map:
363 if d.account == round_off_account:
364 round_off_gle = d
Saqibc6e016e2021-06-04 10:08:22 +0530365 if d.debit:
366 debit_credit_diff -= flt(d.debit)
Zarrar3523b772018-08-14 16:28:14 +0530367 else:
Saqibc6e016e2021-06-04 10:08:22 +0530368 debit_credit_diff += flt(d.credit)
Zarrar3523b772018-08-14 16:28:14 +0530369 round_off_account_exists = True
370
Saqib Ansariad2c64f2022-03-01 13:32:34 +0530371 if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
Nabin Hait34c551d2019-07-03 10:34:31 +0530372 gl_map.remove(round_off_gle)
373 return
374
Zarrar3523b772018-08-14 16:28:14 +0530375 if not round_off_gle:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530376 for k in ["voucher_type", "voucher_no", "company", "posting_date", "remarks"]:
377 round_off_gle[k] = gl_map[0][k]
Anand Doshi602e8252015-11-16 19:05:46 +0530378
Ankush Menat494bd9e2022-03-28 18:52:46 +0530379 round_off_gle.update(
380 {
381 "account": round_off_account,
382 "debit_in_account_currency": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
383 "credit_in_account_currency": debit_credit_diff if debit_credit_diff > 0 else 0,
384 "debit": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
385 "credit": debit_credit_diff if debit_credit_diff > 0 else 0,
386 "cost_center": round_off_cost_center,
387 "party_type": None,
388 "party": None,
389 "is_opening": "No",
390 "against_voucher_type": None,
391 "against_voucher": None,
392 }
393 )
Anand Doshi602e8252015-11-16 19:05:46 +0530394
Zarrar3523b772018-08-14 16:28:14 +0530395 if not round_off_account_exists:
396 gl_map.append(round_off_gle)
Nabin Haite2c200a2015-05-28 13:00:37 +0530397
Ankush Menat494bd9e2022-03-28 18:52:46 +0530398
Nabin Hait2e4de832017-09-19 14:53:16 +0530399def get_round_off_account_and_cost_center(company):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530400 round_off_account, round_off_cost_center = frappe.get_cached_value(
401 "Company", company, ["round_off_account", "round_off_cost_center"]
402 ) or [None, None]
Nabin Hait2e4de832017-09-19 14:53:16 +0530403 if not round_off_account:
404 frappe.throw(_("Please mention Round Off Account in Company"))
405
406 if not round_off_cost_center:
407 frappe.throw(_("Please mention Round Off Cost Center in Company"))
408
409 return round_off_account, round_off_cost_center
410
Ankush Menat494bd9e2022-03-28 18:52:46 +0530411
412def make_reverse_gl_entries(
413 gl_entries=None, voucher_type=None, voucher_no=None, adv_adj=False, update_outstanding="Yes"
414):
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530415 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530416 Get original gl entries of the voucher
417 and make reverse gl entries by swapping debit and credit
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530418 """
Anand Doshi652bc072014-04-16 15:21:46 +0530419
Nabin Hait2e296fa2013-08-28 18:53:11 +0530420 if not gl_entries:
Deepesh Gargff574502022-02-06 22:56:12 +0530421 gl_entry = frappe.qb.DocType("GL Entry")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530422 gl_entries = (
423 frappe.qb.from_(gl_entry)
424 .select("*")
425 .where(gl_entry.voucher_type == voucher_type)
426 .where(gl_entry.voucher_no == voucher_no)
427 .where(gl_entry.is_cancelled == 0)
428 .for_update()
429 ).run(as_dict=1)
Nabin Hait56548cb2016-07-01 15:58:39 +0530430
Nabin Hait27994c22013-08-26 16:53:30 +0530431 if gl_entries:
Deepesh Garg069a54e2020-08-10 16:01:01 +0530432 validate_accounting_period(gl_entries)
Nabin Hait27994c22013-08-26 16:53:30 +0530433 check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530434 set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
Anand Doshi652bc072014-04-16 15:21:46 +0530435
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530436 for entry in gl_entries:
Deepesh Gargffec8652022-02-02 17:14:42 +0530437 new_gle = copy.deepcopy(entry)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530438 new_gle["name"] = None
439 debit = new_gle.get("debit", 0)
440 credit = new_gle.get("credit", 0)
Anand Doshi652bc072014-04-16 15:21:46 +0530441
Ankush Menat494bd9e2022-03-28 18:52:46 +0530442 debit_in_account_currency = new_gle.get("debit_in_account_currency", 0)
443 credit_in_account_currency = new_gle.get("credit_in_account_currency", 0)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530444
Ankush Menat494bd9e2022-03-28 18:52:46 +0530445 new_gle["debit"] = credit
446 new_gle["credit"] = debit
447 new_gle["debit_in_account_currency"] = credit_in_account_currency
448 new_gle["credit_in_account_currency"] = debit_in_account_currency
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530449
Ankush Menat494bd9e2022-03-28 18:52:46 +0530450 new_gle["remarks"] = "On cancellation of " + new_gle["voucher_no"]
451 new_gle["is_cancelled"] = 1
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530452
Ankush Menat494bd9e2022-03-28 18:52:46 +0530453 if new_gle["debit"] or new_gle["credit"]:
Deepesh Gargffec8652022-02-02 17:14:42 +0530454 make_entry(new_gle, adv_adj, "Yes")
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530455
456
457def check_freezing_date(posting_date, adv_adj=False):
458 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530459 Nobody can do GL Entries where posting date is before freezing date
460 except authorized person
Deepesh Garg13d2e7b2021-09-16 18:54:57 +0530461
Ankush Menat494bd9e2022-03-28 18:52:46 +0530462 Administrator has all the roles so this check will be bypassed if any role is allowed to post
463 Hence stop admin to bypass if accounts are freezed
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530464 """
465 if not adv_adj:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530466 acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto")
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530467 if acc_frozen_upto:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530468 frozen_accounts_modifier = frappe.db.get_value(
469 "Accounts Settings", None, "frozen_accounts_modifier"
470 )
471 if getdate(posting_date) <= getdate(acc_frozen_upto) and (
472 frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator"
473 ):
474 frappe.throw(
475 _("You are not authorized to add or update entries before {0}").format(
476 formatdate(acc_frozen_upto)
477 )
478 )
479
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530480
481def set_as_cancel(voucher_type, voucher_no):
482 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530483 Set is_cancelled=1 in all original gl entries for the voucher
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530484 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530485 frappe.db.sql(
486 """UPDATE `tabGL Entry` SET is_cancelled = 1,
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530487 modified=%s, modified_by=%s
488 where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
Ankush Menat494bd9e2022-03-28 18:52:46 +0530489 (now(), frappe.session.user, voucher_type, voucher_no),
490 )