# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt

from __future__ import unicode_literals
import webnotes
from webnotes.utils import flt, cstr
from webnotes import _
from accounts.utils import validate_expense_against_budget


class StockAccountInvalidTransaction(webnotes.ValidationError): pass

def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, 
		update_outstanding='Yes'):
	if gl_map:
		if not cancel:
			gl_map = process_gl_map(gl_map, merge_entries)
			save_entries(gl_map, adv_adj, update_outstanding)
		else:
			delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
		
def process_gl_map(gl_map, merge_entries=True):
	if merge_entries:
		gl_map = merge_similar_entries(gl_map)
	
	for entry in gl_map:
		# round off upto 2 decimal
		entry.debit = flt(entry.debit, 2)
		entry.credit = flt(entry.credit, 2)
	
		# toggle debit, credit if negative entry
		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

	return gl_map
		
def merge_similar_entries(gl_map):
	merged_gl_map = []
	for entry in gl_map:
		# if there is already an entry in this account then just add it 
		# to that entry
		same_head = check_if_in_list(entry, merged_gl_map)
		if same_head:
			same_head.debit	= flt(same_head.debit) + flt(entry.debit)
			same_head.credit = flt(same_head.credit) + flt(entry.credit)
		else:
			merged_gl_map.append(entry)
			
	# filter zero debit and credit entries
	merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
	return merged_gl_map

def check_if_in_list(gle, gl_map):
	for e in gl_map:
		if e.account == gle.account and \
				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

def save_entries(gl_map, adv_adj, update_outstanding):
	validate_account_for_auto_accounting_for_stock(gl_map)
	
	total_debit = total_credit = 0.0
	for entry in gl_map:
		make_entry(entry, adv_adj, update_outstanding)
		# check against budget
		validate_expense_against_budget(entry)
		

		# update total debit / credit
		total_debit += flt(entry.debit)
		total_credit += flt(entry.credit)
		
	validate_total_debit_credit(total_debit, total_credit)
	
def make_entry(args, adv_adj, update_outstanding):
	args.update({"doctype": "GL Entry"})
	gle = webnotes.bean([args])
	gle.ignore_permissions = 1
	gle.insert()
	gle.run_method("on_update_with_args", adv_adj, update_outstanding)
	gle.submit()
	
def validate_total_debit_credit(total_debit, total_credit):
	if abs(total_debit - total_credit) > 0.005:
		webnotes.throw(_("Debit and Credit not equal for this voucher: Diff (Debit) is ") +
		 	cstr(total_debit - total_credit))
			
def validate_account_for_auto_accounting_for_stock(gl_map):
	if gl_map[0].voucher_type=="Journal Voucher":
		aii_accounts = [d[0] for d in webnotes.conn.sql("""select name from tabAccount 
			where account_type = 'Warehouse' and ifnull(master_name, '')!=''""")]
		
		for entry in gl_map:
			if entry.account in aii_accounts:
				webnotes.throw(_("Account") + ": " + entry.account + 
					_(" can only be debited/credited through Stock transactions"), 
					StockAccountInvalidTransaction)
	
		
def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None, 
		adv_adj=False, update_outstanding="Yes"):
	
	from accounts.doctype.gl_entry.gl_entry import check_negative_balance, \
		check_freezing_date, update_outstanding_amt, validate_frozen_account
		
	if not gl_entries:
		gl_entries = webnotes.conn.sql("""select * from `tabGL Entry` 
			where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
	if gl_entries:
		check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
	
	webnotes.conn.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""", 
		(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
	
	for entry in gl_entries:
		validate_frozen_account(entry["account"], adv_adj)
		check_negative_balance(entry["account"], adv_adj)
		validate_expense_against_budget(entry)
		
		if entry.get("against_voucher") and entry.get("against_voucher_type") != "POS" \
			and update_outstanding == 'Yes':
				update_outstanding_amt(entry["account"], entry.get("against_voucher_type"), 
					entry.get("against_voucher"), on_cancel=True)