2015-03-03 09:25:30 +00:00
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2014-01-28 12:13:10 +00:00
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
2018-06-05 05:57:53 +00:00
import frappe , erpnext
2014-09-10 11:41:30 +00:00
from frappe import _ , msgprint , scrub
2018-12-19 14:26:42 +00:00
from frappe . core . doctype . user_permission . user_permission import get_permitted_documents
2017-06-22 11:07:04 +00:00
from frappe . model . utils import get_fetch_values
2018-03-13 10:31:11 +00:00
from frappe . utils import ( add_days , getdate , formatdate , date_diff ,
2018-12-28 20:49:11 +00:00
add_years , get_timestamp , nowdate , flt , cstr , add_months , get_last_day )
2017-07-12 10:15:32 +00:00
from frappe . contacts . doctype . address . address import ( get_address_display ,
get_default_address , get_company_address )
2017-06-13 09:56:35 +00:00
from frappe . contacts . doctype . contact . contact import get_contact_details , get_default_contact
2019-10-20 12:06:36 +00:00
from erpnext . exceptions import PartyFrozen , PartyDisabled , InvalidAccountCurrency
2017-05-24 07:11:14 +00:00
from erpnext . accounts . utils import get_fiscal_year
2019-01-22 18:58:37 +00:00
from erpnext import get_company_currency
2017-08-02 21:20:35 +00:00
2018-12-28 20:49:11 +00:00
from six import iteritems , string_types
2014-01-28 12:13:10 +00:00
2015-09-28 09:54:00 +00:00
class DuplicatePartyAccountError ( frappe . ValidationError ) : pass
2015-09-03 10:33:07 +00:00
2014-02-14 10:17:51 +00:00
@frappe.whitelist ( )
2018-07-13 12:10:48 +00:00
def get_party_details ( party = None , account = None , party_type = " Customer " , company = None , posting_date = None ,
2019-01-24 11:45:38 +00:00
bill_date = None , price_list = None , currency = None , doctype = None , ignore_permissions = False , fetch_payment_terms_template = True ,
2019-12-10 10:25:05 +00:00
party_address = None , company_address = None , shipping_address = None , pos_profile = None ) :
2014-02-20 09:51:53 +00:00
2015-04-01 18:08:13 +00:00
if not party :
return { }
2015-06-08 06:56:52 +00:00
if not frappe . db . exists ( party_type , party ) :
frappe . throw ( _ ( " {0} : {1} does not exists " ) . format ( party_type , party ) )
2014-06-18 11:10:27 +00:00
return _get_party_details ( party , account , party_type ,
2019-01-24 11:45:38 +00:00
company , posting_date , bill_date , price_list , currency , doctype , ignore_permissions ,
2019-12-10 10:25:05 +00:00
fetch_payment_terms_template , party_address , company_address , shipping_address , pos_profile )
2014-02-20 09:51:53 +00:00
2018-07-13 12:10:48 +00:00
def _get_party_details ( party = None , account = None , party_type = " Customer " , company = None , posting_date = None ,
2018-10-07 06:12:07 +00:00
bill_date = None , price_list = None , currency = None , doctype = None , ignore_permissions = False ,
2020-02-18 06:58:41 +00:00
fetch_payment_terms_template = True , party_address = None , company_address = None , shipping_address = None , pos_profile = None ) :
2019-12-10 10:25:05 +00:00
party_details = frappe . _dict ( set_account_and_due_date ( party , account , party_type , company , posting_date , bill_date , doctype ) )
party = party_details [ party_type . lower ( ) ]
2014-02-03 10:44:56 +00:00
2014-02-20 09:51:53 +00:00
if not ignore_permissions and not frappe . has_permission ( party_type , " read " , party ) :
2015-11-27 06:05:35 +00:00
frappe . throw ( _ ( " Not permitted for {0} " ) . format ( party ) , frappe . PermissionError )
2014-02-03 10:44:56 +00:00
2014-04-03 12:08:54 +00:00
party = frappe . get_doc ( party_type , party )
2019-07-03 05:04:31 +00:00
currency = party . default_currency if party . get ( " default_currency " ) else get_company_currency ( company )
2014-02-03 10:44:56 +00:00
2019-12-10 10:25:05 +00:00
party_address , shipping_address = set_address_details ( party_details , party , party_type , doctype , company , party_address , company_address , shipping_address )
set_contact_details ( party_details , party , party_type )
set_other_values ( party_details , party , party_type )
set_price_list ( party_details , party , party_type , price_list , pos_profile )
2014-04-10 13:10:57 +00:00
2019-12-10 10:25:05 +00:00
party_details [ " tax_category " ] = get_address_tax_category ( party . get ( " tax_category " ) ,
2018-12-28 20:49:11 +00:00
party_address , shipping_address if party_type != " Supplier " else party_address )
2019-12-10 10:25:05 +00:00
if not party_details . get ( " taxes_and_charges " ) :
party_details [ " taxes_and_charges " ] = set_taxes ( party . name , party_type , posting_date , company ,
customer_group = party_details . customer_group , supplier_group = party_details . supplier_group , tax_category = party_details . tax_category ,
billing_address = party_address , shipping_address = shipping_address )
2018-07-13 12:10:48 +00:00
if fetch_payment_terms_template :
2019-12-10 10:25:05 +00:00
party_details [ " payment_terms_template " ] = get_pyt_term_template ( party . name , party_type , company )
2014-04-10 13:10:57 +00:00
2019-12-10 10:25:05 +00:00
if not party_details . get ( " currency " ) :
party_details [ " currency " ] = currency
2014-04-10 13:10:57 +00:00
2014-02-03 10:44:56 +00:00
# sales team
2014-01-28 12:13:10 +00:00
if party_type == " Customer " :
2019-12-10 10:25:05 +00:00
party_details [ " sales_team " ] = [ {
2015-10-12 10:45:52 +00:00
" sales_person " : d . sales_person ,
" allocated_percentage " : d . allocated_percentage or None
2014-04-03 12:08:54 +00:00
} for d in party . get ( " sales_team " ) ]
2014-04-10 13:10:57 +00:00
2018-08-01 12:15:05 +00:00
# supplier tax withholding category
if party_type == " Supplier " and party :
2019-12-10 10:25:05 +00:00
party_details [ " supplier_tds " ] = frappe . get_value ( party_type , party . name , " tax_withholding_category " )
2018-08-01 12:15:05 +00:00
2019-12-10 10:25:05 +00:00
return party_details
2014-02-03 10:44:56 +00:00
2019-12-10 10:25:05 +00:00
def set_address_details ( party_details , party , party_type , doctype = None , company = None , party_address = None , company_address = None , shipping_address = None ) :
2014-02-19 12:13:24 +00:00
billing_address_field = " customer_address " if party_type == " Lead " \
else party_type . lower ( ) + " _address "
2019-12-10 10:25:05 +00:00
party_details [ billing_address_field ] = party_address or get_default_address ( party_type , party . name )
2017-10-02 10:29:27 +00:00
if doctype :
2019-12-10 10:25:05 +00:00
party_details . update ( get_fetch_values ( doctype , billing_address_field , party_details [ billing_address_field ] ) )
2014-02-03 10:44:56 +00:00
# address display
2019-12-10 10:25:05 +00:00
party_details . address_display = get_address_display ( party_details [ billing_address_field ] )
2014-02-19 12:13:24 +00:00
# shipping address
if party_type in [ " Customer " , " Lead " ] :
2019-12-10 10:25:05 +00:00
party_details . shipping_address_name = shipping_address or get_party_shipping_address ( party_type , party . name )
party_details . shipping_address = get_address_display ( party_details [ " shipping_address_name " ] )
2017-10-02 10:29:27 +00:00
if doctype :
2019-12-10 10:25:05 +00:00
party_details . update ( get_fetch_values ( doctype , ' shipping_address_name ' , party_details . shipping_address_name ) )
if company_address :
party_details . update ( { ' company_address ' : company_address } )
else :
party_details . update ( get_company_address ( company ) )
2017-06-22 11:07:04 +00:00
2019-12-10 10:25:05 +00:00
if doctype and doctype in [ ' Delivery Note ' , ' Sales Invoice ' , ' Sales Order ' ] :
if party_details . company_address :
party_details . update ( get_fetch_values ( doctype , ' company_address ' , party_details . company_address ) )
get_regional_address_details ( party_details , doctype , company )
2018-06-05 05:57:53 +00:00
2019-12-10 10:25:05 +00:00
elif doctype and doctype in [ " Purchase Invoice " , " Purchase Order " , " Purchase Receipt " ] :
if party_details . company_address :
party_details [ " shipping_address " ] = shipping_address or party_details [ " company_address " ]
party_details . shipping_address_display = get_address_display ( party_details [ " shipping_address " ] )
party_details . update ( get_fetch_values ( doctype , ' shipping_address ' , party_details . shipping_address ) )
get_regional_address_details ( party_details , doctype , company )
2018-06-05 05:57:53 +00:00
2019-12-10 10:25:05 +00:00
return party_details . get ( billing_address_field ) , party_details . shipping_address_name
2018-12-26 21:11:07 +00:00
2018-06-05 05:57:53 +00:00
@erpnext.allow_regional
2019-12-10 10:25:05 +00:00
def get_regional_address_details ( party_details , doctype , company ) :
2018-06-05 05:57:53 +00:00
pass
2014-04-10 13:10:57 +00:00
2019-12-10 10:25:05 +00:00
def set_contact_details ( party_details , party , party_type ) :
party_details . contact_person = get_default_contact ( party_type , party . name )
2014-04-10 13:10:57 +00:00
2019-12-10 10:25:05 +00:00
if not party_details . contact_person :
party_details . update ( {
2015-07-07 11:11:37 +00:00
" contact_person " : None ,
" contact_display " : None ,
" contact_email " : None ,
" contact_mobile " : None ,
" contact_phone " : None ,
" contact_designation " : None ,
" contact_department " : None
} )
2015-07-08 12:46:51 +00:00
else :
2019-12-10 10:25:05 +00:00
party_details . update ( get_contact_details ( party_details . contact_person ) )
2014-02-03 10:44:56 +00:00
2019-12-10 10:25:05 +00:00
def set_other_values ( party_details , party , party_type ) :
2014-02-03 10:44:56 +00:00
# copy
if party_type == " Customer " :
2016-02-19 05:38:45 +00:00
to_copy = [ " customer_name " , " customer_group " , " territory " , " language " ]
2014-01-28 12:13:10 +00:00
else :
2018-04-19 13:07:29 +00:00
to_copy = [ " supplier_name " , " supplier_group " , " language " ]
2014-02-03 10:44:56 +00:00
for f in to_copy :
2019-12-10 10:25:05 +00:00
party_details [ f ] = party . get ( f )
2014-04-10 13:10:57 +00:00
2014-02-03 10:44:56 +00:00
# fields prepended with default in Customer doctype
2015-08-21 09:34:57 +00:00
for f in [ ' currency ' ] \
2014-02-03 10:44:56 +00:00
+ ( [ ' sales_partner ' , ' commission_rate ' ] if party_type == " Customer " else [ ] ) :
if party . get ( " default_ " + f ) :
2019-12-10 10:25:05 +00:00
party_details [ f ] = party . get ( " default_ " + f )
2014-02-03 10:44:56 +00:00
2015-09-17 12:59:44 +00:00
def get_default_price_list ( party ) :
""" Return default price list for party (Document object) """
2019-07-03 05:04:31 +00:00
if party . get ( " default_price_list " ) :
2015-09-17 12:59:44 +00:00
return party . default_price_list
if party . doctype == " Customer " :
2018-08-09 05:17:09 +00:00
price_list = frappe . get_cached_value ( " Customer Group " ,
party . customer_group , " default_price_list " )
2015-09-17 12:59:44 +00:00
if price_list :
return price_list
return None
2019-12-10 10:25:05 +00:00
def set_price_list ( party_details , party , party_type , given_price_list , pos = None ) :
2014-04-10 13:10:57 +00:00
# price list
2018-12-19 14:26:42 +00:00
price_list = get_permitted_documents ( ' Price List ' )
2014-02-03 10:44:56 +00:00
2018-05-04 12:22:57 +00:00
if price_list :
price_list = price_list [ 0 ]
2019-01-24 11:45:38 +00:00
elif pos and party_type == ' Customer ' :
customer_price_list = frappe . get_value ( ' Customer ' , party . name , ' default_price_list ' )
if customer_price_list :
price_list = customer_price_list
else :
2019-01-25 11:14:45 +00:00
pos_price_list = frappe . get_value ( ' POS Profile ' , pos , ' selling_price_list ' )
2019-01-25 06:23:55 +00:00
price_list = pos_price_list or given_price_list
2018-05-04 12:22:57 +00:00
else :
price_list = get_default_price_list ( party ) or given_price_list
2014-02-03 10:44:56 +00:00
if price_list :
2019-12-10 10:25:05 +00:00
party_details . price_list_currency = frappe . db . get_value ( " Price List " , price_list , " currency " , cache = True )
2014-04-10 13:10:57 +00:00
2019-12-10 10:25:05 +00:00
party_details [ " selling_price_list " if party . doctype == " Customer " else " buying_price_list " ] = price_list
2014-04-10 13:10:57 +00:00
2014-02-03 10:44:56 +00:00
2018-02-16 07:35:21 +00:00
def set_account_and_due_date ( party , account , party_type , company , posting_date , bill_date , doctype ) :
2014-06-18 11:10:27 +00:00
if doctype not in [ " Sales Invoice " , " Purchase Invoice " ] :
2014-02-03 10:44:56 +00:00
# not an invoice
return {
party_type . lower ( ) : party
}
2014-04-10 13:10:57 +00:00
2014-01-28 12:13:10 +00:00
if party :
2015-09-25 10:47:50 +00:00
account = get_party_account ( party_type , party , company )
2014-01-28 12:13:10 +00:00
2014-04-10 13:10:57 +00:00
account_fieldname = " debit_to " if party_type == " Customer " else " credit_to "
2014-01-28 12:13:10 +00:00
out = {
party_type . lower ( ) : party ,
account_fieldname : account ,
2018-02-16 07:35:21 +00:00
" due_date " : get_due_date ( posting_date , party_type , party , company , bill_date )
2014-02-03 10:44:56 +00:00
}
2018-02-16 07:35:21 +00:00
2014-01-28 12:13:10 +00:00
return out
2015-09-18 07:29:51 +00:00
2014-09-10 11:41:30 +00:00
@frappe.whitelist ( )
2015-09-25 10:47:50 +00:00
def get_party_account ( party_type , party , company ) :
2015-02-21 09:09:35 +00:00
""" Returns the account for the given `party`.
Will first search in party ( Customer / Supplier ) record , if not found ,
2018-04-19 13:07:29 +00:00
will search in group ( Customer Group / Supplier Group ) ,
2015-02-21 09:09:35 +00:00
finally will return default . """
2014-01-28 12:13:10 +00:00
if not company :
2015-09-25 10:47:50 +00:00
frappe . throw ( _ ( " Please select a Company " ) )
2014-01-28 12:13:10 +00:00
2017-11-10 13:51:09 +00:00
if not party :
2017-11-13 09:36:35 +00:00
return
2017-11-10 13:51:09 +00:00
account = frappe . db . get_value ( " Party Account " ,
{ " parenttype " : party_type , " parent " : party , " company " : company } , " account " )
if not account and party_type in [ ' Customer ' , ' Supplier ' ] :
2018-04-19 13:07:29 +00:00
party_group_doctype = " Customer Group " if party_type == " Customer " else " Supplier Group "
2018-08-09 05:17:09 +00:00
group = frappe . get_cached_value ( party_type , party , scrub ( party_group_doctype ) )
2015-02-21 09:09:35 +00:00
account = frappe . db . get_value ( " Party Account " ,
2017-11-10 13:51:09 +00:00
{ " parenttype " : party_group_doctype , " parent " : group , " company " : company } , " account " )
if not account and party_type in [ ' Customer ' , ' Supplier ' ] :
default_account_name = " default_receivable_account " \
if party_type == " Customer " else " default_payable_account "
2018-08-08 11:07:31 +00:00
account = frappe . get_cached_value ( ' Company ' , company , default_account_name )
2017-11-10 13:51:09 +00:00
existing_gle_currency = get_party_gle_currency ( party_type , party , company )
if existing_gle_currency :
if account :
2018-08-09 05:17:09 +00:00
account_currency = frappe . db . get_value ( " Account " , account , " account_currency " , cache = True )
2017-11-10 13:51:09 +00:00
if ( account and account_currency != existing_gle_currency ) or not account :
account = get_party_gle_account ( party_type , party , company )
return account
2014-01-28 12:13:10 +00:00
2018-09-11 12:10:37 +00:00
@frappe.whitelist ( )
def get_party_bank_account ( party_type , party ) :
return frappe . db . get_value ( ' Bank Account ' , {
' party_type ' : party_type ,
' party ' : party ,
' is_default ' : 1
} )
2015-09-25 10:47:50 +00:00
def get_party_account_currency ( party_type , party , company ) :
def generator ( ) :
party_account = get_party_account ( party_type , party , company )
2018-08-09 05:17:09 +00:00
return frappe . db . get_value ( " Account " , party_account , " account_currency " , cache = True )
2015-09-25 10:47:50 +00:00
return frappe . local_cache ( " party_account_currency " , ( party_type , party , company ) , generator )
2015-09-30 11:11:15 +00:00
def get_party_gle_currency ( party_type , party , company ) :
def generator ( ) :
existing_gle_currency = frappe . db . sql ( """ select account_currency from `tabGL Entry`
where docstatus = 1 and company = % ( company ) s and party_type = % ( party_type ) s and party = % ( party ) s
limit 1 """ , { " company " : company, " party_type " : party_type, " party " : party })
return existing_gle_currency [ 0 ] [ 0 ] if existing_gle_currency else None
2015-10-22 14:02:56 +00:00
return frappe . local_cache ( " party_gle_currency " , ( party_type , party , company ) , generator ,
regenerate_if_none = True )
2017-01-13 13:23:11 +00:00
2016-06-28 10:45:58 +00:00
def get_party_gle_account ( party_type , party , company ) :
def generator ( ) :
existing_gle_account = frappe . db . sql ( """ select account from `tabGL Entry`
where docstatus = 1 and company = % ( company ) s and party_type = % ( party_type ) s and party = % ( party ) s
limit 1 """ , { " company " : company, " party_type " : party_type, " party " : party })
return existing_gle_account [ 0 ] [ 0 ] if existing_gle_account else None
return frappe . local_cache ( " party_gle_account " , ( party_type , party , company ) , generator ,
regenerate_if_none = True )
2015-09-30 11:11:15 +00:00
2015-10-22 12:24:50 +00:00
def validate_party_gle_currency ( party_type , party , company , party_account_currency = None ) :
2015-09-30 11:11:15 +00:00
""" Validate party account currency with existing GL Entry ' s currency """
2015-10-22 12:24:50 +00:00
if not party_account_currency :
party_account_currency = get_party_account_currency ( party_type , party , company )
2015-09-30 11:11:15 +00:00
existing_gle_currency = get_party_gle_currency ( party_type , party , company )
if existing_gle_currency and party_account_currency != existing_gle_currency :
frappe . throw ( _ ( " Accounting Entry for {0} : {1} can only be made in currency: {2} " )
. format ( party_type , party , existing_gle_currency ) , InvalidAccountCurrency )
2015-09-28 09:43:38 +00:00
def validate_party_accounts ( doc ) :
companies = [ ]
for account in doc . get ( " accounts " ) :
if account . company in companies :
2015-10-16 07:37:45 +00:00
frappe . throw ( _ ( " There can only be 1 Account per Company in {0} {1} " )
. format ( doc . doctype , doc . name ) , DuplicatePartyAccountError )
2015-09-28 09:43:38 +00:00
else :
companies . append ( account . company )
2015-10-22 12:24:50 +00:00
2018-08-09 05:17:09 +00:00
party_account_currency = frappe . db . get_value ( " Account " , account . account , " account_currency " , cache = True )
2015-10-16 07:37:45 +00:00
existing_gle_currency = get_party_gle_currency ( doc . doctype , doc . name , account . company )
2019-09-05 09:44:09 +00:00
if frappe . db . get_default ( " Company " ) :
company_default_currency = frappe . get_cached_value ( ' Company ' ,
frappe . db . get_default ( " Company " ) , " default_currency " )
else :
company_default_currency = frappe . db . get_value ( ' Company ' , account . company , " default_currency " )
2015-10-22 12:24:50 +00:00
2015-10-16 07:38:33 +00:00
if existing_gle_currency and party_account_currency != existing_gle_currency :
frappe . throw ( _ ( " Accounting entries have already been made in currency {0} for company {1} . Please select a receivable or payable account with currency {0} . " ) . format ( existing_gle_currency , account . company ) )
2015-09-28 09:43:38 +00:00
2017-02-01 06:32:08 +00:00
if doc . get ( " default_currency " ) and party_account_currency and company_default_currency :
2016-03-30 07:54:42 +00:00
if doc . default_currency != party_account_currency and doc . default_currency != company_default_currency :
2017-08-31 15:28:47 +00:00
frappe . throw ( _ ( " Billing currency must be equal to either default company ' s currency or party account currency " ) )
2016-03-30 07:54:42 +00:00
2015-07-09 11:05:46 +00:00
@frappe.whitelist ( )
2018-02-16 07:35:21 +00:00
def get_due_date ( posting_date , party_type , party , company = None , bill_date = None ) :
2017-08-31 15:28:47 +00:00
""" Get due date from `Payment Terms Template` """
2014-01-28 12:13:10 +00:00
due_date = None
2018-02-16 07:35:21 +00:00
if ( bill_date or posting_date ) and party :
due_date = bill_date or posting_date
2018-01-29 10:37:21 +00:00
template_name = get_pyt_term_template ( party , party_type , company )
2018-07-13 12:10:48 +00:00
2017-08-31 15:28:47 +00:00
if template_name :
2018-02-16 07:35:21 +00:00
due_date = get_due_date_from_template ( template_name , posting_date , bill_date ) . strftime ( " % Y- % m- %d " )
2017-09-05 00:15:31 +00:00
else :
if party_type == " Supplier " :
2018-08-09 05:17:09 +00:00
supplier_group = frappe . get_cached_value ( party_type , party , " supplier_group " )
template_name = frappe . get_cached_value ( " Supplier Group " , supplier_group , " payment_terms " )
2017-09-05 17:11:58 +00:00
if template_name :
2018-02-16 07:35:21 +00:00
due_date = get_due_date_from_template ( template_name , posting_date , bill_date ) . strftime ( " % Y- % m- %d " )
# If due date is calculated from bill_date, check this condition
if getdate ( due_date ) < getdate ( posting_date ) :
due_date = posting_date
2014-04-10 13:10:57 +00:00
return due_date
2014-01-28 12:13:10 +00:00
2018-02-16 07:35:21 +00:00
def get_due_date_from_template ( template_name , posting_date , bill_date ) :
2017-08-31 15:28:47 +00:00
"""
Inspects all ` Payment Term ` s from the a ` Payment Terms Template ` and returns the due
date after considering all the ` Payment Term ` s requirements .
: param template_name : Name of the ` Payment Terms Template `
: return : String representing the calculated due date
"""
2018-02-16 07:35:21 +00:00
due_date = getdate ( bill_date or posting_date )
2017-08-31 15:28:47 +00:00
template = frappe . get_doc ( ' Payment Terms Template ' , template_name )
for term in template . terms :
if term . due_date_based_on == ' Day(s) after invoice date ' :
due_date = max ( due_date , add_days ( due_date , term . credit_days ) )
elif term . due_date_based_on == ' Day(s) after the end of the invoice month ' :
due_date = max ( due_date , add_days ( get_last_day ( due_date ) , term . credit_days ) )
else :
due_date = max ( due_date , add_months ( get_last_day ( due_date ) , term . credit_months ) )
return due_date
2018-07-18 11:38:16 +00:00
def validate_due_date ( posting_date , due_date , party_type , party , company = None , bill_date = None , template_name = None ) :
2015-07-09 11:05:46 +00:00
if getdate ( due_date ) < getdate ( posting_date ) :
2018-11-26 13:12:29 +00:00
frappe . throw ( _ ( " Due Date cannot be before Posting / Supplier Invoice Date " ) )
2015-07-09 11:05:46 +00:00
else :
2018-07-13 12:10:48 +00:00
if not template_name : return
2018-07-18 11:38:16 +00:00
default_due_date = get_due_date_from_template ( template_name , posting_date , bill_date ) . strftime ( " % Y- % m- %d " )
2015-09-25 11:02:14 +00:00
if not default_due_date :
return
2015-07-10 11:41:58 +00:00
if default_due_date != posting_date and getdate ( due_date ) > getdate ( default_due_date ) :
2015-07-09 11:05:46 +00:00
is_credit_controller = frappe . db . get_single_value ( " Accounts Settings " , " credit_controller " ) in frappe . get_roles ( )
if is_credit_controller :
msgprint ( _ ( " Note: Due / Reference Date exceeds allowed customer credit days by {0} day(s) " )
. format ( date_diff ( due_date , default_due_date ) ) )
else :
2017-11-21 14:28:16 +00:00
frappe . throw ( _ ( " Due / Reference Date cannot be after {0} " )
. format ( formatdate ( default_due_date ) ) )
2015-09-18 07:29:51 +00:00
2015-08-26 05:11:31 +00:00
@frappe.whitelist ( )
2019-09-05 07:31:15 +00:00
def get_address_tax_category ( tax_category = None , billing_address = None , shipping_address = None ) :
2018-12-28 20:49:11 +00:00
addr_tax_category_from = frappe . db . get_single_value ( " Accounts Settings " , " determine_address_tax_category_from " )
if addr_tax_category_from == " Shipping Address " :
if shipping_address :
tax_category = frappe . db . get_value ( " Address " , shipping_address , " tax_category " ) or tax_category
else :
if billing_address :
tax_category = frappe . db . get_value ( " Address " , billing_address , " tax_category " ) or tax_category
return cstr ( tax_category )
2018-12-26 21:11:07 +00:00
2015-08-26 05:11:31 +00:00
@frappe.whitelist ( )
2018-12-26 21:11:07 +00:00
def set_taxes ( party , party_type , posting_date , company , customer_group = None , supplier_group = None , tax_category = None ,
2015-09-11 10:14:06 +00:00
billing_address = None , shipping_address = None , use_for_shopping_cart = None ) :
2015-08-21 09:34:57 +00:00
from erpnext . accounts . doctype . tax_rule . tax_rule import get_tax_template , get_party_details
args = {
2015-09-23 10:13:09 +00:00
party_type . lower ( ) : party ,
2015-08-21 09:34:57 +00:00
" company " : company
}
2015-09-18 07:29:51 +00:00
2018-12-26 21:11:07 +00:00
if tax_category :
args [ ' tax_category ' ] = tax_category
2017-09-29 07:51:22 +00:00
if customer_group :
args [ ' customer_group ' ] = customer_group
2018-04-19 13:07:29 +00:00
if supplier_group :
args [ ' supplier_group ' ] = supplier_group
2017-09-29 07:51:22 +00:00
2015-08-26 05:11:31 +00:00
if billing_address or shipping_address :
2015-09-11 10:14:06 +00:00
args . update ( get_party_details ( party , party_type , { " billing_address " : billing_address , \
" shipping_address " : shipping_address } ) )
2015-08-26 05:11:31 +00:00
else :
args . update ( get_party_details ( party , party_type ) )
2015-09-18 07:29:51 +00:00
2016-04-08 12:06:10 +00:00
if party_type in ( " Customer " , " Lead " ) :
2015-08-21 09:34:57 +00:00
args . update ( { " tax_type " : " Sales " } )
2016-04-08 12:06:10 +00:00
if party_type == ' Lead ' :
args [ ' customer ' ] = None
del args [ ' lead ' ]
2015-08-21 09:34:57 +00:00
else :
args . update ( { " tax_type " : " Purchase " } )
2015-09-18 07:29:51 +00:00
2015-09-11 10:14:06 +00:00
if use_for_shopping_cart :
args . update ( { " use_for_shopping_cart " : use_for_shopping_cart } )
2015-09-18 07:29:51 +00:00
return get_tax_template ( posting_date , args )
2016-01-25 12:00:49 +00:00
2017-08-31 12:44:57 +00:00
@frappe.whitelist ( )
2018-01-29 10:37:21 +00:00
def get_pyt_term_template ( party_name , party_type , company = None ) :
if party_type not in ( " Customer " , " Supplier " ) :
return
2017-08-31 12:44:57 +00:00
template = None
2018-01-29 10:37:21 +00:00
if party_type == ' Customer ' :
2018-08-09 05:17:09 +00:00
customer = frappe . get_cached_value ( " Customer " , party_name ,
2018-01-29 10:37:21 +00:00
fieldname = [ ' payment_terms ' , " customer_group " ] , as_dict = 1 )
template = customer . payment_terms
if not template and customer . customer_group :
2018-08-09 05:17:09 +00:00
template = frappe . get_cached_value ( " Customer Group " ,
customer . customer_group , ' payment_terms ' )
2018-01-29 10:37:21 +00:00
else :
2018-08-09 05:17:09 +00:00
supplier = frappe . get_cached_value ( " Supplier " , party_name ,
2018-04-19 13:07:29 +00:00
fieldname = [ ' payment_terms ' , " supplier_group " ] , as_dict = 1 )
2018-01-29 10:37:21 +00:00
template = supplier . payment_terms
2018-04-19 13:07:29 +00:00
if not template and supplier . supplier_group :
2018-08-09 05:17:09 +00:00
template = frappe . get_cached_value ( " Supplier Group " , supplier . supplier_group , ' payment_terms ' )
2018-01-29 10:37:21 +00:00
if not template and company :
2018-08-08 11:07:31 +00:00
template = frappe . get_cached_value ( ' Company ' , company , fieldname = ' payment_terms ' )
2018-01-29 10:37:21 +00:00
return template
2017-08-31 12:44:57 +00:00
2016-01-26 09:26:52 +00:00
def validate_party_frozen_disabled ( party_type , party_name ) :
2016-01-26 08:27:06 +00:00
if party_type and party_name :
2017-01-30 09:45:58 +00:00
if party_type in ( " Customer " , " Supplier " ) :
2018-08-09 05:17:09 +00:00
party = frappe . get_cached_value ( party_type , party_name , [ " is_frozen " , " disabled " ] , as_dict = True )
2019-10-20 12:06:36 +00:00
if party . disabled :
frappe . throw ( _ ( " {0} {1} is disabled " ) . format ( party_type , party_name ) , PartyDisabled )
elif party . get ( " is_frozen " ) :
2018-08-09 05:17:09 +00:00
frozen_accounts_modifier = frappe . db . get_single_value ( ' Accounts Settings ' , ' frozen_accounts_modifier ' )
2017-01-30 09:45:58 +00:00
if not frozen_accounts_modifier in frappe . get_roles ( ) :
frappe . throw ( _ ( " {0} {1} is frozen " ) . format ( party_type , party_name ) , PartyFrozen )
elif party_type == " Employee " :
if frappe . db . get_value ( " Employee " , party_name , " status " ) == " Left " :
2017-04-11 10:25:34 +00:00
frappe . msgprint ( _ ( " {0} {1} is not active " ) . format ( party_type , party_name ) , alert = True )
2016-04-14 12:00:40 +00:00
def get_timeline_data ( doctype , name ) :
''' returns timeline data for the past one year '''
from frappe . desk . form . load import get_communication_data
2017-02-16 07:42:29 +00:00
out = { }
2018-05-30 06:26:23 +00:00
fields = ' date(creation), count(name) '
after = add_years ( None , - 1 ) . strftime ( ' % Y- % m- %d ' )
group_by = ' group by date(creation) '
2019-05-23 08:46:56 +00:00
data = get_communication_data ( doctype , name , after = after , group_by = ' group by date(creation) ' ,
fields = ' date(C.creation) as creation, count(C.name) ' , as_dict = False )
2018-05-30 06:26:23 +00:00
# fetch and append data from Activity Log
data + = frappe . db . sql ( """ select {fields}
from ` tabActivity Log `
2019-08-19 06:21:16 +00:00
where ( reference_doctype = " {doctype} " and reference_name = " {name} " )
or ( timeline_doctype in ( " {doctype} " ) and timeline_name = " {name} " )
or ( reference_doctype in ( " Quotation " , " Opportunity " ) and timeline_name = " {name} " )
2018-05-30 06:26:23 +00:00
and status != ' Success ' and creation > { after }
{ group_by } order by creation desc
2018-06-07 11:18:31 +00:00
""" .format(doctype=frappe.db.escape(doctype), name=frappe.db.escape(name), fields=fields,
2018-05-30 06:26:23 +00:00
group_by = group_by , after = after ) , as_dict = False )
2017-02-16 07:42:29 +00:00
timeline_items = dict ( data )
2018-02-13 09:12:40 +00:00
for date , count in iteritems ( timeline_items ) :
2017-02-16 07:42:29 +00:00
timestamp = get_timestamp ( date )
out . update ( { timestamp : count } )
2017-05-24 07:11:14 +00:00
return out
2017-06-22 11:07:04 +00:00
2018-12-25 10:36:19 +00:00
def get_dashboard_info ( party_type , party , loyalty_program = None ) :
2017-05-24 07:11:14 +00:00
current_fiscal_year = get_fiscal_year ( nowdate ( ) , as_dict = True )
2017-06-22 11:07:04 +00:00
2017-05-24 07:11:14 +00:00
doctype = " Sales Invoice " if party_type == " Customer " else " Purchase Invoice "
2017-06-22 11:07:04 +00:00
2018-11-29 10:54:28 +00:00
companies = frappe . get_all ( doctype , filters = {
' docstatus ' : 1 ,
party_type . lower ( ) : party
} , distinct = 1 , fields = [ ' company ' ] )
2018-11-23 04:47:28 +00:00
company_wise_info = [ ]
2018-11-29 10:54:28 +00:00
company_wise_grand_total = frappe . get_all ( doctype ,
filters = {
' docstatus ' : 1 ,
party_type . lower ( ) : party ,
' posting_date ' : ( ' between ' , [ current_fiscal_year . year_start_date , current_fiscal_year . year_end_date ] )
} ,
group_by = " company " ,
fields = [ " company " , " sum(grand_total) as grand_total " , " sum(base_grand_total) as base_grand_total " ]
)
2018-11-27 09:34:12 +00:00
2018-12-26 05:31:02 +00:00
loyalty_point_details = [ ]
2018-12-25 10:36:19 +00:00
if party_type == " Customer " :
loyalty_point_details = frappe . _dict ( frappe . get_all ( " Loyalty Point Entry " ,
filters = {
' customer ' : party ,
' expiry_date ' : ( ' >= ' , getdate ( ) ) ,
} ,
group_by = " company " ,
fields = [ " company " , " sum(loyalty_points) as loyalty_points " ] ,
as_list = 1
) )
2018-11-27 09:34:12 +00:00
company_wise_billing_this_year = frappe . _dict ( )
for d in company_wise_grand_total :
company_wise_billing_this_year . setdefault (
d . company , {
" grand_total " : d . grand_total ,
" base_grand_total " : d . base_grand_total
} )
2018-11-23 04:47:28 +00:00
2017-06-22 11:07:04 +00:00
2018-11-23 04:47:28 +00:00
company_wise_total_unpaid = frappe . _dict ( frappe . db . sql ( """
select company , sum ( debit_in_account_currency ) - sum ( credit_in_account_currency )
2017-05-24 07:31:26 +00:00
from ` tabGL Entry `
2018-11-23 04:47:28 +00:00
where party_type = % s and party = % s
group by company """ , (party_type, party)))
for d in companies :
company_default_currency = frappe . db . get_value ( " Company " , d . company , ' default_currency ' )
party_account_currency = get_party_account_currency ( party_type , party , d . company )
if party_account_currency == company_default_currency :
2018-11-27 09:34:12 +00:00
billing_this_year = flt ( company_wise_billing_this_year . get ( d . company , { } ) . get ( " base_grand_total " ) )
2018-11-23 04:47:28 +00:00
else :
2018-11-27 09:34:12 +00:00
billing_this_year = flt ( company_wise_billing_this_year . get ( d . company , { } ) . get ( " grand_total " ) )
2018-11-23 04:47:28 +00:00
total_unpaid = flt ( company_wise_total_unpaid . get ( d . company ) )
2018-12-25 10:36:19 +00:00
if loyalty_point_details :
loyalty_points = loyalty_point_details . get ( d . company )
2018-11-23 04:47:28 +00:00
info = { }
info [ " billing_this_year " ] = flt ( billing_this_year ) if billing_this_year else 0
info [ " currency " ] = party_account_currency
info [ " total_unpaid " ] = flt ( total_unpaid ) if total_unpaid else 0
info [ " company " ] = d . company
2018-12-25 10:36:19 +00:00
if party_type == " Customer " and loyalty_point_details :
info [ " loyalty_points " ] = loyalty_points
2018-11-23 04:47:28 +00:00
if party_type == " Supplier " :
info [ " total_unpaid " ] = - 1 * info [ " total_unpaid " ]
2017-05-24 07:11:14 +00:00
2018-11-23 04:47:28 +00:00
company_wise_info . append ( info )
2017-06-22 11:07:04 +00:00
2018-11-23 04:47:28 +00:00
return company_wise_info
2017-10-25 06:54:34 +00:00
def get_party_shipping_address ( doctype , name ) :
"""
Returns an Address name ( best guess ) for the given doctype and name for which ` address_type == ' Shipping ' ` is true .
and / or ` is_shipping_address = 1 ` .
It returns an empty string if there is no matching record .
: param doctype : Party Doctype
: param name : Party name
: return : String
"""
out = frappe . db . sql (
' SELECT dl.parent '
' from `tabDynamic Link` dl join `tabAddress` ta on dl.parent=ta.name '
' where '
' dl.link_doctype= %s '
' and dl.link_name= %s '
' and dl.parenttype= " Address " '
2018-12-10 12:15:39 +00:00
' and ifnull(ta.disabled, 0) = 0 and '
2017-10-25 06:54:34 +00:00
' (ta.address_type= " Shipping " or ta.is_shipping_address=1) '
' order by ta.is_shipping_address desc, ta.address_type desc limit 1 ' ,
( doctype , name )
)
if out :
return out [ 0 ] [ 0 ]
else :
return ' '
2019-01-15 12:08:31 +00:00
2019-03-25 10:07:25 +00:00
def get_partywise_advanced_payment_amount ( party_type , posting_date = None ) :
cond = " 1=1 "
if posting_date :
cond = " posting_date <= ' {0} ' " . format ( posting_date )
2019-01-15 12:08:31 +00:00
data = frappe . db . sql ( """ SELECT party, sum( {0} ) as amount
FROM ` tabGL Entry `
2019-03-19 09:36:01 +00:00
WHERE
party_type = % s and against_voucher is null
2019-03-25 10:07:25 +00:00
and { 1 } GROUP BY party """
. format ( ( " credit " ) if party_type == " Customer " else " debit " , cond ) , party_type )
2019-01-15 12:08:31 +00:00
if data :
2019-09-05 09:44:09 +00:00
return frappe . _dict ( data )