blob: 50f37be27b8ba7f7e519dacafdc75cb131d00dc8 [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
Nabin Haite2c200a2015-05-28 13:00:37 +0530256 round_off_debit_credit(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
Nabin Haite2c200a2015-05-28 13:00:37 +0530305def round_off_debit_credit(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
Nabin Haite2c200a2015-05-28 13:00:37 +0530311 debit_credit_diff = 0.0
312 for entry in gl_map:
313 entry.debit = flt(entry.debit, precision)
314 entry.credit = flt(entry.credit, precision)
315 debit_credit_diff += entry.debit - entry.credit
Anand Doshi602e8252015-11-16 19:05:46 +0530316
Nabin Haite2c200a2015-05-28 13:00:37 +0530317 debit_credit_diff = flt(debit_credit_diff, precision)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530318
Nabin Haitd2a966e2017-05-05 10:41:16 +0530319 if gl_map[0]["voucher_type"] in ("Journal Entry", "Payment Entry"):
Nabin Haitfb24a272016-02-18 19:18:07 +0530320 allowance = 5.0 / (10**precision)
321 else:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530322 allowance = 0.5
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530323
Saqib Ansarib0e160f2021-04-22 13:23:50 +0530324 if abs(debit_credit_diff) > allowance:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530325 frappe.throw(
326 _("Debit and Credit not equal for {0} #{1}. Difference is {2}.").format(
327 gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff
328 )
329 )
Anand Doshi602e8252015-11-16 19:05:46 +0530330
Saqib Ansariaa4f7502021-04-28 14:42:49 +0530331 elif abs(debit_credit_diff) >= (1.0 / (10**precision)):
Nabin Hait34c551d2019-07-03 10:34:31 +0530332 make_round_off_gle(gl_map, debit_credit_diff, precision)
Anand Doshi602e8252015-11-16 19:05:46 +0530333
Ankush Menat494bd9e2022-03-28 18:52:46 +0530334
Nabin Hait34c551d2019-07-03 10:34:31 +0530335def make_round_off_gle(gl_map, debit_credit_diff, precision):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530336 round_off_account, round_off_cost_center = get_round_off_account_and_cost_center(
337 gl_map[0].company
338 )
Zarrar3523b772018-08-14 16:28:14 +0530339 round_off_account_exists = False
Nabin Hait80069a62015-05-28 19:19:59 +0530340 round_off_gle = frappe._dict()
Zarrar3523b772018-08-14 16:28:14 +0530341 for d in gl_map:
342 if d.account == round_off_account:
343 round_off_gle = d
Saqibc6e016e2021-06-04 10:08:22 +0530344 if d.debit:
345 debit_credit_diff -= flt(d.debit)
Zarrar3523b772018-08-14 16:28:14 +0530346 else:
Saqibc6e016e2021-06-04 10:08:22 +0530347 debit_credit_diff += flt(d.credit)
Zarrar3523b772018-08-14 16:28:14 +0530348 round_off_account_exists = True
349
Saqib Ansariad2c64f2022-03-01 13:32:34 +0530350 if round_off_account_exists and abs(debit_credit_diff) < (1.0 / (10**precision)):
Nabin Hait34c551d2019-07-03 10:34:31 +0530351 gl_map.remove(round_off_gle)
352 return
353
Zarrar3523b772018-08-14 16:28:14 +0530354 if not round_off_gle:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530355 for k in ["voucher_type", "voucher_no", "company", "posting_date", "remarks"]:
356 round_off_gle[k] = gl_map[0][k]
Anand Doshi602e8252015-11-16 19:05:46 +0530357
Ankush Menat494bd9e2022-03-28 18:52:46 +0530358 round_off_gle.update(
359 {
360 "account": round_off_account,
361 "debit_in_account_currency": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
362 "credit_in_account_currency": debit_credit_diff if debit_credit_diff > 0 else 0,
363 "debit": abs(debit_credit_diff) if debit_credit_diff < 0 else 0,
364 "credit": debit_credit_diff if debit_credit_diff > 0 else 0,
365 "cost_center": round_off_cost_center,
366 "party_type": None,
367 "party": None,
368 "is_opening": "No",
369 "against_voucher_type": None,
370 "against_voucher": None,
371 }
372 )
Anand Doshi602e8252015-11-16 19:05:46 +0530373
Zarrar3523b772018-08-14 16:28:14 +0530374 if not round_off_account_exists:
375 gl_map.append(round_off_gle)
Nabin Haite2c200a2015-05-28 13:00:37 +0530376
Ankush Menat494bd9e2022-03-28 18:52:46 +0530377
Nabin Hait2e4de832017-09-19 14:53:16 +0530378def get_round_off_account_and_cost_center(company):
Ankush Menat494bd9e2022-03-28 18:52:46 +0530379 round_off_account, round_off_cost_center = frappe.get_cached_value(
380 "Company", company, ["round_off_account", "round_off_cost_center"]
381 ) or [None, None]
Nabin Hait2e4de832017-09-19 14:53:16 +0530382 if not round_off_account:
383 frappe.throw(_("Please mention Round Off Account in Company"))
384
385 if not round_off_cost_center:
386 frappe.throw(_("Please mention Round Off Cost Center in Company"))
387
388 return round_off_account, round_off_cost_center
389
Ankush Menat494bd9e2022-03-28 18:52:46 +0530390
391def make_reverse_gl_entries(
392 gl_entries=None, voucher_type=None, voucher_no=None, adv_adj=False, update_outstanding="Yes"
393):
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530394 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530395 Get original gl entries of the voucher
396 and make reverse gl entries by swapping debit and credit
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530397 """
Anand Doshi652bc072014-04-16 15:21:46 +0530398
Nabin Hait2e296fa2013-08-28 18:53:11 +0530399 if not gl_entries:
Deepesh Gargff574502022-02-06 22:56:12 +0530400 gl_entry = frappe.qb.DocType("GL Entry")
Ankush Menat494bd9e2022-03-28 18:52:46 +0530401 gl_entries = (
402 frappe.qb.from_(gl_entry)
403 .select("*")
404 .where(gl_entry.voucher_type == voucher_type)
405 .where(gl_entry.voucher_no == voucher_no)
406 .where(gl_entry.is_cancelled == 0)
407 .for_update()
408 ).run(as_dict=1)
Nabin Hait56548cb2016-07-01 15:58:39 +0530409
Nabin Hait27994c22013-08-26 16:53:30 +0530410 if gl_entries:
Deepesh Garg069a54e2020-08-10 16:01:01 +0530411 validate_accounting_period(gl_entries)
Nabin Hait27994c22013-08-26 16:53:30 +0530412 check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530413 set_as_cancel(gl_entries[0]["voucher_type"], gl_entries[0]["voucher_no"])
Anand Doshi652bc072014-04-16 15:21:46 +0530414
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530415 for entry in gl_entries:
Deepesh Gargffec8652022-02-02 17:14:42 +0530416 new_gle = copy.deepcopy(entry)
Ankush Menat494bd9e2022-03-28 18:52:46 +0530417 new_gle["name"] = None
418 debit = new_gle.get("debit", 0)
419 credit = new_gle.get("credit", 0)
Anand Doshi652bc072014-04-16 15:21:46 +0530420
Ankush Menat494bd9e2022-03-28 18:52:46 +0530421 debit_in_account_currency = new_gle.get("debit_in_account_currency", 0)
422 credit_in_account_currency = new_gle.get("credit_in_account_currency", 0)
Rushabh Mehta708e47a2018-08-08 16:37:31 +0530423
Ankush Menat494bd9e2022-03-28 18:52:46 +0530424 new_gle["debit"] = credit
425 new_gle["credit"] = debit
426 new_gle["debit_in_account_currency"] = credit_in_account_currency
427 new_gle["credit_in_account_currency"] = debit_in_account_currency
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530428
Ankush Menat494bd9e2022-03-28 18:52:46 +0530429 new_gle["remarks"] = "On cancellation of " + new_gle["voucher_no"]
430 new_gle["is_cancelled"] = 1
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530431
Ankush Menat494bd9e2022-03-28 18:52:46 +0530432 if new_gle["debit"] or new_gle["credit"]:
Deepesh Gargffec8652022-02-02 17:14:42 +0530433 make_entry(new_gle, adv_adj, "Yes")
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530434
435
436def check_freezing_date(posting_date, adv_adj=False):
437 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530438 Nobody can do GL Entries where posting date is before freezing date
439 except authorized person
Deepesh Garg13d2e7b2021-09-16 18:54:57 +0530440
Ankush Menat494bd9e2022-03-28 18:52:46 +0530441 Administrator has all the roles so this check will be bypassed if any role is allowed to post
442 Hence stop admin to bypass if accounts are freezed
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530443 """
444 if not adv_adj:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530445 acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto")
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530446 if acc_frozen_upto:
Ankush Menat494bd9e2022-03-28 18:52:46 +0530447 frozen_accounts_modifier = frappe.db.get_value(
448 "Accounts Settings", None, "frozen_accounts_modifier"
449 )
450 if getdate(posting_date) <= getdate(acc_frozen_upto) and (
451 frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator"
452 ):
453 frappe.throw(
454 _("You are not authorized to add or update entries before {0}").format(
455 formatdate(acc_frozen_upto)
456 )
457 )
458
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530459
460def set_as_cancel(voucher_type, voucher_no):
461 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530462 Set is_cancelled=1 in all original gl entries for the voucher
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530463 """
Ankush Menat494bd9e2022-03-28 18:52:46 +0530464 frappe.db.sql(
465 """UPDATE `tabGL Entry` SET is_cancelled = 1,
Deepesh Garg2a9c5ba2020-04-30 10:38:58 +0530466 modified=%s, modified_by=%s
467 where voucher_type=%s and voucher_no=%s and is_cancelled = 0""",
Ankush Menat494bd9e2022-03-28 18:52:46 +0530468 (now(), frappe.session.user, voucher_type, voucher_no),
469 )