Set Receivable/Payable account based on party

This commit is contained in:
Nabin Hait 2014-09-10 17:11:30 +05:30
parent e2095c0dd7
commit db030d1761
13 changed files with 1886 additions and 1849 deletions

View File

@ -6,21 +6,21 @@ import frappe
def _make_test_records(verbose): def _make_test_records(verbose):
from frappe.test_runner import make_test_objects from frappe.test_runner import make_test_objects
accounts = [ accounts = [
# [account_name, parent_account, group_or_ledger] # [account_name, parent_account, group_or_ledger]
["_Test Account Bank Account", "Bank Accounts", "Ledger", "Bank"], ["_Test Account Bank Account", "Bank Accounts", "Ledger", "Bank"],
["_Test Account Stock Expenses", "Direct Expenses", "Group", None], ["_Test Account Stock Expenses", "Direct Expenses", "Group", None],
["_Test Account Shipping Charges", "_Test Account Stock Expenses", "Ledger", "Chargeable"], ["_Test Account Shipping Charges", "_Test Account Stock Expenses", "Ledger", "Chargeable"],
["_Test Account Customs Duty", "_Test Account Stock Expenses", "Ledger", "Tax"], ["_Test Account Customs Duty", "_Test Account Stock Expenses", "Ledger", "Tax"],
["_Test Account Insurance Charges", "_Test Account Stock Expenses", "Ledger", "Chargeable"], ["_Test Account Insurance Charges", "_Test Account Stock Expenses", "Ledger", "Chargeable"],
["_Test Account Tax Assets", "Current Assets", "Group", None], ["_Test Account Tax Assets", "Current Assets", "Group", None],
["_Test Account VAT", "_Test Account Tax Assets", "Ledger", "Tax"], ["_Test Account VAT", "_Test Account Tax Assets", "Ledger", "Tax"],
["_Test Account Service Tax", "_Test Account Tax Assets", "Ledger", "Tax"], ["_Test Account Service Tax", "_Test Account Tax Assets", "Ledger", "Tax"],
["_Test Account Reserves and Surplus", "Current Liabilities", "Ledger", None], ["_Test Account Reserves and Surplus", "Current Liabilities", "Ledger", None],
["_Test Account Cost for Goods Sold", "Expenses", "Ledger", None], ["_Test Account Cost for Goods Sold", "Expenses", "Ledger", None],
@ -29,10 +29,14 @@ def _make_test_records(verbose):
["_Test Account S&H Education Cess", "_Test Account Tax Assets", "Ledger", "Tax"], ["_Test Account S&H Education Cess", "_Test Account Tax Assets", "Ledger", "Tax"],
["_Test Account CST", "Direct Expenses", "Ledger", "Tax"], ["_Test Account CST", "Direct Expenses", "Ledger", "Tax"],
["_Test Account Discount", "Direct Expenses", "Ledger", None], ["_Test Account Discount", "Direct Expenses", "Ledger", None],
# related to Account Inventory Integration # related to Account Inventory Integration
["_Test Account Stock In Hand", "Current Assets", "Ledger", None], ["_Test Account Stock In Hand", "Current Assets", "Ledger", None],
["_Test Account Fixed Assets", "Current Assets", "Ledger", None], ["_Test Account Fixed Assets", "Current Assets", "Ledger", None],
# Receivable / Payable Account
["_Test Receivable", "Current Assets", "Ledger", "Receivable"],
["_Test Payable", "Current Liabilities", "Ledger", "Payable"],
] ]
for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]: for company, abbr in [["_Test Company", "_TC"], ["_Test Company 1", "_TC1"]]:
@ -44,5 +48,5 @@ def _make_test_records(verbose):
"group_or_ledger": group_or_ledger, "group_or_ledger": group_or_ledger,
"account_type": account_type "account_type": account_type
} for account_name, parent_account, group_or_ledger, account_type in accounts]) } for account_name, parent_account, group_or_ledger, account_type in accounts])
return test_objects return test_objects

View File

@ -263,3 +263,22 @@ cur_frm.cscript.voucher_type = function(doc, cdt, cdn) {
}) })
} }
} }
frappe.ui.form.on("Journal Voucher Detail", "party", function(frm, cdt, cdn) {
var d = locals[cdt][cdn];
if(!d.account && d.party_type && d.party) {
return frappe.call({
method: "erpnext.accounts.party.get_party_account",
args: {
company: frm.doc.company,
party_type: d.party_type,
party: d.party
},
callback: function(r) {
if(!r.exc && r.message) {
frappe.model.set_value(cdt, cdn, "account", r.message);
}
}
});
}
})

View File

@ -152,38 +152,36 @@ class JournalVoucher(AccountsController):
def validate_account_in_against_voucher(self, against_field, doctype): def validate_account_in_against_voucher(self, against_field, doctype):
payment_against_voucher = frappe._dict() payment_against_voucher = frappe._dict()
field_dict = {'Sales Invoice': "Debit To", field_dict = {'Sales Invoice': ["Customer", "Debit To"],
'Purchase Invoice': "Credit To", 'Purchase Invoice': ["Supplier", "Credit To"],
'Sales Order': "Customer", 'Sales Order': ["Customer"],
'Purchase Order': "Supplier" 'Purchase Order': ["Supplier"]
} }
for d in self.get("entries"): for d in self.get("entries"):
if d.get(against_field): if d.get(against_field):
dr_or_cr = "credit" if against_field in ["against_invoice", "against_sales_order"] \ dr_or_cr = "credit" if against_field in ["against_invoice", "against_sales_order"] \
else "debit" else "debit"
if against_field in ["against_invoice", "against_sales_order"] \ if against_field in ["against_invoice", "against_sales_order"] and flt(d.debit) > 0:
and flt(d.debit) > 0:
frappe.throw(_("Row {0}: Debit entry can not be linked with a {1}").format(d.idx, doctype)) frappe.throw(_("Row {0}: Debit entry can not be linked with a {1}").format(d.idx, doctype))
if against_field in ["against_voucher", "against_purchase_order"] \ if against_field in ["against_voucher", "against_purchase_order"] and flt(d.credit) > 0:
and flt(d.credit) > 0:
frappe.throw(_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, doctype)) frappe.throw(_("Row {0}: Credit entry can not be linked with a {1}").format(d.idx, doctype))
voucher_account = frappe.db.get_value(doctype, d.get(against_field), \ against_voucher = frappe.db.get_value(doctype, d.get(against_field),
scrub(field_dict.get(doctype))) [scrub(d) for d in field_dict.get(doctype)])
account_master_name = frappe.db.get_value("Account", d.account, "master_name") if against_field in ["against_invoice", "against_voucher"]:
if (against_voucher[0] !=d.party or against_voucher[1] != d.account):
if against_field in ["against_invoice", "against_voucher"] \ frappe.throw(_("Row {0}: Party / Account does not match with \
and voucher_account != d.account: Customer / Debit To in {1}").format(d.idx, doctype))
frappe.throw(_("Row {0}: Account {1} does not match with {2} {3} account") \ else:
.format(d.idx, d.account, doctype, field_dict.get(doctype))) payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr)))
if against_field in ["against_sales_order", "against_purchase_order"]: if against_field in ["against_sales_order", "against_purchase_order"]:
if voucher_account != account_master_name: if against_voucher != d.party:
frappe.throw(_("Row {0}: Account {1} does not match with {2} {3} Name") \ frappe.throw(_("Row {0}: {1} {2} does not match with {3}") \
.format(d.idx, d.account, doctype, field_dict.get(doctype))) .format(d.idx, d.party_type, d.party, doctype))
elif d.is_advance == "Yes": elif d.is_advance == "Yes":
payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr))) payment_against_voucher.setdefault(d.get(against_field), []).append(flt(d.get(dr_or_cr)))
@ -420,6 +418,8 @@ def get_payment_entry_from_sales_invoice(sales_invoice):
# credit customer # credit customer
jv.get("entries")[0].account = si.debit_to jv.get("entries")[0].account = si.debit_to
jv.get("entries")[0].party_type = "Customer"
jv.get("entries")[0].party = si.customer
jv.get("entries")[0].balance = get_balance_on(si.debit_to) jv.get("entries")[0].balance = get_balance_on(si.debit_to)
jv.get("entries")[0].credit = si.outstanding_amount jv.get("entries")[0].credit = si.outstanding_amount
jv.get("entries")[0].against_invoice = si.name jv.get("entries")[0].against_invoice = si.name
@ -438,6 +438,8 @@ def get_payment_entry_from_purchase_invoice(purchase_invoice):
# credit supplier # credit supplier
jv.get("entries")[0].account = pi.credit_to jv.get("entries")[0].account = pi.credit_to
jv.get("entries")[0].party_type = "Supplier"
jv.get("entries")[0].party = pi.supplier
jv.get("entries")[0].balance = get_balance_on(pi.credit_to) jv.get("entries")[0].balance = get_balance_on(pi.credit_to)
jv.get("entries")[0].debit = pi.outstanding_amount jv.get("entries")[0].debit = pi.outstanding_amount
jv.get("entries")[0].against_voucher = pi.name jv.get("entries")[0].against_voucher = pi.name
@ -452,7 +454,6 @@ def get_payment_entry(doc):
jv = frappe.new_doc('Journal Voucher') jv = frappe.new_doc('Journal Voucher')
jv.voucher_type = 'Bank Voucher' jv.voucher_type = 'Bank Voucher'
jv.company = doc.company jv.company = doc.company
jv.fiscal_year = doc.fiscal_year jv.fiscal_year = doc.fiscal_year

View File

@ -86,17 +86,13 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({
posting_date: this.frm.doc.posting_date, posting_date: this.frm.doc.posting_date,
party: this.frm.doc.supplier, party: this.frm.doc.supplier,
party_type: "Supplier", party_type: "Supplier",
account: this.frm.doc.debit_to, account: this.frm.doc.credit_to,
price_list: this.frm.doc.buying_price_list, price_list: this.frm.doc.buying_price_list,
}, function() { }, function() {
me.apply_pricing_rule(); me.apply_pricing_rule();
}) })
}, },
credit_to: function() {
this.supplier();
},
write_off_amount: function() { write_off_amount: function() {
this.calculate_outstanding_amount(); this.calculate_outstanding_amount();
this.frm.refresh_fields(); this.frm.refresh_fields();
@ -169,7 +165,8 @@ cur_frm.fields_dict['entries'].grid.get_field("item_code").get_query = function(
cur_frm.fields_dict['credit_to'].get_query = function(doc) { cur_frm.fields_dict['credit_to'].get_query = function(doc) {
return{ return{
filters:{ filters:{
'report_type': 'Balance Sheet', 'account_type': 'Payable',
'root_type': 'Liability',
'group_or_ledger': 'Ledger', 'group_or_ledger': 'Ledger',
'company': doc.company 'company': doc.company
} }

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
"buying_price_list": "_Test Price List", "buying_price_list": "_Test Price List",
"company": "_Test Company", "company": "_Test Company",
"conversion_rate": 1, "conversion_rate": 1,
"credit_to": "_Test Supplier - _TC", "credit_to": "_Test Payable - _TC",
"currency": "INR", "currency": "INR",
"doctype": "Purchase Invoice", "doctype": "Purchase Invoice",
"entries": [ "entries": [
@ -146,7 +146,7 @@
"buying_price_list": "_Test Price List", "buying_price_list": "_Test Price List",
"company": "_Test Company", "company": "_Test Company",
"conversion_rate": 1.0, "conversion_rate": 1.0,
"credit_to": "_Test Supplier - _TC", "credit_to": "_Test Payable - _TC",
"currency": "INR", "currency": "INR",
"doctype": "Purchase Invoice", "doctype": "Purchase Invoice",
"entries": [ "entries": [

View File

@ -172,10 +172,6 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte
}) })
}, },
debit_to: function() {
this.customer();
},
allocated_amount: function() { allocated_amount: function() {
this.calculate_total_advance("Sales Invoice", "advance_adjustment_details"); this.calculate_total_advance("Sales Invoice", "advance_adjustment_details");
this.frm.refresh_fields(); this.frm.refresh_fields();
@ -306,7 +302,8 @@ cur_frm.fields_dict.debit_to.get_query = function(doc) {
cur_frm.fields_dict.cash_bank_account.get_query = function(doc) { cur_frm.fields_dict.cash_bank_account.get_query = function(doc) {
return{ return{
filters: { filters: {
'report_type': 'Balance Sheet', 'account_type': 'Receivable',
'root_type': 'Asset',
'group_or_ledger': 'Ledger', 'group_or_ledger': 'Ledger',
'company': doc.company 'company': doc.company
} }

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"currency": "INR", "currency": "INR",
"customer": "_Test Customer", "customer": "_Test Customer",
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Customer - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"due_date": "2013-01-23", "due_date": "2013-01-23",
"entries": [ "entries": [
@ -74,7 +74,7 @@
"currency": "INR", "currency": "INR",
"customer": "_Test Customer", "customer": "_Test Customer",
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Customer - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"due_date": "2013-03-07", "due_date": "2013-03-07",
"entries": [ "entries": [
@ -130,7 +130,7 @@
"currency": "INR", "currency": "INR",
"customer": "_Test Customer", "customer": "_Test Customer",
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Customer - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"due_date": "2013-01-23", "due_date": "2013-01-23",
"entries": [ "entries": [
@ -256,7 +256,7 @@
"currency": "INR", "currency": "INR",
"customer": "_Test Customer", "customer": "_Test Customer",
"customer_name": "_Test Customer", "customer_name": "_Test Customer",
"debit_to": "_Test Customer - _TC", "debit_to": "_Test Receivable - _TC",
"doctype": "Sales Invoice", "doctype": "Sales Invoice",
"due_date": "2013-01-23", "due_date": "2013-01-23",
"entries": [ "entries": [

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe import _, msgprint from frappe import _, msgprint, scrub
from frappe.defaults import get_user_permissions from frappe.defaults import get_user_permissions
from frappe.utils import add_days, getdate, formatdate, flt from frappe.utils import add_days, getdate, formatdate, flt
from erpnext.utilities.doctype.address.address import get_address_display from erpnext.utilities.doctype.address.address import get_address_display
@ -116,8 +116,6 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
if party: if party:
account = get_party_account(company, party, party_type) account = get_party_account(company, party, party_type)
elif account:
party = frappe.db.get_value('Account', account, 'master_name')
account_fieldname = "debit_to" if party_type=="Customer" else "credit_to" account_fieldname = "debit_to" if party_type=="Customer" else "credit_to"
@ -128,15 +126,26 @@ def set_account_and_due_date(party, account, party_type, company, posting_date,
} }
return out return out
@frappe.whitelist()
def get_party_account(company, party, party_type): def get_party_account(company, party, party_type):
if not company: if not company:
frappe.throw(_("Please select company first.")) frappe.throw(_("Please select company first."))
if party: if party:
acc_head = frappe.db.get_value("Account", {"master_name":party, party_group_doctype = "Customer Group" if party_type=="Customer" else "Supplier Type"
"master_type": party_type, "company": company}) party_details = frappe.db.sql("""select p.{0}, pa.account
from `tab{1}` p left join `tabParty Account` pa on pa.parent = p.name
where p.name = %s""".format(scrub(party_group_doctype), party_type), party)
if party_details:
party_group, account = party_details[0]
return acc_head if not account:
account = frappe.db.get_value("Party Account",
{"parenttype": party_group_doctype, "parent": party_group, "company": company}, "account") or \
frappe.db.get_value("Company", company,
"default_receivable_account" if party_type=="Customer" else "default_payable_account")
return account
def get_due_date(posting_date, party_type, party, company): def get_due_date(posting_date, party_type, party, company):
"""Set Due Date = Posting Date + Credit Days""" """Set Due Date = Posting Date + Credit Days"""

View File

@ -65,9 +65,9 @@ cur_frm.cscript.setup_dashboard = function(doc) {
if(r.message["company_currency"].length == 1) { if(r.message["company_currency"].length == 1) {
cur_frm.dashboard.set_headline( cur_frm.dashboard.set_headline(
__("Total Billing This Year: ") + "<b>" __("Total Billing This Year: ") + "<b>"
+ format_currency(r.message.total_billing, company_currency[0]) + format_currency(r.message.total_billing, r.message["company_currency"][0])
+ '</b> / <span class="text-muted">' + __("Unpaid") + ": <b>" + '</b> / <span class="text-muted">' + __("Unpaid") + ": <b>"
+ format_currency(r.message.total_unpaid, company_currency[0]) + format_currency(r.message.total_unpaid, r.message["company_currency"][0])
+ '</b></span>'); + '</b></span>');
} }
} }

View File

@ -813,6 +813,8 @@ def make_return_jv_from_sales_invoice(se, ref):
# customer account entry # customer account entry
parent = { parent = {
"account": ref.doc.debit_to, "account": ref.doc.debit_to,
"party_type": "Customer",
"party": ref.doc.customer,
"against_invoice": ref.doc.name, "against_invoice": ref.doc.name,
} }
@ -879,7 +881,11 @@ def make_return_jv_from_delivery_note(se, ref):
children.append(account) children.append(account)
if not parent: if not parent:
parent = {"account": si.debit_to} parent = {
"account": si.debit_to,
"party_type": "Customer",
"party": si.customer
}
break break
@ -933,7 +939,11 @@ def make_return_jv_from_purchase_receipt(se, ref):
children.append(account) children.append(account)
if not parent: if not parent:
parent = {"account": pi.credit_to} parent = {
"account": pi.credit_to,
"party_type": "Supplier",
"party": pi.supplier
}
break break

View File

@ -332,7 +332,7 @@ class TestStockEntry(unittest.TestCase):
si = frappe.get_doc(si_doc) si = frappe.get_doc(si_doc)
si.posting_date = dn.posting_date si.posting_date = dn.posting_date
si.debit_to = "_Test Customer - _TC" si.debit_to = "_Test Receivable - _TC"
for d in si.get("entries"): for d in si.get("entries"):
d.income_account = "Sales - _TC" d.income_account = "Sales - _TC"
d.cost_center = "_Test Cost Center - _TC" d.cost_center = "_Test Cost Center - _TC"
@ -425,7 +425,7 @@ class TestStockEntry(unittest.TestCase):
si = make_sales_invoice(so.name) si = make_sales_invoice(so.name)
si.posting_date = dn.posting_date si.posting_date = dn.posting_date
si.debit_to = "_Test Customer - _TC" si.debit_to = "_Test Receivable - _TC"
for d in si.get("entries"): for d in si.get("entries"):
d.income_account = "Sales - _TC" d.income_account = "Sales - _TC"
d.cost_center = "_Test Cost Center - _TC" d.cost_center = "_Test Cost Center - _TC"
@ -471,7 +471,7 @@ class TestStockEntry(unittest.TestCase):
pi = frappe.get_doc(pi_doc) pi = frappe.get_doc(pi_doc)
pi.posting_date = pr.posting_date pi.posting_date = pr.posting_date
pi.credit_to = "_Test Supplier - _TC" pi.credit_to = "_Test Payable - _TC"
for d in pi.get("entries"): for d in pi.get("entries"):
d.expense_account = "_Test Account Cost for Goods Sold - _TC" d.expense_account = "_Test Account Cost for Goods Sold - _TC"
d.cost_center = "_Test Cost Center - _TC" d.cost_center = "_Test Cost Center - _TC"
@ -574,7 +574,7 @@ class TestStockEntry(unittest.TestCase):
pi = frappe.get_doc(pi_doc) pi = frappe.get_doc(pi_doc)
pi.posting_date = pr.posting_date pi.posting_date = pr.posting_date
pi.credit_to = "_Test Supplier - _TC" pi.credit_to = "_Test Payable - _TC"
for d in pi.get("entries"): for d in pi.get("entries"):
d.expense_account = "_Test Account Cost for Goods Sold - _TC" d.expense_account = "_Test Account Cost for Goods Sold - _TC"
d.cost_center = "_Test Cost Center - _TC" d.cost_center = "_Test Cost Center - _TC"