2015-03-03 09:25:30 +00:00
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2013-08-05 09:29:54 +00:00
# License: GNU General Public License v3. See license.txt
2013-01-30 07:19:08 +00:00
from __future__ import unicode_literals
2014-02-14 10:17:51 +00:00
import frappe
from frappe . utils import flt , cstr
from frappe import _
2013-12-12 13:42:19 +00:00
from erpnext . accounts . utils import validate_expense_against_budget
2013-01-30 07:19:08 +00:00
2013-08-29 12:49:37 +00:00
2014-02-14 10:17:51 +00:00
class StockAccountInvalidTransaction ( frappe . ValidationError ) : pass
2013-01-30 07:19:08 +00:00
2014-04-16 09:51:46 +00:00
def make_gl_entries ( gl_map , cancel = False , adv_adj = False , merge_entries = True ,
2013-01-30 07:19:08 +00:00
update_outstanding = ' Yes ' ) :
2013-08-28 13:23:11 +00:00
if gl_map :
if not cancel :
gl_map = process_gl_map ( gl_map , merge_entries )
2014-07-29 12:36:18 +00:00
if gl_map and len ( gl_map ) > 1 :
2014-07-29 12:17:02 +00:00
save_entries ( gl_map , adv_adj , update_outstanding )
2014-07-29 12:36:18 +00:00
else :
2014-07-30 08:58:24 +00:00
frappe . throw ( _ ( " Incorrect number of General Ledger Entries found. You might have selected a wrong Account in the transaction. " ) )
2013-08-28 13:23:11 +00:00
else :
delete_gl_entries ( gl_map , adv_adj = adv_adj , update_outstanding = update_outstanding )
2014-04-16 09:51:46 +00:00
2013-08-26 11:23:30 +00:00
def process_gl_map ( gl_map , merge_entries = True ) :
2013-01-30 07:19:08 +00:00
if merge_entries :
gl_map = merge_similar_entries ( gl_map )
2014-04-16 09:51:46 +00:00
2013-08-26 11:23:30 +00:00
for entry in gl_map :
# toggle debit, credit if negative entry
2013-10-23 10:59:19 +00:00
if flt ( entry . debit ) < 0 :
entry . credit = flt ( entry . credit ) - flt ( entry . debit )
entry . debit = 0.0
if flt ( entry . credit ) < 0 :
entry . debit = flt ( entry . debit ) - flt ( entry . credit )
entry . credit = 0.0
2013-02-14 08:08:12 +00:00
2013-08-26 11:23:30 +00:00
return gl_map
2014-04-16 09:51:46 +00:00
2013-01-30 07:19:08 +00:00
def merge_similar_entries ( gl_map ) :
merged_gl_map = [ ]
for entry in gl_map :
2014-04-16 09:51:46 +00:00
# if there is already an entry in this account then just add it
2013-01-30 07:19:08 +00:00
# to that entry
same_head = check_if_in_list ( entry , merged_gl_map )
if same_head :
2013-08-28 13:23:11 +00:00
same_head . debit = flt ( same_head . debit ) + flt ( entry . debit )
same_head . credit = flt ( same_head . credit ) + flt ( entry . credit )
2013-01-30 07:19:08 +00:00
else :
merged_gl_map . append ( entry )
2014-04-16 09:51:46 +00:00
2013-08-07 11:30:01 +00:00
# filter zero debit and credit entries
2013-08-28 13:23:11 +00:00
merged_gl_map = filter ( lambda x : flt ( x . debit ) != 0 or flt ( x . credit ) != 0 , merged_gl_map )
2013-01-30 07:19:08 +00:00
return merged_gl_map
2013-08-29 12:49:37 +00:00
def check_if_in_list ( gle , gl_map ) :
for e in gl_map :
2013-08-28 13:23:11 +00:00
if e . account == gle . account and \
2013-01-30 07:19:08 +00:00
cstr ( e . get ( ' against_voucher ' ) ) == cstr ( gle . get ( ' against_voucher ' ) ) \
and cstr ( e . get ( ' against_voucher_type ' ) ) == \
cstr ( gle . get ( ' against_voucher_type ' ) ) \
and cstr ( e . get ( ' cost_center ' ) ) == cstr ( gle . get ( ' cost_center ' ) ) :
return e
2013-08-21 12:17:11 +00:00
def save_entries ( gl_map , adv_adj , update_outstanding ) :
2013-08-29 12:49:37 +00:00
validate_account_for_auto_accounting_for_stock ( gl_map )
2014-04-16 09:51:46 +00:00
2013-01-30 07:19:08 +00:00
total_debit = total_credit = 0.0
for entry in gl_map :
2013-08-23 09:47:36 +00:00
make_entry ( entry , adv_adj , update_outstanding )
2013-08-26 11:23:30 +00:00
# check against budget
2013-08-23 05:16:41 +00:00
validate_expense_against_budget ( entry )
2014-04-16 09:51:46 +00:00
2013-01-30 07:19:08 +00:00
# update total debit / credit
2013-08-28 13:23:11 +00:00
total_debit + = flt ( entry . debit )
total_credit + = flt ( entry . credit )
2014-04-16 09:51:46 +00:00
2015-05-19 09:57:16 +00:00
validate_total_debit_credit ( total_debit , total_credit , gl_map )
2014-04-16 09:51:46 +00:00
2013-08-23 09:47:36 +00:00
def make_entry ( args , adv_adj , update_outstanding ) :
args . update ( { " doctype " : " GL Entry " } )
2014-04-04 06:46:26 +00:00
gle = frappe . get_doc ( args )
2015-02-10 09:11:27 +00:00
gle . flags . ignore_permissions = 1
2013-08-23 09:47:36 +00:00
gle . insert ( )
gle . run_method ( " on_update_with_args " , adv_adj , update_outstanding )
gle . submit ( )
2014-04-16 09:51:46 +00:00
2015-05-19 09:57:16 +00:00
def validate_total_debit_credit ( total_debit , total_credit , gl_map ) :
2013-01-30 07:19:08 +00:00
if abs ( total_debit - total_credit ) > 0.005 :
2015-05-19 09:57:16 +00:00
frappe . throw ( _ ( " Debit and Credit not equal for {0} # {1} . Difference is {2} . " ) . format ( gl_map [ 0 ] . voucher_type , gl_map [ 0 ] . voucher_no , total_debit - total_credit ) )
2014-04-16 09:51:46 +00:00
2013-08-29 12:49:37 +00:00
def validate_account_for_auto_accounting_for_stock ( gl_map ) :
2014-12-25 11:44:18 +00:00
if gl_map [ 0 ] . voucher_type == " Journal Entry " :
2014-04-16 09:51:46 +00:00
aii_accounts = [ d [ 0 ] for d in frappe . db . sql ( """ select name from tabAccount
2014-08-27 06:35:48 +00:00
where account_type = ' Warehouse ' and ifnull ( warehouse , ' ' ) != ' ' """ )]
2014-04-16 09:51:46 +00:00
2013-08-29 12:49:37 +00:00
for entry in gl_map :
if entry . account in aii_accounts :
2014-10-06 06:23:52 +00:00
frappe . throw ( _ ( " Account: {0} can only be updated via Stock Transactions " ) . format ( entry . account ) , StockAccountInvalidTransaction )
2014-04-16 09:51:46 +00:00
def delete_gl_entries ( gl_entries = None , voucher_type = None , voucher_no = None ,
2013-08-28 13:23:11 +00:00
adv_adj = False , update_outstanding = " Yes " ) :
2014-04-16 09:51:46 +00:00
2014-03-03 13:48:17 +00:00
from erpnext . accounts . doctype . gl_entry . gl_entry import validate_balance_type , \
2013-09-24 09:06:55 +00:00
check_freezing_date , update_outstanding_amt , validate_frozen_account
2014-04-16 09:51:46 +00:00
2013-08-28 13:23:11 +00:00
if not gl_entries :
2014-04-16 09:51:46 +00:00
gl_entries = frappe . db . sql ( """ select * from `tabGL Entry`
2013-08-28 13:23:11 +00:00
where voucher_type = % s and voucher_no = % s """ , (voucher_type, voucher_no), as_dict=True)
2013-08-26 11:23:30 +00:00
if gl_entries :
check_freezing_date ( gl_entries [ 0 ] [ " posting_date " ] , adv_adj )
2014-04-16 09:51:46 +00:00
frappe . db . sql ( """ delete from `tabGL Entry` where voucher_type= %s and voucher_no= %s """ ,
2013-08-28 13:23:11 +00:00
( voucher_type or gl_entries [ 0 ] [ " voucher_type " ] , voucher_no or gl_entries [ 0 ] [ " voucher_no " ] ) )
2014-04-16 09:51:46 +00:00
2013-08-21 12:17:11 +00:00
for entry in gl_entries :
2013-09-24 09:06:55 +00:00
validate_frozen_account ( entry [ " account " ] , adv_adj )
2014-03-03 13:48:17 +00:00
validate_balance_type ( entry [ " account " ] , adv_adj )
2013-08-22 12:55:43 +00:00
validate_expense_against_budget ( entry )
2014-04-16 09:51:46 +00:00
if entry . get ( " against_voucher " ) and update_outstanding == ' Yes ' :
2014-08-29 05:48:32 +00:00
update_outstanding_amt ( entry [ " account " ] , entry . get ( " party_type " ) , entry . get ( " party " ) , entry . get ( " against_voucher_type " ) ,
2014-04-16 11:51:25 +00:00
entry . get ( " against_voucher " ) , on_cancel = True )