blob: b0513f16a592f83d067639c8429380e144bc0ec7 [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
ruthra kumare8889752022-05-16 14:28:25 +053017from erpnext.accounts.utils import create_payment_ledger_entry
Chillar Anand915b3432021-09-02 16:44:59 +053018
Nabin Haitbf495c92013-01-30 12:49:08 +053019
Ankush Menat494bd9e2022-03-28 18:52:46 +053020class ClosedAccountingPeriod(frappe.ValidationError):
21 pass
Nabin Haitbf495c92013-01-30 12:49:08 +053022
Ankush Menat494bd9e2022-03-28 18:52:46 +053023
24def make_gl_entries(
25 gl_map,
26 cancel=False,
27 adv_adj=False,
28 merge_entries=True,
29 update_outstanding="Yes",
30 from_repost=False,
31):
Nabin Hait2e296fa2013-08-28 18:53:11 +053032 if gl_map:
33 if not cancel:
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053034 validate_accounting_period(gl_map)
Saqib Ansari95b059a2022-05-11 13:26:15 +053035 validate_disabled_accounts(gl_map)
Nabin Hait2e296fa2013-08-28 18:53:11 +053036 gl_map = process_gl_map(gl_map, merge_entries)
nabinhaitc3432922014-07-29 18:06:18 +053037 if gl_map and len(gl_map) > 1:
ruthra kumare8889752022-05-16 14:28:25 +053038 create_payment_ledger_entry(gl_map)
Nabin Haita77b8c92020-12-21 14:45:50 +053039 save_entries(gl_map, adv_adj, update_outstanding, from_repost)
Deepesh Garg4c8d15b2021-04-26 15:24:34 +053040 # Post GL Map proccess there may no be any GL Entries
41 elif gl_map:
Ankush Menat494bd9e2022-03-28 18:52:46 +053042 frappe.throw(
43 _(
44 "Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction."
45 )
46 )
Nabin Hait2e296fa2013-08-28 18:53:11 +053047 else:
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +053048 make_reverse_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
Anand Doshi652bc072014-04-16 15:21:46 +053049
Ankush Menat494bd9e2022-03-28 18:52:46 +053050
Saqib Ansari95b059a2022-05-11 13:26:15 +053051def validate_disabled_accounts(gl_map):
52 accounts = [d.account for d in gl_map if d.account]
53
54 Account = frappe.qb.DocType("Account")
55
56 disabled_accounts = (
57 frappe.qb.from_(Account)
58 .where(Account.name.isin(accounts) & Account.disabled == 1)
59 .select(Account.name, Account.disabled)
60 ).run(as_dict=True)
61
62 if disabled_accounts:
63 account_list = "<br>"
64 account_list += ", ".join([frappe.bold(d.name) for d in disabled_accounts])
65 frappe.throw(
66 _("Cannot create accounting entries against disabled accounts: {0}").format(account_list),
67 title=_("Disabled Account Selected"),
68 )
69
70
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053071def validate_accounting_period(gl_map):
Ankush Menat494bd9e2022-03-28 18:52:46 +053072 accounting_periods = frappe.db.sql(
73 """ SELECT
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053074 ap.name as name
75 FROM
76 `tabAccounting Period` ap, `tabClosed Document` cd
77 WHERE
78 ap.name = cd.parent
79 AND ap.company = %(company)s
80 AND cd.closed = 1
81 AND cd.document_type = %(voucher_type)s
82 AND %(date)s between ap.start_date and ap.end_date
Ankush Menat494bd9e2022-03-28 18:52:46 +053083 """,
84 {
85 "date": gl_map[0].posting_date,
86 "company": gl_map[0].company,
87 "voucher_type": gl_map[0].voucher_type,
88 },
89 as_dict=1,
90 )
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +053091
92 if accounting_periods:
Ankush Menat494bd9e2022-03-28 18:52:46 +053093 frappe.throw(
94 _(
95 "You cannot create or cancel any accounting entries with in the closed Accounting Period {0}"
96 ).format(frappe.bold(accounting_periods[0].name)),
97 ClosedAccountingPeriod,
98 )
99
Mangesh-Khairnare5c733b2019-08-08 15:44:11 +0530100
Nabin Hait19f8fa52021-02-22 22:27:22 +0530101def process_gl_map(gl_map, merge_entries=True, precision=None):
Nabin Hait6099af52022-01-31 17:24:50 +0530102 if not gl_map:
103 return []
104
Nabin Hait004c1ed2022-01-31 13:20:18 +0530105 gl_map = distribute_gl_based_on_cost_center_allocation(gl_map, precision)
106
Nabin Haitbf495c92013-01-30 12:49:08 +0530107 if merge_entries:
Nabin Hait19f8fa52021-02-22 22:27:22 +0530108 gl_map = merge_similar_entries(gl_map, precision)
Anand Doshi602e8252015-11-16 19:05:46 +0530109
Nabin Hait004c1ed2022-01-31 13:20:18 +0530110 gl_map = toggle_debit_credit_if_negative(gl_map)
Deepesh Garg5ba3b282021-11-25 15:42:30 +0530111
Nabin Hait27994c22013-08-26 16:53:30 +0530112 return gl_map
Anand Doshi652bc072014-04-16 15:21:46 +0530113
Ankush Menat494bd9e2022-03-28 18:52:46 +0530114
Nabin Hait004c1ed2022-01-31 13:20:18 +0530115def distribute_gl_based_on_cost_center_allocation(gl_map, precision=None):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530116 cost_center_allocation = get_cost_center_allocation_data(
117 gl_map[0]["company"], gl_map[0]["posting_date"]
118 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530119 if not cost_center_allocation:
120 return gl_map
Deepesh Garg5ba3b282021-11-25 15:42:30 +0530121
Nabin Hait004c1ed2022-01-31 13:20:18 +0530122 new_gl_map = []
123 for d in gl_map:
124 cost_center = d.get("cost_center")
125 if cost_center and cost_center_allocation.get(cost_center):
126 for sub_cost_center, percentage in cost_center_allocation.get(cost_center, {}).items():
127 gle = copy.deepcopy(d)
128 gle.cost_center = sub_cost_center
129 for field in ("debit", "credit", "debit_in_account_currency", "credit_in_company_currency"):
130 gle[field] = flt(flt(d.get(field)) * percentage / 100, precision)
131 new_gl_map.append(gle)
132 else:
133 new_gl_map.append(d)
134
135 return new_gl_map
136
Ankush Menat494bd9e2022-03-28 18:52:46 +0530137
Nabin Hait004c1ed2022-01-31 13:20:18 +0530138def get_cost_center_allocation_data(company, posting_date):
139 par = frappe.qb.DocType("Cost Center Allocation")
140 child = frappe.qb.DocType("Cost Center Allocation Percentage")
141
142 records = (
Ankush Menat494bd9e2022-03-28 18:52:46 +0530143 frappe.qb.from_(par)
144 .inner_join(child)
145 .on(par.name == child.parent)
Nabin Hait004c1ed2022-01-31 13:20:18 +0530146 .select(par.main_cost_center, child.cost_center, child.percentage)
147 .where(par.docstatus == 1)
148 .where(par.company == company)
149 .where(par.valid_from <= posting_date)
150 .orderby(par.valid_from, order=frappe.qb.desc)
151 ).run(as_dict=True)
152
153 cc_allocation = frappe._dict()
154 for d in records:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530155 cc_allocation.setdefault(d.main_cost_center, frappe._dict()).setdefault(
156 d.cost_center, d.percentage
157 )
Nabin Hait5b0ec642022-01-31 18:07:04 +0530158
Nabin Hait004c1ed2022-01-31 13:20:18 +0530159 return cc_allocation
Deepesh Garg5ba3b282021-11-25 15:42:30 +0530160
Ankush Menat494bd9e2022-03-28 18:52:46 +0530161
Nabin Hait19f8fa52021-02-22 22:27:22 +0530162def merge_similar_entries(gl_map, precision=None):
Nabin Haitbf495c92013-01-30 12:49:08 +0530163 merged_gl_map = []
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530164 accounting_dimensions = get_accounting_dimensions()
Nabin Haitbf495c92013-01-30 12:49:08 +0530165 for entry in gl_map:
Anand Doshi652bc072014-04-16 15:21:46 +0530166 # if there is already an entry in this account then just add it
Nabin Haitbf495c92013-01-30 12:49:08 +0530167 # to that entry
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530168 same_head = check_if_in_list(entry, merged_gl_map, accounting_dimensions)
Nabin Haitbf495c92013-01-30 12:49:08 +0530169 if same_head:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530170 same_head.debit = flt(same_head.debit) + flt(entry.debit)
171 same_head.debit_in_account_currency = flt(same_head.debit_in_account_currency) + flt(
172 entry.debit_in_account_currency
173 )
Nabin Hait2e296fa2013-08-28 18:53:11 +0530174 same_head.credit = flt(same_head.credit) + flt(entry.credit)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530175 same_head.credit_in_account_currency = flt(same_head.credit_in_account_currency) + flt(
176 entry.credit_in_account_currency
177 )
Nabin Haitbf495c92013-01-30 12:49:08 +0530178 else:
179 merged_gl_map.append(entry)
Anand Doshi652bc072014-04-16 15:21:46 +0530180
thefalconx33bfc43d32019-12-13 15:09:51 +0530181 company = gl_map[0].company if gl_map else erpnext.get_default_company()
182 company_currency = erpnext.get_company_currency(company)
Nabin Hait19f8fa52021-02-22 22:27:22 +0530183
184 if not precision:
185 precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"), company_currency)
thefalconx33bfc43d32019-12-13 15:09:51 +0530186
Nabin Hait815a49e2013-08-07 17:00:01 +0530187 # filter zero debit and credit entries
Ankush Menat494bd9e2022-03-28 18:52:46 +0530188 merged_gl_map = filter(
189 lambda x: flt(x.debit, precision) != 0 or flt(x.credit, precision) != 0, merged_gl_map
190 )
Achilles Rasquinha908289d2018-03-08 13:10:51 +0530191 merged_gl_map = list(merged_gl_map)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530192
Nabin Haitbf495c92013-01-30 12:49:08 +0530193 return merged_gl_map
194
Ankush Menat494bd9e2022-03-28 18:52:46 +0530195
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530196def check_if_in_list(gle, gl_map, dimensions=None):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530197 account_head_fieldnames = [
198 "voucher_detail_no",
199 "party",
200 "against_voucher",
201 "cost_center",
202 "against_voucher_type",
203 "party_type",
204 "project",
205 "finance_book",
206 ]
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530207
208 if dimensions:
209 account_head_fieldnames = account_head_fieldnames + dimensions
210
Nabin Haitbb777562013-08-29 18:19:37 +0530211 for e in gl_map:
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530212 same_head = True
213 if e.account != gle.account:
214 same_head = False
Ankush91527152021-08-11 11:17:50 +0530215 continue
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530216
217 for fieldname in account_head_fieldnames:
218 if cstr(e.get(fieldname)) != cstr(gle.get(fieldname)):
219 same_head = False
Ankush91527152021-08-11 11:17:50 +0530220 break
deepeshgarg0073d11ac02019-05-19 00:02:01 +0530221
222 if same_head:
223 return e
Nabin Haitbf495c92013-01-30 12:49:08 +0530224
Ankush Menat494bd9e2022-03-28 18:52:46 +0530225
Nabin Hait004c1ed2022-01-31 13:20:18 +0530226def toggle_debit_credit_if_negative(gl_map):
227 for entry in gl_map:
228 # toggle debit, credit if negative entry
229 if flt(entry.debit) < 0:
230 entry.credit = flt(entry.credit) - flt(entry.debit)
231 entry.debit = 0.0
232
233 if flt(entry.debit_in_account_currency) < 0:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530234 entry.credit_in_account_currency = flt(entry.credit_in_account_currency) - flt(
235 entry.debit_in_account_currency
236 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530237 entry.debit_in_account_currency = 0.0
238
239 if flt(entry.credit) < 0:
240 entry.debit = flt(entry.debit) - flt(entry.credit)
241 entry.credit = 0.0
242
243 if flt(entry.credit_in_account_currency) < 0:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530244 entry.debit_in_account_currency = flt(entry.debit_in_account_currency) - flt(
245 entry.credit_in_account_currency
246 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530247 entry.credit_in_account_currency = 0.0
248
249 update_net_values(entry)
250
251 return gl_map
252
Ankush Menat494bd9e2022-03-28 18:52:46 +0530253
Nabin Hait004c1ed2022-01-31 13:20:18 +0530254def update_net_values(entry):
255 # In some scenarios net value needs to be shown in the ledger
256 # This method updates net values as debit or credit
257 if entry.post_net_value and entry.debit and entry.credit:
258 if entry.debit > entry.credit:
259 entry.debit = entry.debit - entry.credit
Ankush Menat494bd9e2022-03-28 18:52:46 +0530260 entry.debit_in_account_currency = (
261 entry.debit_in_account_currency - entry.credit_in_account_currency
262 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530263 entry.credit = 0
264 entry.credit_in_account_currency = 0
265 else:
266 entry.credit = entry.credit - entry.debit
Ankush Menat494bd9e2022-03-28 18:52:46 +0530267 entry.credit_in_account_currency = (
268 entry.credit_in_account_currency - entry.debit_in_account_currency
269 )
Nabin Hait004c1ed2022-01-31 13:20:18 +0530270
271 entry.debit = 0
272 entry.debit_in_account_currency = 0
273
Ankush Menat494bd9e2022-03-28 18:52:46 +0530274
Nabin Haita77b8c92020-12-21 14:45:50 +0530275def save_entries(gl_map, adv_adj, update_outstanding, from_repost=False):
276 if not from_repost:
277 validate_cwip_accounts(gl_map)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530278
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530279 process_debit_credit_difference(gl_map)
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530280
281 if gl_map:
282 check_freezing_date(gl_map[0]["posting_date"], adv_adj)
283
Nabin Haitbf495c92013-01-30 12:49:08 +0530284 for entry in gl_map:
Nabin Haita77b8c92020-12-21 14:45:50 +0530285 make_entry(entry, adv_adj, update_outstanding, from_repost)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530286
Ankush Menat494bd9e2022-03-28 18:52:46 +0530287
Nabin Haita77b8c92020-12-21 14:45:50 +0530288def make_entry(args, adv_adj, update_outstanding, from_repost=False):
Nabin Haitddc3bb22020-03-17 17:04:18 +0530289 gle = frappe.new_doc("GL Entry")
290 gle.update(args)
Anand Doshi6dfd4302015-02-10 14:41:27 +0530291 gle.flags.ignore_permissions = 1
Nabin Haita77b8c92020-12-21 14:45:50 +0530292 gle.flags.from_repost = from_repost
Nabin Hait19f8fa52021-02-22 22:27:22 +0530293 gle.flags.adv_adj = adv_adj
Ankush Menat494bd9e2022-03-28 18:52:46 +0530294 gle.flags.update_outstanding = update_outstanding or "Yes"
Nabin Haitaeba24e2013-08-23 15:17:36 +0530295 gle.submit()
Anand Doshi652bc072014-04-16 15:21:46 +0530296
Nabin Haita77b8c92020-12-21 14:45:50 +0530297 if not from_repost:
298 validate_expense_against_budget(args)
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530299
Ankush Menat494bd9e2022-03-28 18:52:46 +0530300
Anurag Mishra7e1987e2019-08-05 10:18:57 +0530301def validate_cwip_accounts(gl_map):
Ankush91527152021-08-11 11:17:50 +0530302 """Validate that CWIP account are not used in Journal Entry"""
303 if gl_map and gl_map[0].voucher_type != "Journal Entry":
304 return
Maricad00c5982019-11-12 19:17:43 +0530305
Ankush Menat494bd9e2022-03-28 18:52:46 +0530306 cwip_enabled = any(
307 cint(ac.enable_cwip_accounting)
308 for ac in frappe.db.get_all("Asset Category", "enable_cwip_accounting")
309 )
Ankush91527152021-08-11 11:17:50 +0530310 if cwip_enabled:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530311 cwip_accounts = [
312 d[0]
313 for d in frappe.db.sql(
314 """select name from tabAccount
315 where account_type = 'Capital Work in Progress' and is_group=0"""
316 )
317 ]
Anurag Mishra7e1987e2019-08-05 10:18:57 +0530318
Ankush91527152021-08-11 11:17:50 +0530319 for entry in gl_map:
320 if entry.account in cwip_accounts:
321 frappe.throw(
Ankush Menat494bd9e2022-03-28 18:52:46 +0530322 _(
323 "Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry"
324 ).format(entry.account)
325 )
326
Anurag Mishra7e1987e2019-08-05 10:18:57 +0530327
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530328def process_debit_credit_difference(gl_map):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530329 precision = get_field_precision(
330 frappe.get_meta("GL Entry").get_field("debit"),
331 currency=frappe.get_cached_value("Company", gl_map[0].company, "default_currency"),
332 )
Anand Doshi602e8252015-11-16 19:05:46 +0530333
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530334 voucher_type = gl_map[0].voucher_type
335 voucher_no = gl_map[0].voucher_no
336 allowance = get_debit_credit_allowance(voucher_type, precision)
337
338 debit_credit_diff = get_debit_credit_difference(gl_map, precision)
339 if abs(debit_credit_diff) > allowance:
340 raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_no)
341
342 elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
343 make_round_off_gle(gl_map, debit_credit_diff, precision)
344
345 debit_credit_diff = get_debit_credit_difference(gl_map, precision)
346 if abs(debit_credit_diff) > allowance:
347 raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_no)
348
349
350def get_debit_credit_difference(gl_map, precision):
Nabin Haite2c200a2015-05-28 13:00:37 +0530351 debit_credit_diff = 0.0
352 for entry in gl_map:
353 entry.debit = flt(entry.debit, precision)
354 entry.credit = flt(entry.credit, precision)
355 debit_credit_diff += entry.debit - entry.credit
Anand Doshi602e8252015-11-16 19:05:46 +0530356
Nabin Haite2c200a2015-05-28 13:00:37 +0530357 debit_credit_diff = flt(debit_credit_diff, precision)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530358
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530359 return debit_credit_diff
360
361
362def get_debit_credit_allowance(voucher_type, precision):
363 if voucher_type in ("Journal Entry", "Payment Entry"):
Nabin Haitfb24a272016-02-18 19:18:07 +0530364 allowance = 5.0 / (10**precision)
365 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530366 allowance = 0.5
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530367
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530368 return allowance
Anand Doshi602e8252015-11-16 19:05:46 +0530369
Saqib Ansaribfc34e12022-04-01 11:03:16 +0530370
371def raise_debit_credit_not_equal_error(debit_credit_diff, voucher_type, voucher_no):
372 frappe.throw(
373 _("Debit and Credit not equal for {0} #{1}. Difference is {2}.").format(
374 voucher_type, voucher_no, debit_credit_diff
375 )
376 )
Anand Doshi602e8252015-11-16 19:05:46 +0530377
Ankush Menat494bd9e2022-03-28 18:52:46 +0530378
Nabin Hait34c551d2019-07-03 10:34:31 +0530379def make_round_off_gle(gl_map, debit_credit_diff, precision):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530380 round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
Deepesh Garg0ac11a52022-04-20 12:18:11 +0530381 gl_map[0].company, gl_map[0].voucher_type, gl_map[0].voucher_no
Ankush Menat494bd9e2022-03-28 18:52:46 +0530382 )
Zarrar3523b772018-08-14 16:28:14 +0530383 round_off_account_exists = False
Nabin Hait80069a62015-05-28 19:19:59 +0530384 round_off_gle = frappe._dict()
Zarrar3523b772018-08-14 16:28:14 +0530385 for d in gl_map:
386 if d.account == round_off_account:
387 round_off_gle = d
Saqibc6e016e2021-06-04 10:08:22 +0530388 if d.debit:
389 debit_credit_diff -= flt(d.debit)
Zarrar3523b772018-08-14 16:28:14 +0530390 else:
Saqibc6e016e2021-06-04 10:08:22 +0530391 debit_credit_diff += flt(d.credit)
Zarrar3523b772018-08-14 16:28:14 +0530392 round_off_account_exists = True
393
Saqib Ansariad2c64f2022-03-01 13:32:34 +0530394 if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
Nabin Hait34c551d2019-07-03 10:34:31 +0530395 gl_map.remove(round_off_gle)
396 return
397
Zarrar3523b772018-08-14 16:28:14 +0530398 if not round_off_gle:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530399 for k in ["voucher_type", "voucher_no", "company", "posting_date", "remarks"]:
400 round_off_gle[k] = gl_map[0][k]
Anand Doshi602e8252015-11-16 19:05:46 +0530401
Ankush Menat494bd9e2022-03-28 18:52:46 +0530402 round_off_gle.update(
403 {
404 "account": round_off_account,
405 "debit_in_account_currency": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
406 "credit_in_account_currency": debit_credit_diff if debit_credit_diff > 0 else 0,
407 "debit": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
408 "credit": debit_credit_diff if debit_credit_diff > 0 else 0,
409 "cost_center": round_off_cost_center,
410 "party_type": None,
411 "party": None,
412 "is_opening": "No",
413 "against_voucher_type": None,
414 "against_voucher": None,
415 }
416 )
Anand Doshi602e8252015-11-16 19:05:46 +0530417
Deepesh Garg015812b2022-04-23 21:40:08 +0530418 update_accounting_dimensions(round_off_gle)
419
Zarrar3523b772018-08-14 16:28:14 +0530420 if not round_off_account_exists:
421 gl_map.append(round_off_gle)
Nabin Haite2c200a2015-05-28 13:00:37 +0530422
Ankush Menat494bd9e2022-03-28 18:52:46 +0530423
Deepesh Garg015812b2022-04-23 21:40:08 +0530424def update_accounting_dimensions(round_off_gle):
425 dimensions = get_accounting_dimensions()
Deepesh Gargc312cd32022-04-24 18:11:32 +0530426 meta = frappe.get_meta(round_off_gle["voucher_type"])
427 has_all_dimensions = True
Deepesh Garg015812b2022-04-23 21:40:08 +0530428
429 for dimension in dimensions:
Deepesh Gargc312cd32022-04-24 18:11:32 +0530430 if not meta.has_field(dimension):
431 has_all_dimensions = False
432
433 if dimensions and has_all_dimensions:
434 dimension_values = frappe.db.get_value(
Deepesh Garg3fa1c632022-04-25 16:29:26 +0530435 round_off_gle["voucher_type"], round_off_gle["voucher_no"], dimensions, as_dict=1
Deepesh Gargc312cd32022-04-24 18:11:32 +0530436 )
437
438 for dimension in dimensions:
439 round_off_gle[dimension] = dimension_values.get(dimension)
Deepesh Garg015812b2022-04-23 21:40:08 +0530440
441
Deepesh Garg0ac11a52022-04-20 12:18:11 +0530442def get_round_off_account_and_cost_center(company, voucher_type, voucher_no):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530443 round_off_account, round_off_cost_center = frappe.get_cached_value(
444 "Company", company, ["round_off_account", "round_off_cost_center"]
445 ) or [None, None]
Deepesh Garg0ac11a52022-04-20 12:18:11 +0530446
Deepesh Gargc312cd32022-04-24 18:11:32 +0530447 meta = frappe.get_meta(voucher_type)
448
Deepesh Garg0ac11a52022-04-20 12:18:11 +0530449 # Give first preference to parent cost center for round off GLE
Deepesh Gargc312cd32022-04-24 18:11:32 +0530450 if meta.has_field("cost_center"):
Deepesh Garg0ac11a52022-04-20 12:18:11 +0530451 parent_cost_center = frappe.db.get_value(voucher_type, voucher_no, "cost_center")
452 if parent_cost_center:
453 round_off_cost_center = parent_cost_center
454
Nabin Hait2e4de832017-09-19 14:53:16 +0530455 if not round_off_account:
456 frappe.throw(_("Please mention Round Off Account in Company"))
457
458 if not round_off_cost_center:
459 frappe.throw(_("Please mention Round Off Cost Center in Company"))
460
461 return round_off_account, round_off_cost_center
462
Ankush Menat494bd9e2022-03-28 18:52:46 +0530463
464def make_reverse_gl_entries(
465 gl_entries=None, voucher_type=None, voucher_no=None, adv_adj=False, update_outstanding="Yes"
466):
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530467 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530468 Get original gl entries of the voucher
469 and make reverse gl entries by swapping debit and credit
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530470 """
Anand Doshi652bc072014-04-16 15:21:46 +0530471
Nabin Hait2e296fa2013-08-28 18:53:11 +0530472 if not gl_entries:
Deepesh Gargff574502022-02-06 22:56:12 +0530473 gl_entry = frappe.qb.DocType("GL Entry")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530474 gl_entries = (
475 frappe.qb.from_(gl_entry)
476 .select("*")
477 .where(gl_entry.voucher_type == voucher_type)
478 .where(gl_entry.voucher_no == voucher_no)
479 .where(gl_entry.is_cancelled == 0)
480 .for_update()
481 ).run(as_dict=1)
Nabin Hait56548cb2016-07-01 15:58:39 +0530482
Nabin Hait27994c22013-08-26 16:53:30 +0530483 if gl_entries:
ruthra kumare8889752022-05-16 14:28:25 +0530484 create_payment_ledger_entry(gl_entries, cancel=1)
Deepesh Garg069a54e2020-08-10 16:01:01 +0530485 validate_accounting_period(gl_entries)
Nabin Hait27994c22013-08-26 16:53:30 +0530486 check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530487 set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
Anand Doshi652bc072014-04-16 15:21:46 +0530488
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530489 for entry in gl_entries:
Deepesh Gargffec8652022-02-02 17:14:42 +0530490 new_gle = copy.deepcopy(entry)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530491 new_gle["name"] = None
492 debit = new_gle.get("debit", 0)
493 credit = new_gle.get("credit", 0)
Anand Doshi652bc072014-04-16 15:21:46 +0530494
Ankush Menat494bd9e2022-03-28 18:52:46 +0530495 debit_in_account_currency = new_gle.get("debit_in_account_currency", 0)
496 credit_in_account_currency = new_gle.get("credit_in_account_currency", 0)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530497
Ankush Menat494bd9e2022-03-28 18:52:46 +0530498 new_gle["debit"] = credit
499 new_gle["credit"] = debit
500 new_gle["debit_in_account_currency"] = credit_in_account_currency
501 new_gle["credit_in_account_currency"] = debit_in_account_currency
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530502
Ankush Menat494bd9e2022-03-28 18:52:46 +0530503 new_gle["remarks"] = "On cancellation of " + new_gle["voucher_no"]
504 new_gle["is_cancelled"] = 1
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530505
Ankush Menat494bd9e2022-03-28 18:52:46 +0530506 if new_gle["debit"] or new_gle["credit"]:
Deepesh Gargffec8652022-02-02 17:14:42 +0530507 make_entry(new_gle, adv_adj, "Yes")
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530508
509
510def check_freezing_date(posting_date, adv_adj=False):
511 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530512 Nobody can do GL Entries where posting date is before freezing date
513 except authorized person
Deepesh Garg13d2e7b2021-09-16 18:54:57 +0530514
Ankush Menat494bd9e2022-03-28 18:52:46 +0530515 Administrator has all the roles so this check will be bypassed if any role is allowed to post
516 Hence stop admin to bypass if accounts are freezed
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530517 """
518 if not adv_adj:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530519 acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto")
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530520 if acc_frozen_upto:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530521 frozen_accounts_modifier = frappe.db.get_value(
522 "Accounts Settings", None, "frozen_accounts_modifier"
523 )
524 if getdate(posting_date) <= getdate(acc_frozen_upto) and (
525 frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator"
526 ):
527 frappe.throw(
528 _("You are not authorized to add or update entries before {0}").format(
529 formatdate(acc_frozen_upto)
530 )
531 )
532
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530533
534def set_as_cancel(voucher_type, voucher_no):
535 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530536 Set is_cancelled=1 in all original gl entries for the voucher
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530537 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530538 frappe.db.sql(
539 """UPDATE `tabGL Entry` SET is_cancelled = 1,
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530540 modified=%s, modified_by=%s
541 where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
Ankush Menat494bd9e2022-03-28 18:52:46 +0530542 (now(), frappe.session.user, voucher_type, voucher_no),
543 )