2013-11-20 07:29:58 +00:00
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
2013-08-05 09:29:54 +00:00
# License: GNU General Public License v3. See license.txt
2013-01-29 06:04:39 +00:00
from __future__ import unicode_literals
2014-02-14 10:17:51 +00:00
import frappe
from frappe import _ , throw
2014-09-18 09:33:54 +00:00
from frappe . utils import cint , today , flt
2014-07-01 12:15:15 +00:00
from erpnext . setup . utils import get_company_currency , get_exchange_rate
2013-12-12 13:42:19 +00:00
from erpnext . accounts . utils import get_fiscal_year , validate_fiscal_year
2014-02-10 09:17:54 +00:00
from erpnext . utilities . transaction_base import TransactionBase
2014-09-21 14:15:49 +00:00
from erpnext . controllers . recurring_document import convert_to_recurring , validate_recurring_document
2013-05-24 13:55:01 +00:00
import json
2013-01-29 06:04:39 +00:00
2013-01-30 07:19:08 +00:00
class AccountsController ( TransactionBase ) :
2013-03-20 07:25:28 +00:00
def validate ( self ) :
2014-07-03 06:55:06 +00:00
if self . get ( " _action " ) and self . _action != " update_after_submit " :
2014-06-05 11:25:31 +00:00
self . set_missing_values ( for_validate = True )
2013-07-11 12:19:18 +00:00
self . validate_date_with_fiscal_year ( )
2013-05-24 13:55:01 +00:00
if self . meta . get_field ( " currency " ) :
2013-05-28 11:53:36 +00:00
self . calculate_taxes_and_totals ( )
2013-03-20 07:25:28 +00:00
self . validate_value ( " grand_total " , " >= " , 0 )
2013-05-24 13:55:01 +00:00
self . set_total_in_words ( )
2014-04-08 14:40:03 +00:00
2013-07-26 05:31:17 +00:00
self . validate_for_freezed_account ( )
2014-04-08 14:40:03 +00:00
2014-09-21 14:15:49 +00:00
if self . meta . get_field ( " is_recurring " ) :
validate_recurring_document ( self )
def on_submit ( self ) :
if self . meta . get_field ( " is_recurring " ) :
convert_to_recurring ( self , self . get ( " posting_date " ) or self . get ( " transaction_date " ) )
def on_update_after_submit ( self ) :
if self . meta . get_field ( " is_recurring " ) :
validate_recurring_document ( self )
convert_to_recurring ( self , self . get ( " posting_date " ) or self . get ( " transaction_date " ) )
def before_recurring ( self ) :
self . fiscal_year = None
for fieldname in ( " due_date " , " aging_date " ) :
if self . meta . get_field ( fieldname ) :
self . set ( fieldname , None )
2013-06-14 12:14:03 +00:00
def set_missing_values ( self , for_validate = False ) :
for fieldname in [ " posting_date " , " transaction_date " ] :
2014-03-28 08:25:00 +00:00
if not self . get ( fieldname ) and self . meta . get_field ( fieldname ) :
self . set ( fieldname , today ( ) )
if not self . fiscal_year :
2014-03-31 18:07:40 +00:00
self . fiscal_year = get_fiscal_year ( self . get ( fieldname ) ) [ 0 ]
2014-04-17 20:00:14 +00:00
break
2014-04-08 14:40:03 +00:00
2013-07-11 12:19:18 +00:00
def validate_date_with_fiscal_year ( self ) :
if self . meta . get_field ( " fiscal_year " ) :
date_field = " "
if self . meta . get_field ( " posting_date " ) :
date_field = " posting_date "
elif self . meta . get_field ( " transaction_date " ) :
date_field = " transaction_date "
2014-04-08 14:40:03 +00:00
2014-03-31 18:07:40 +00:00
if date_field and self . get ( date_field ) :
2014-04-08 14:40:03 +00:00
validate_fiscal_year ( self . get ( date_field ) , self . fiscal_year ,
2013-07-11 12:19:18 +00:00
label = self . meta . get_label ( date_field ) )
2014-04-08 14:40:03 +00:00
2013-07-26 05:31:17 +00:00
def validate_for_freezed_account ( self ) :
2013-07-26 10:37:52 +00:00
for fieldname in [ " customer " , " supplier " ] :
2014-03-28 08:25:00 +00:00
if self . meta . get_field ( fieldname ) and self . get ( fieldname ) :
2014-04-08 14:40:03 +00:00
accounts = frappe . db . get_values ( " Account " ,
{ " master_type " : fieldname . title ( ) , " master_name " : self . get ( fieldname ) ,
2014-03-28 08:25:00 +00:00
" company " : self . company } , " name " )
2013-07-26 05:31:17 +00:00
if accounts :
2014-01-23 10:03:30 +00:00
from erpnext . accounts . doctype . gl_entry . gl_entry import validate_frozen_account
2014-04-08 14:40:03 +00:00
for account in accounts :
2014-01-13 07:58:07 +00:00
validate_frozen_account ( account [ 0 ] )
2014-04-08 14:40:03 +00:00
2013-10-17 11:31:14 +00:00
def set_price_list_currency ( self , buying_or_selling ) :
2013-08-09 12:41:35 +00:00
if self . meta . get_field ( " currency " ) :
2014-03-28 08:25:00 +00:00
company_currency = get_company_currency ( self . company )
2014-04-08 14:40:03 +00:00
2013-09-17 04:51:20 +00:00
# price list part
fieldname = " selling_price_list " if buying_or_selling . lower ( ) == " selling " \
else " buying_price_list "
2014-03-28 08:25:00 +00:00
if self . meta . get_field ( fieldname ) and self . get ( fieldname ) :
self . price_list_currency = frappe . db . get_value ( " Price List " ,
self . get ( fieldname ) , " currency " )
2014-04-08 14:40:03 +00:00
2014-03-28 08:25:00 +00:00
if self . price_list_currency == company_currency :
self . plc_conversion_rate = 1.0
2013-09-24 09:06:55 +00:00
2014-03-28 08:25:00 +00:00
elif not self . plc_conversion_rate :
2014-07-01 12:15:15 +00:00
self . plc_conversion_rate = get_exchange_rate (
2014-03-28 08:25:00 +00:00
self . price_list_currency , company_currency )
2014-04-08 14:40:03 +00:00
2013-09-17 04:51:20 +00:00
# currency
2014-03-28 08:25:00 +00:00
if not self . currency :
self . currency = self . price_list_currency
self . conversion_rate = self . plc_conversion_rate
elif self . currency == company_currency :
self . conversion_rate = 1.0
elif not self . conversion_rate :
2014-07-01 12:15:15 +00:00
self . conversion_rate = get_exchange_rate ( self . currency ,
2013-09-17 04:51:20 +00:00
company_currency )
2014-02-11 10:44:52 +00:00
def set_missing_item_details ( self ) :
2013-05-24 13:55:01 +00:00
""" set missing item values """
2014-02-11 10:44:52 +00:00
from erpnext . stock . get_item_details import get_item_details
2014-04-03 09:00:42 +00:00
if hasattr ( self , " fname " ) :
2014-06-20 10:29:49 +00:00
parent_dict = { }
2014-04-10 12:23:30 +00:00
for fieldname in self . meta . get_valid_columns ( ) :
parent_dict [ fieldname ] = self . get ( fieldname )
2014-04-03 09:00:42 +00:00
for item in self . get ( self . fname ) :
if item . get ( " item_code " ) :
2014-06-20 10:29:49 +00:00
args = parent_dict . copy ( )
args . update ( item . as_dict ( ) )
2015-03-09 09:24:37 +00:00
if not args . get ( " transaction_date " ) :
args [ " transaction_date " ] = args . get ( " posting_date " )
2014-04-03 09:00:42 +00:00
ret = get_item_details ( args )
2014-05-28 07:19:20 +00:00
2014-04-03 09:00:42 +00:00
for fieldname , value in ret . items ( ) :
2014-04-03 12:08:54 +00:00
if item . meta . get_field ( fieldname ) and \
2014-04-03 09:00:42 +00:00
item . get ( fieldname ) is None and value is not None :
item . set ( fieldname , value )
2014-04-08 14:40:03 +00:00
2014-12-30 13:03:52 +00:00
if fieldname == " cost_center " and item . meta . get_field ( " cost_center " ) \
and not item . get ( " cost_center " ) and value is not None :
item . set ( fieldname , value )
2014-05-28 07:19:20 +00:00
if ret . get ( " pricing_rule " ) :
for field in [ " base_price_list_rate " , " price_list_rate " ,
" discount_percentage " , " base_rate " , " rate " ] :
item . set ( field , ret . get ( field ) )
2013-07-04 11:43:53 +00:00
def set_taxes ( self , tax_parentfield , tax_master_field ) :
2013-05-24 13:55:01 +00:00
if not self . meta . get_field ( tax_parentfield ) :
return
2014-04-08 14:40:03 +00:00
2013-07-04 11:43:53 +00:00
tax_master_doctype = self . meta . get_field ( tax_master_field ) . options
2014-04-08 14:40:03 +00:00
2014-03-27 10:42:56 +00:00
if not self . get ( tax_parentfield ) :
2014-03-28 08:25:00 +00:00
if not self . get ( tax_master_field ) :
2013-05-24 13:55:01 +00:00
# get the default tax master
2014-03-28 08:25:00 +00:00
self . set ( tax_master_field , frappe . db . get_value ( tax_master_doctype , { " is_default " : 1 } ) )
2014-04-08 14:40:03 +00:00
2013-07-04 11:43:53 +00:00
self . append_taxes_from_master ( tax_parentfield , tax_master_field , tax_master_doctype )
2014-04-08 14:40:03 +00:00
2013-07-04 11:43:53 +00:00
def append_taxes_from_master ( self , tax_parentfield , tax_master_field , tax_master_doctype = None ) :
2014-03-28 08:25:00 +00:00
if self . get ( tax_master_field ) :
2013-07-04 11:43:53 +00:00
if not tax_master_doctype :
tax_master_doctype = self . meta . get_field ( tax_master_field ) . options
2014-04-08 14:40:03 +00:00
2014-05-02 10:15:10 +00:00
self . extend ( tax_parentfield ,
2014-05-04 14:07:45 +00:00
get_taxes_and_charges ( tax_master_doctype , self . get ( tax_master_field ) , tax_parentfield ) )
2014-01-30 08:26:57 +00:00
2014-04-17 20:00:14 +00:00
def set_other_charges ( self ) :
2014-03-27 10:42:56 +00:00
self . set ( " other_charges " , [ ] )
2014-01-30 08:26:57 +00:00
self . set_taxes ( " other_charges " , " taxes_and_charges " )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def calculate_taxes_and_totals ( self ) :
2014-01-03 12:45:07 +00:00
self . discount_amount_applied = False
self . _calculate_taxes_and_totals ( )
2014-04-08 14:40:03 +00:00
2014-01-23 11:15:22 +00:00
if self . meta . get_field ( " discount_amount " ) :
2014-01-03 12:45:07 +00:00
self . apply_discount_amount ( )
def _calculate_taxes_and_totals ( self ) :
2013-07-15 12:40:51 +00:00
# validate conversion rate
2014-03-28 08:25:00 +00:00
company_currency = get_company_currency ( self . company )
if not self . currency or self . currency == company_currency :
self . currency = company_currency
self . conversion_rate = 1.0
2013-07-15 12:40:51 +00:00
else :
2014-02-10 09:17:54 +00:00
from erpnext . setup . doctype . currency . currency import validate_conversion_rate
2014-03-28 08:25:00 +00:00
validate_conversion_rate ( self . currency , self . conversion_rate ,
self . meta . get_label ( " conversion_rate " ) , self . company )
2013-12-23 10:19:08 +00:00
2014-03-28 08:25:00 +00:00
self . conversion_rate = flt ( self . conversion_rate )
2014-03-27 10:42:56 +00:00
self . item_doclist = self . get ( self . fname )
self . tax_doclist = self . get ( self . other_fname )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
self . calculate_item_values ( )
self . initialize_taxes ( )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
if hasattr ( self , " determine_exclusive_rate " ) :
self . determine_exclusive_rate ( )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
self . calculate_net_total ( )
self . calculate_taxes ( )
2015-03-13 12:53:10 +00:00
self . manipulate_grand_total_for_inclusive_tax ( )
2013-05-24 13:55:01 +00:00
self . calculate_totals ( )
self . _cleanup ( )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def initialize_taxes ( self ) :
for tax in self . tax_doclist :
tax . item_wise_tax_detail = { }
2014-04-08 14:40:03 +00:00
tax_fields = [ " total " , " tax_amount_after_discount_amount " ,
" tax_amount_for_current_item " , " grand_total_for_current_item " ,
2013-12-23 10:19:08 +00:00
" tax_fraction_for_current_item " , " grand_total_fraction_for_current_item " ]
2014-01-03 12:45:07 +00:00
if not self . discount_amount_applied :
2013-12-23 10:19:08 +00:00
tax_fields . append ( " tax_amount " )
for fieldname in tax_fields :
2014-03-28 08:25:00 +00:00
tax . set ( fieldname , 0.0 )
2013-12-23 10:19:08 +00:00
2013-05-24 13:55:01 +00:00
self . validate_on_previous_row ( tax )
self . validate_inclusive_tax ( tax )
self . round_floats_in ( tax )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def validate_on_previous_row ( self , tax ) :
"""
validate if a valid row id is mentioned in case of
On Previous Row Amount and On Previous Row Total
"""
if tax . charge_type in [ " On Previous Row Amount " , " On Previous Row Total " ] and \
( not tax . row_id or cint ( tax . row_id ) > = tax . idx ) :
2014-04-15 11:00:55 +00:00
throw ( _ ( " Please specify a valid Row ID for {0} in row {1} " ) . format ( _ ( tax . doctype ) , tax . idx ) )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def validate_inclusive_tax ( self , tax ) :
def _on_previous_row_error ( row_range ) :
2014-04-15 11:00:55 +00:00
throw ( _ ( " To include tax in row {0} in Item rate, taxes in rows {1} must also be included " ) . format ( tax . idx ,
row_range ) )
2014-04-08 14:40:03 +00:00
2014-04-04 05:36:10 +00:00
if cint ( getattr ( tax , " included_in_print_rate " , None ) ) :
2013-05-24 13:55:01 +00:00
if tax . charge_type == " Actual " :
# inclusive tax cannot be of type Actual
2014-04-15 11:00:55 +00:00
throw ( _ ( " Charge of type ' Actual ' in row {0} cannot be included in Item Rate " ) . format ( tax . idx ) )
2013-05-24 13:55:01 +00:00
elif tax . charge_type == " On Previous Row Amount " and \
2013-12-25 14:16:20 +00:00
not cint ( self . tax_doclist [ cint ( tax . row_id ) - 1 ] . included_in_print_rate ) :
2013-05-24 13:55:01 +00:00
# referred row should also be inclusive
_on_previous_row_error ( tax . row_id )
elif tax . charge_type == " On Previous Row Total " and \
2013-12-25 14:16:20 +00:00
not all ( [ cint ( t . included_in_print_rate ) for t in self . tax_doclist [ : cint ( tax . row_id ) - 1 ] ] ) :
2013-05-24 13:55:01 +00:00
# all rows about the reffered tax should be inclusive
_on_previous_row_error ( " 1 - %d " % ( tax . row_id , ) )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def calculate_taxes ( self ) :
2014-01-14 12:14:34 +00:00
# maintain actual tax rate based on idx
2014-08-19 07:09:40 +00:00
actual_tax_dict = dict ( [ [ tax . idx , flt ( tax . rate , self . precision ( " tax_amount " , tax ) ) ] for tax in self . tax_doclist
2014-01-14 12:14:34 +00:00
if tax . charge_type == " Actual " ] )
2013-12-24 15:00:03 +00:00
2014-01-14 12:14:34 +00:00
for n , item in enumerate ( self . item_doclist ) :
2013-05-24 13:55:01 +00:00
item_tax_map = self . _load_item_tax_rate ( item . item_tax_rate )
for i , tax in enumerate ( self . tax_doclist ) :
# tax_amount represents the amount of tax for the current step
current_tax_amount = self . get_current_tax_amount ( item , tax , item_tax_map )
2013-12-24 15:00:03 +00:00
2014-01-14 12:14:34 +00:00
# Adjust divisional loss to the last item
if tax . charge_type == " Actual " :
actual_tax_dict [ tax . idx ] - = current_tax_amount
if n == len ( self . item_doclist ) - 1 :
current_tax_amount + = actual_tax_dict [ tax . idx ]
2013-05-24 13:55:01 +00:00
# store tax_amount for current item as it will be used for
# charge type = 'On Previous Row Amount'
tax . tax_amount_for_current_item = current_tax_amount
# accumulate tax amount into tax.tax_amount
2014-01-03 12:45:07 +00:00
if not self . discount_amount_applied :
2013-12-23 10:19:08 +00:00
tax . tax_amount + = current_tax_amount
2014-01-03 12:45:07 +00:00
tax . tax_amount_after_discount_amount + = current_tax_amount
2014-04-08 14:40:03 +00:00
2014-04-04 05:36:10 +00:00
if getattr ( tax , " category " , None ) :
2013-05-24 13:55:01 +00:00
# if just for valuation, do not add the tax amount in total
# hence, setting it as 0 for further steps
2014-01-14 12:14:34 +00:00
current_tax_amount = 0.0 if ( tax . category == " Valuation " ) \
else current_tax_amount
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
current_tax_amount * = - 1.0 if ( tax . add_deduct_tax == " Deduct " ) else 1.0
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
# Calculate tax.total viz. grand total till that step
2014-04-08 14:40:03 +00:00
# note: grand_total_for_current_item contains the contribution of
2013-05-24 13:55:01 +00:00
# item's amount, previously applied tax and the current tax on that item
if i == 0 :
2014-02-10 13:50:15 +00:00
tax . grand_total_for_current_item = flt ( item . base_amount + current_tax_amount ,
2013-12-24 15:00:03 +00:00
self . precision ( " total " , tax ) )
2013-05-24 13:55:01 +00:00
else :
tax . grand_total_for_current_item = \
2014-04-08 14:40:03 +00:00
flt ( self . tax_doclist [ i - 1 ] . grand_total_for_current_item +
2013-05-24 13:55:01 +00:00
current_tax_amount , self . precision ( " total " , tax ) )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
# in tax.total, accumulate grand total of each item
tax . total + = tax . grand_total_for_current_item
2013-12-23 10:19:08 +00:00
2014-01-14 12:14:34 +00:00
# set precision in the last item iteration
if n == len ( self . item_doclist ) - 1 :
2013-12-25 14:16:20 +00:00
self . round_off_totals ( tax )
2013-12-24 15:00:03 +00:00
2014-01-03 12:45:07 +00:00
# adjust Discount Amount loss in last tax iteration
if i == ( len ( self . tax_doclist ) - 1 ) and self . discount_amount_applied :
self . adjust_discount_amount_loss ( tax )
2013-12-25 14:16:20 +00:00
def round_off_totals ( self , tax ) :
tax . total = flt ( tax . total , self . precision ( " total " , tax ) )
tax . tax_amount = flt ( tax . tax_amount , self . precision ( " tax_amount " , tax ) )
2014-04-08 14:40:03 +00:00
tax . tax_amount_after_discount_amount = flt ( tax . tax_amount_after_discount_amount ,
2013-12-25 14:16:20 +00:00
self . precision ( " tax_amount " , tax ) )
2014-01-03 12:45:07 +00:00
def adjust_discount_amount_loss ( self , tax ) :
2015-01-12 12:05:14 +00:00
discount_amount_loss = self . grand_total - flt ( self . base_discount_amount ) - tax . total
2014-04-08 14:40:03 +00:00
tax . tax_amount_after_discount_amount = flt ( tax . tax_amount_after_discount_amount +
2014-01-03 12:45:07 +00:00
discount_amount_loss , self . precision ( " tax_amount " , tax ) )
tax . total = flt ( tax . total + discount_amount_loss , self . precision ( " total " , tax ) )
2013-12-24 15:00:03 +00:00
2013-05-24 13:55:01 +00:00
def get_current_tax_amount ( self , item , tax , item_tax_map ) :
tax_rate = self . _get_tax_rate ( tax , item_tax_map )
current_tax_amount = 0.0
if tax . charge_type == " Actual " :
# distribute the tax amount proportionally to each item row
actual = flt ( tax . rate , self . precision ( " tax_amount " , tax ) )
2014-03-28 08:25:00 +00:00
current_tax_amount = ( self . net_total
and ( ( item . base_amount / self . net_total ) * actual )
2013-05-24 13:55:01 +00:00
or 0 )
elif tax . charge_type == " On Net Total " :
2014-02-10 13:50:15 +00:00
current_tax_amount = ( tax_rate / 100.0 ) * item . base_amount
2013-05-24 13:55:01 +00:00
elif tax . charge_type == " On Previous Row Amount " :
current_tax_amount = ( tax_rate / 100.0 ) * \
self . tax_doclist [ cint ( tax . row_id ) - 1 ] . tax_amount_for_current_item
elif tax . charge_type == " On Previous Row Total " :
current_tax_amount = ( tax_rate / 100.0 ) * \
self . tax_doclist [ cint ( tax . row_id ) - 1 ] . grand_total_for_current_item
2013-12-24 15:00:03 +00:00
2013-05-31 06:20:01 +00:00
current_tax_amount = flt ( current_tax_amount , self . precision ( " tax_amount " , tax ) )
2013-12-24 15:00:03 +00:00
2013-05-31 06:20:01 +00:00
# store tax breakup for each item
2013-09-05 11:23:57 +00:00
key = item . item_code or item . item_name
if tax . item_wise_tax_detail . get ( key ) :
item_wise_tax_amount = tax . item_wise_tax_detail [ key ] [ 1 ] + current_tax_amount
2014-05-07 09:25:09 +00:00
tax . item_wise_tax_detail [ key ] = [ tax_rate , item_wise_tax_amount ]
2013-09-05 11:23:57 +00:00
else :
2014-05-07 09:25:09 +00:00
tax . item_wise_tax_detail [ key ] = [ tax_rate , current_tax_amount ]
2013-05-24 13:55:01 +00:00
2013-05-31 06:20:01 +00:00
return current_tax_amount
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def _load_item_tax_rate ( self , item_tax_rate ) :
return json . loads ( item_tax_rate ) if item_tax_rate else { }
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def _get_tax_rate ( self , tax , item_tax_map ) :
if item_tax_map . has_key ( tax . account_head ) :
return flt ( item_tax_map . get ( tax . account_head ) , self . precision ( " rate " , tax ) )
else :
return tax . rate
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def _cleanup ( self ) :
for tax in self . tax_doclist :
2014-05-07 09:25:09 +00:00
tax . item_wise_tax_detail = json . dumps ( tax . item_wise_tax_detail , separators = ( ' , ' , ' : ' ) )
2014-04-08 14:40:03 +00:00
2013-05-24 13:55:01 +00:00
def _set_in_company_currency ( self , item , print_field , base_field ) :
""" set values in base currency """
2014-04-08 14:40:03 +00:00
value_in_company_currency = flt ( self . conversion_rate *
2014-04-02 09:33:35 +00:00
flt ( item . get ( print_field ) , self . precision ( print_field , item ) ) ,
2013-05-24 13:55:01 +00:00
self . precision ( base_field , item ) )
2014-04-02 09:33:35 +00:00
item . set ( base_field , value_in_company_currency )
2014-04-08 14:40:03 +00:00
2015-03-13 12:53:10 +00:00
def manipulate_grand_total_for_inclusive_tax ( self ) :
# if fully inclusive taxes and diff
if ( self . meta . get_field ( " net_total_export " ) and self . tax_doclist
and all ( cint ( t . included_in_print_rate ) for t in self . tax_doclist ) ) :
last_tax = self . tax_doclist [ - 1 ]
diff = self . net_total_export - flt ( last_tax . total / self . conversion_rate ,
self . precision ( " grand_total_export " ) )
2015-03-16 11:31:09 +00:00
if diff and abs ( diff ) < = ( 2.0 / 10 * * ( self . precision ( " tax_amount " , last_tax ) ) ) :
adjustment_amount = flt ( diff * self . conversion_rate , self . precision ( " tax_amount " , last_tax ) )
last_tax . tax_amount + = adjustment_amount
last_tax . tax_amount_after_discount_amount + = adjustment_amount
last_tax . total + = adjustment_amount
2015-03-13 12:53:10 +00:00
2013-05-28 11:53:36 +00:00
def calculate_total_advance ( self , parenttype , advance_parentfield ) :
2014-03-28 08:25:00 +00:00
if self . doctype == parenttype and self . docstatus < 2 :
2014-04-08 14:40:03 +00:00
sum_of_allocated_amount = sum ( [ flt ( adv . allocated_amount , self . precision ( " allocated_amount " , adv ) )
2014-03-27 10:42:56 +00:00
for adv in self . get ( advance_parentfield ) ] )
2013-05-28 11:53:36 +00:00
2014-03-28 08:25:00 +00:00
self . total_advance = flt ( sum_of_allocated_amount , self . precision ( " total_advance " ) )
2014-04-08 14:40:03 +00:00
2013-05-28 11:53:36 +00:00
self . calculate_outstanding_amount ( )
2013-03-20 07:25:28 +00:00
2013-08-21 12:17:11 +00:00
def get_gl_dict ( self , args ) :
2013-01-29 06:04:39 +00:00
""" this method populates the common properties of a gl entry record """
2014-02-14 10:17:51 +00:00
gl_dict = frappe . _dict ( {
2014-04-08 14:40:03 +00:00
' company ' : self . company ,
2014-03-28 08:25:00 +00:00
' posting_date ' : self . posting_date ,
' voucher_type ' : self . doctype ,
' voucher_no ' : self . name ,
' aging_date ' : self . get ( " aging_date " ) or self . posting_date ,
2014-04-07 06:32:57 +00:00
' remarks ' : self . get ( " remarks " ) ,
2014-03-28 08:25:00 +00:00
' fiscal_year ' : self . fiscal_year ,
2013-01-29 06:04:39 +00:00
' debit ' : 0 ,
' credit ' : 0 ,
2014-03-28 08:25:00 +00:00
' is_opening ' : self . get ( " is_opening " ) or " No " ,
2013-08-28 13:23:11 +00:00
} )
2013-01-29 06:04:39 +00:00
gl_dict . update ( args )
return gl_dict
2014-04-08 14:40:03 +00:00
2013-02-06 12:03:46 +00:00
def clear_unallocated_advances ( self , childtype , parentfield ) :
2014-04-02 12:39:34 +00:00
self . set ( parentfield , self . get ( parentfield , { " allocated_amount " : [ " not in " , [ 0 , None , " " ] ] } ) )
2014-04-08 14:40:03 +00:00
frappe . db . sql ( """ delete from `tab %s ` where parentfield= %s and parent = %s
2014-03-28 08:25:00 +00:00
and ifnull ( allocated_amount , 0 ) = 0 """ % (childtype, ' %s ' , ' %s ' ), (parentfield, self.name))
2014-04-08 14:40:03 +00:00
2014-09-18 09:33:54 +00:00
def get_advances ( self , account_head , child_doctype , parentfield , dr_or_cr , against_order_field ) :
so_list = list ( set ( [ d . get ( against_order_field ) for d in self . get ( " entries " ) if d . get ( against_order_field ) ] ) )
2014-09-19 09:01:49 +00:00
cond = " "
if so_list :
cond = " or (ifnull(t2. %s , ' ' ) in ( %s )) " % ( " against_ " + against_order_field , ' , ' . join ( [ ' %s ' ] * len ( so_list ) ) )
2014-09-18 09:33:54 +00:00
2014-05-01 10:13:22 +00:00
res = frappe . db . sql ( """
select
2014-10-13 05:17:14 +00:00
t1 . name as jv_no , t1 . remark , t2 . % s as amount , t2 . name as jv_detail_no , ` against_ % s ` as against_order
2014-05-01 10:13:22 +00:00
from
` tabJournal Voucher ` t1 , ` tabJournal Voucher Detail ` t2
where
t1 . name = t2 . parent and t2 . account = % s and t2 . is_advance = ' Yes ' and t1 . docstatus = 1
2014-09-18 09:33:54 +00:00
and ( (
ifnull ( t2 . against_voucher , ' ' ) = ' '
and ifnull ( t2 . against_invoice , ' ' ) = ' '
and ifnull ( t2 . against_jv , ' ' ) = ' '
and ifnull ( t2 . against_sales_order , ' ' ) = ' '
and ifnull ( t2 . against_purchase_order , ' ' ) = ' '
2014-09-19 09:01:49 +00:00
) % s )
2014-05-01 10:13:22 +00:00
order by t1 . posting_date """ %
2014-10-13 05:17:14 +00:00
( dr_or_cr , against_order_field , ' %s ' , cond ) ,
2014-09-18 09:33:54 +00:00
tuple ( [ account_head ] + so_list ) , as_dict = True )
2014-04-08 14:40:03 +00:00
2014-03-27 10:42:56 +00:00
self . set ( parentfield , [ ] )
2013-01-30 13:46:13 +00:00
for d in res :
2014-09-18 09:33:54 +00:00
self . append ( parentfield , {
" doctype " : child_doctype ,
" journal_voucher " : d . jv_no ,
" jv_detail_no " : d . jv_detail_no ,
" remarks " : d . remark ,
" advance_amount " : flt ( d . amount ) ,
2014-10-13 05:17:14 +00:00
" allocated_amount " : flt ( d . amount ) if d . against_order else 0
2014-09-18 09:33:54 +00:00
} )
def validate_advance_jv ( self , advance_table_fieldname , against_order_field ) :
order_list = list ( set ( [ d . get ( against_order_field ) for d in self . get ( " entries " ) if d . get ( against_order_field ) ] ) )
if order_list :
account = self . get ( " debit_to " if self . doctype == " Sales Invoice " else " credit_to " )
jv_against_order = frappe . db . sql ( """ select parent, %s as against_order
from ` tabJournal Voucher Detail `
where docstatus = 1 and account = % s and ifnull ( is_advance , ' No ' ) = ' Yes '
and ifnull ( against_sales_order , ' ' ) in ( % s )
group by parent , against_sales_order """ %
( " against_ " + against_order_field , ' %s ' , ' , ' . join ( [ ' %s ' ] * len ( order_list ) ) ) ,
tuple ( [ account ] + order_list ) , as_dict = 1 )
if jv_against_order :
order_jv_map = { }
for d in jv_against_order :
order_jv_map . setdefault ( d . against_order , [ ] ) . append ( d . parent )
advance_jv_against_si = [ d . journal_voucher for d in self . get ( advance_table_fieldname ) ]
for order , jv_list in order_jv_map . items ( ) :
for jv in jv_list :
if not advance_jv_against_si or jv not in advance_jv_against_si :
2014-11-28 10:23:07 +00:00
frappe . msgprint ( _ ( " Journal Voucher {0} is linked against Order {1} , check if it should be pulled as advance in this invoice. " )
2014-09-18 09:33:54 +00:00
. format ( jv , order ) )
2014-04-08 14:40:03 +00:00
2013-07-29 13:05:39 +00:00
def validate_multiple_billing ( self , ref_dt , item_ref_dn , based_on , parentfield ) :
2014-01-23 10:03:30 +00:00
from erpnext . controllers . status_updater import get_tolerance_for
2014-01-03 12:13:19 +00:00
item_tolerance = { }
global_tolerance = None
2014-04-08 14:40:03 +00:00
2014-03-27 10:42:56 +00:00
for item in self . get ( " entries " ) :
2014-03-28 08:25:00 +00:00
if item . get ( item_ref_dn ) :
2014-04-08 14:40:03 +00:00
ref_amt = flt ( frappe . db . get_value ( ref_dt + " Item " ,
2014-03-31 18:07:40 +00:00
item . get ( item_ref_dn ) , based_on ) , self . precision ( based_on , item ) )
2014-01-07 07:11:09 +00:00
if not ref_amt :
2014-04-14 13:50:45 +00:00
frappe . msgprint ( _ ( " Warning: System will not check overbilling since amount for Item {0} in {1} is zero " ) . format ( item . item_code , ref_dt ) )
2014-01-07 07:11:09 +00:00
else :
2014-04-08 14:40:03 +00:00
already_billed = frappe . db . sql ( """ select sum( %s ) from `tab %s `
where % s = % s and docstatus = 1 and parent != % s """ %
( based_on , self . tname , item_ref_dn , ' %s ' , ' %s ' ) ,
2014-03-31 18:07:40 +00:00
( item . get ( item_ref_dn ) , self . name ) ) [ 0 ] [ 0 ]
2014-04-08 14:40:03 +00:00
total_billed_amt = flt ( flt ( already_billed ) + flt ( item . get ( based_on ) ) ,
2014-01-07 07:11:09 +00:00
self . precision ( based_on , item ) )
2014-04-08 14:40:03 +00:00
tolerance , item_tolerance , global_tolerance = get_tolerance_for ( item . item_code ,
2014-01-07 07:11:09 +00:00
item_tolerance , global_tolerance )
2014-04-08 14:40:03 +00:00
2014-01-07 07:11:09 +00:00
max_allowed_amt = flt ( ref_amt * ( 100 + tolerance ) / 100 )
2014-04-08 14:40:03 +00:00
2014-01-07 07:11:09 +00:00
if total_billed_amt - max_allowed_amt > 0.01 :
2015-01-06 07:26:37 +00:00
frappe . throw ( _ ( " Cannot overbill for Item {0} in row {1} more than {2} . To allow overbilling, please set in Stock Settings " ) . format ( item . item_code , item . idx , max_allowed_amt ) )
2014-04-08 14:40:03 +00:00
2013-03-25 05:36:00 +00:00
def get_company_default ( self , fieldname ) :
2013-12-12 13:42:19 +00:00
from erpnext . accounts . utils import get_company_default
2014-03-28 08:25:00 +00:00
return get_company_default ( self . company , fieldname )
2014-04-08 14:40:03 +00:00
2013-08-02 09:20:12 +00:00
def get_stock_items ( self ) :
stock_items = [ ]
2014-06-25 08:01:02 +00:00
item_codes = list ( set ( item . item_code for item in self . get ( self . fname ) ) )
2013-08-02 09:20:12 +00:00
if item_codes :
2014-02-26 07:05:33 +00:00
stock_items = [ r [ 0 ] for r in frappe . db . sql ( """ select name
2013-08-02 09:20:12 +00:00
from ` tabItem ` where name in ( % s ) and is_stock_item = ' Yes ' """ % \
( " , " . join ( ( [ " %s " ] * len ( item_codes ) ) ) , ) , item_codes ) ]
2014-04-08 14:40:03 +00:00
2013-08-02 09:20:12 +00:00
return stock_items
2014-04-08 14:40:03 +00:00
2014-09-12 09:48:53 +00:00
def set_total_advance_paid ( self ) :
if self . doctype == " Sales Order " :
dr_or_cr = " credit "
against_field = " against_sales_order "
else :
dr_or_cr = " debit "
against_field = " against_purchase_order "
advance_paid = frappe . db . sql ( """
select
sum ( ifnull ( { dr_or_cr } , 0 ) )
from
` tabJournal Voucher Detail `
where
{ against_field } = % s and docstatus = 1 and is_advance = " Yes " """ .format(dr_or_cr=dr_or_cr, \
against_field = against_field ) , self . name )
if advance_paid :
advance_paid = flt ( advance_paid [ 0 ] [ 0 ] , self . precision ( " advance_paid " ) )
if flt ( self . grand_total ) > = advance_paid :
frappe . db . set_value ( self . doctype , self . name , " advance_paid " , advance_paid )
else :
frappe . throw ( _ ( " Total advance ( {0} ) against Order {1} cannot be greater \
than the Grand Total ( { 2 } ) " )
. format ( advance_paid , self . name , self . grand_total ) )
2014-08-26 08:59:06 +00:00
@property
def company_abbr ( self ) :
if not hasattr ( self , " _abbr " ) :
self . _abbr = frappe . db . get_value ( " Company " , self . company , " abbr " )
return self . _abbr
def check_credit_limit ( self , account ) :
total_outstanding = frappe . db . sql ( """
select sum ( ifnull ( debit , 0 ) ) - sum ( ifnull ( credit , 0 ) )
from ` tabGL Entry ` where account = % s """ , account)
total_outstanding = total_outstanding [ 0 ] [ 0 ] if total_outstanding else 0
if total_outstanding :
frappe . get_doc ( ' Account ' , account ) . check_credit_limit ( total_outstanding )
2014-02-14 10:17:51 +00:00
@frappe.whitelist ( )
2013-10-10 11:05:09 +00:00
def get_tax_rate ( account_head ) :
2014-04-08 14:40:03 +00:00
return frappe . db . get_value ( " Account " , account_head , " tax_rate " )
2014-05-02 10:15:10 +00:00
@frappe.whitelist ( )
def get_taxes_and_charges ( master_doctype , master_name , tax_parentfield ) :
from frappe . model import default_fields
tax_master = frappe . get_doc ( master_doctype , master_name )
taxes_and_charges = [ ]
for i , tax in enumerate ( tax_master . get ( tax_parentfield ) ) :
tax = tax . as_dict ( )
for fieldname in default_fields :
if fieldname in tax :
del tax [ fieldname ]
taxes_and_charges . append ( tax )
return taxes_and_charges