Allow cost center in entry of balance sheet accounts (#14972)
* Allow Cost Center In Entry of Balance Sheet Account
* Add parent cost center in get payment entry
* Add Tests for Allow Cost Center In Entry of Balance Sheet Account
* Add tests for cost center wise account and party balance
* set parent cost center in taxes
* 1. Remove copy parent cost_center to child
2. Improve update party and account balance functionality on cost_center change
3. Add cost_center filter to get_outstanding_documents
* fix Codacy and Travis issue
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index e040b61..b7eb786 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -302,6 +302,37 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "allow_cost_center_in_entry_of_bs_account",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow Cost Center In Entry of Balance Sheet Account",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "print_settings",
"fieldtype": "Section Break",
"hidden": 0,
@@ -543,6 +574,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
},
{
@@ -575,6 +607,7 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
],
@@ -589,7 +622,7 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-02-21 16:47:38.043115",
+ "modified": "2018-05-14 15:58:27.638576",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts Settings",
@@ -597,7 +630,6 @@
"permissions": [
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 1,
"delete": 0,
@@ -617,7 +649,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
@@ -637,7 +668,6 @@
},
{
"amend": 0,
- "apply_user_permissions": 0,
"cancel": 0,
"create": 0,
"delete": 0,
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
index 4f1570c..b834a5f 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.py
@@ -17,6 +17,7 @@
def validate(self):
self.validate_stale_days()
self.enable_payment_schedule_in_print()
+ self.enable_fields_for_cost_center_settings()
def validate_stale_days(self):
if not self.allow_stale and cint(self.stale_days) <= 0:
@@ -28,4 +29,9 @@
show_in_print = cint(self.show_payment_schedule_in_print)
for doctype in ("Sales Order", "Sales Invoice", "Purchase Order", "Purchase Invoice"):
make_property_setter(doctype, "due_date", "print_hide", show_in_print, "Check")
- make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check")
\ No newline at end of file
+ make_property_setter(doctype, "payment_schedule", "print_hide", 0 if show_in_print else 1, "Check")
+
+ def enable_fields_for_cost_center_settings(self):
+ show_field = 0 if cint(self.allow_cost_center_in_entry_of_bs_account) else 1
+ for doctype in ("Sales Invoice", "Purchase Invoice", "Payment Entry"):
+ make_property_setter(doctype, "cost_center", "hidden", show_field, "Check")
diff --git a/erpnext/accounts/doctype/cost_center/test_cost_center.py b/erpnext/accounts/doctype/cost_center/test_cost_center.py
index dab5028..c4fad75 100644
--- a/erpnext/accounts/doctype/cost_center/test_cost_center.py
+++ b/erpnext/accounts/doctype/cost_center/test_cost_center.py
@@ -4,4 +4,23 @@
import frappe
-test_records = frappe.get_test_records('Cost Center')
\ No newline at end of file
+test_records = frappe.get_test_records('Cost Center')
+
+
+
+def create_cost_center(**args):
+ args = frappe._dict(args)
+ if args.cost_center_name:
+ company = args.company or "_Test Company"
+ company_abbr = frappe.db.get_value("Company", company, "abbr")
+ cc_name = args.cost_center_name + " - " + company_abbr
+ if not frappe.db.exists("Cost Center", cc_name):
+ cc = frappe.new_doc("Cost Center")
+ cc.company = args.company or "_Test Company"
+ cc.cost_center_name = args.cost_center_name
+ cc.is_group = args.is_group or 0
+ cc.parent_cost_center = args.parent_cost_center or "_Test Company - _TC"
+ cc.insert()
+
+
+
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 47e214e..e6fe6ca 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -67,7 +67,8 @@
frappe.throw(_("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}. Please set up a default Cost Center for the Company.")
.format(self.voucher_type, self.voucher_no, self.account))
else:
- if self.cost_center:
+ from erpnext.accounts.utils import get_allow_cost_center_in_entry_of_bs_account
+ if not get_allow_cost_center_in_entry_of_bs_account() and self.cost_center:
self.cost_center = None
if self.project:
self.project = None
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 6ad1df5..6aec6e9 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -414,37 +414,18 @@
args: {
company: frm.doc.company,
party_type: d.party_type,
- party: d.party
+ party: d.party,
+ cost_center: d.cost_center
}
});
}
},
+ cost_center: function(frm, dt, dn) {
+ erpnext.journal_entry.set_account_balance(frm, dt, dn);
+ },
account: function(frm, dt, dn) {
- var d = locals[dt][dn];
- if(d.account) {
- if(!frm.doc.company) frappe.throw(__("Please select Company first"));
- if(!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first"));
-
- return frappe.call({
- method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
- args: {
- account: d.account,
- date: frm.doc.posting_date,
- company: frm.doc.company,
- debit: flt(d.debit_in_account_currency),
- credit: flt(d.credit_in_account_currency),
- exchange_rate: d.exchange_rate
- },
- callback: function(r) {
- if(r.message) {
- $.extend(d, r.message);
- erpnext.journal_entry.set_debit_credit_in_company_currency(frm, dt, dn);
- refresh_field('accounts');
- }
- }
- });
- }
+ erpnext.journal_entry.set_account_balance(frm, dt, dn);
},
debit_in_account_currency: function(frm, cdt, cdn) {
@@ -637,3 +618,33 @@
cur_frm.reload_doc();
}
});
+
+$.extend(erpnext.journal_entry, {
+ set_account_balance: function(frm, dt, dn) {
+ var d = locals[dt][dn];
+ if(d.account) {
+ if(!frm.doc.company) frappe.throw(__("Please select Company first"));
+ if(!frm.doc.posting_date) frappe.throw(__("Please select Posting Date first"));
+
+ return frappe.call({
+ method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_account_balance_and_party_type",
+ args: {
+ account: d.account,
+ date: frm.doc.posting_date,
+ company: frm.doc.company,
+ debit: flt(d.debit_in_account_currency),
+ credit: flt(d.credit_in_account_currency),
+ exchange_rate: d.exchange_rate,
+ cost_center: d.cost_center
+ },
+ callback: function(r) {
+ if(r.message) {
+ $.extend(d, r.message);
+ erpnext.journal_entry.set_debit_credit_in_company_currency(frm, dt, dn);
+ refresh_field('accounts');
+ }
+ }
+ });
+ }
+ },
+});
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 84c165f..259172e 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -716,7 +716,7 @@
def get_payment_entry(ref_doc, args):
- cost_center = frappe.get_cached_value('Company', ref_doc.company, "cost_center")
+ cost_center = ref_doc.get("cost_center") or frappe.get_cached_value('Company', ref_doc.company, "cost_center")
exchange_rate = 1
if args.get("party_account"):
# Modified to include the posting date for which the exchange rate is required.
@@ -849,14 +849,14 @@
}
@frappe.whitelist()
-def get_party_account_and_balance(company, party_type, party):
+def get_party_account_and_balance(company, party_type, party, cost_center=None):
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
account = get_party_account(party_type, party, company)
- account_balance = get_balance_on(account=account)
- party_balance = get_balance_on(party_type=party_type, party=party, company=company)
+ account_balance = get_balance_on(account=account, cost_center=cost_center)
+ party_balance = get_balance_on(party_type=party_type, party=party, company=company, cost_center=cost_center)
return {
"account": account,
@@ -867,7 +867,7 @@
@frappe.whitelist()
-def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None):
+def get_account_balance_and_party_type(account, date, company, debit=None, credit=None, exchange_rate=None, cost_center=None):
"""Returns dict of account balance and party type to be set in Journal Entry on selection of account."""
if not frappe.has_permission("Account"):
frappe.msgprint(_("No Permission"), raise_exception=1)
@@ -886,7 +886,7 @@
party_type = ""
grid_values = {
- "balance": get_balance_on(account, date),
+ "balance": get_balance_on(account, date, cost_center=cost_center),
"party_type": party_type,
"account_type": account_details.account_type,
"account_currency": account_details.account_currency or company_currency,
diff --git a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
index 5495c93..6996c77 100644
--- a/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/test_journal_entry.py
@@ -204,12 +204,72 @@
self.assertEqual(jv.inter_company_journal_entry_reference, "")
self.assertEqual(jv1.inter_company_journal_entry_reference, "")
+ def test_jv_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+ jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False)
+ jv.voucher_type = "Bank Entry"
+ jv.multi_currency = 0
+ jv.cheque_no = "112233"
+ jv.cheque_date = nowdate()
+ jv.insert()
+ jv.submit()
+
+ expected_values = {
+ "_Test Cash - _TC": {
+ "cost_center": cost_center
+ },
+ "_Test Bank - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, debit, credit
+ from `tabGL Entry` where voucher_type='Journal Entry' and voucher_no=%s
+ order by account asc""", jv.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_jv_account_and_party_balance_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ from erpnext.accounts.utils import get_balance_on
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+ jv = make_journal_entry("_Test Cash - _TC", "_Test Bank - _TC", 100, cost_center = cost_center, save=False)
+ account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center)
+ jv.voucher_type = "Bank Entry"
+ jv.multi_currency = 0
+ jv.cheque_no = "112233"
+ jv.cheque_date = nowdate()
+ jv.insert()
+ jv.submit()
+
+ expected_account_balance = account_balance - 100
+ account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=cost_center)
+ self.assertEqual(expected_account_balance, account_balance)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
def make_journal_entry(account1, account2, amount, cost_center=None, posting_date=None, exchange_rate=1, save=True, submit=False, project=None):
if not cost_center:
cost_center = "_Test Cost Center - _TC"
jv = frappe.new_doc("Journal Entry")
- jv.posting_date = posting_date or "2013-02-14"
+ jv.posting_date = posting_date or nowdate()
jv.company = "_Test Company"
jv.user_remark = "test"
jv.multi_currency = 1
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 490f2b4..9215e5f 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -245,7 +245,8 @@
company: frm.doc.company,
party_type: frm.doc.party_type,
party: frm.doc.party,
- date: frm.doc.posting_date
+ date: frm.doc.posting_date,
+ cost_center: frm.doc.cost_center
},
callback: function(r, rt) {
if(r.message) {
@@ -317,7 +318,8 @@
method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_account_details",
args: {
"account": account,
- "date": frm.doc.posting_date
+ "date": frm.doc.posting_date,
+ "cost_center": frm.doc.cost_center
},
callback: function(r, rt) {
if(r.message) {
@@ -505,7 +507,8 @@
"party_type": frm.doc.party_type,
"payment_type": frm.doc.payment_type,
"party": frm.doc.party,
- "party_account": frm.doc.payment_type=="Receive" ? frm.doc.paid_from : frm.doc.paid_to
+ "party_account": frm.doc.payment_type=="Receive" ? frm.doc.paid_from : frm.doc.paid_to,
+ "cost_center": frm.doc.cost_center
}
},
callback: function(r, rt) {
@@ -859,3 +862,38 @@
frm.events.set_unallocated_amount(frm);
}
})
+frappe.ui.form.on('Payment Entry', {
+ cost_center: function(frm){
+ if (frm.doc.posting_date && (frm.doc.paid_from||frm.doc.paid_to)) {
+ return frappe.call({
+ method: "erpnext.accounts.doctype.payment_entry.payment_entry.get_party_and_account_balance",
+ args: {
+ company: frm.doc.company,
+ date: frm.doc.posting_date,
+ paid_from: frm.doc.paid_from,
+ paid_to: frm.doc.paid_to,
+ ptype: frm.doc.party_type,
+ pty: frm.doc.party,
+ cost_center: frm.doc.cost_center
+ },
+ callback: function(r, rt) {
+ if(r.message) {
+ frappe.run_serially([
+ () => {
+ frm.set_value("paid_from_account_balance", r.message.paid_from_account_balance);
+ frm.set_value("paid_to_account_balance", r.message.paid_to_account_balance);
+ frm.set_value("party_balance", r.message.party_balance);
+ },
+ () => {
+ if(frm.doc.payment_type != "Internal") {
+ frm.events.get_outstanding_documents(frm);
+ }
+ }
+ ]);
+
+ }
+ }
+ });
+ }
+ },
+})
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index bffe669..1d5e130 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -215,6 +215,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Cost Center",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Cost Center",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "mode_of_payment",
"fieldtype": "Link",
"hidden": 0,
@@ -1962,4 +1995,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 9ce7ecb..6c814ad 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -127,12 +127,12 @@
self.party_account = party_account
if self.paid_from and not (self.paid_from_account_currency or self.paid_from_account_balance):
- acc = get_account_details(self.paid_from, self.posting_date)
+ acc = get_account_details(self.paid_from, self.posting_date, self.cost_center)
self.paid_from_account_currency = acc.account_currency
self.paid_from_account_balance = acc.account_balance
if self.paid_to and not (self.paid_to_account_currency or self.paid_to_account_balance):
- acc = get_account_details(self.paid_to, self.posting_date)
+ acc = get_account_details(self.paid_to, self.posting_date, self.cost_center)
self.paid_to_account_currency = acc.account_currency
self.paid_to_account_balance = acc.account_balance
@@ -419,7 +419,8 @@
"party_type": self.party_type,
"party": self.party,
"against": against_account,
- "account_currency": self.party_account_currency
+ "account_currency": self.party_account_currency,
+ "cost_center": self.cost_center
})
dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
@@ -462,7 +463,8 @@
"account_currency": self.paid_from_account_currency,
"against": self.party if self.payment_type=="Pay" else self.paid_to,
"credit_in_account_currency": self.paid_amount,
- "credit": self.base_paid_amount
+ "credit": self.base_paid_amount,
+ "cost_center": self.cost_center
})
)
if self.payment_type in ("Receive", "Internal Transfer"):
@@ -472,7 +474,8 @@
"account_currency": self.paid_to_account_currency,
"against": self.party if self.payment_type=="Receive" else self.paid_from,
"debit_in_account_currency": self.received_amount,
- "debit": self.base_received_amount
+ "debit": self.base_received_amount,
+ "cost_center": self.cost_center
})
)
@@ -549,6 +552,10 @@
condition = " and voucher_type='{0}' and voucher_no='{1}'"\
.format(frappe.db.escape(args["voucher_type"]), frappe.db.escape(args["voucher_no"]))
+ # Add cost center condition
+ if args.get("cost_center"):
+ condition += " and cost_center='%s'" % args.get("cost_center")
+
outstanding_invoices = get_outstanding_invoices(args.get("party_type"), args.get("party"),
args.get("party_account"), condition=condition)
@@ -573,7 +580,7 @@
return negative_outstanding_invoices + outstanding_invoices + orders_to_be_billed
-def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency):
+def get_orders_to_be_billed(posting_date, party_type, party, party_account_currency, company_currency, cost_center=None):
if party_type == "Customer":
voucher_type = 'Sales Order'
elif party_type == "Supplier":
@@ -581,6 +588,12 @@
elif party_type == "Employee":
voucher_type = None
+ # Add cost center condition
+ doc = frappe.get_doc({"doctype": voucher_type})
+ condition = ""
+ if doc and hasattr(doc, 'cost_center'):
+ condition = " and cost_center='%s'" % cost_center
+
orders = []
if voucher_type:
ref_field = "base_grand_total" if party_account_currency == company_currency else "grand_total"
@@ -599,12 +612,14 @@
and ifnull(status, "") != "Closed"
and {ref_field} > advance_paid
and abs(100 - per_billed) > 0.01
+ {condition}
order by
transaction_date, name
""".format(**{
"ref_field": ref_field,
"voucher_type": voucher_type,
- "party_type": scrub(party_type)
+ "party_type": scrub(party_type),
+ "condition": condition
}), party, as_dict=True)
order_list = []
@@ -616,7 +631,7 @@
return order_list
-def get_negative_outstanding_invoices(party_type, party, party_account, party_account_currency, company_currency):
+def get_negative_outstanding_invoices(party_type, party, party_account, party_account_currency, company_currency, cost_center=None):
voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
supplier_condition = ""
if voucher_type == "Purchase Invoice":
@@ -647,22 +662,23 @@
"grand_total_field": grand_total_field,
"voucher_type": voucher_type,
"party_type": scrub(party_type),
- "party_account": "debit_to" if party_type == "Customer" else "credit_to"
+ "party_account": "debit_to" if party_type == "Customer" else "credit_to",
+ "cost_center": cost_center
}), (party, party_account), as_dict=True)
@frappe.whitelist()
-def get_party_details(company, party_type, party, date):
+def get_party_details(company, party_type, party, date, cost_center=None):
if not frappe.db.exists(party_type, party):
frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
party_account = get_party_account(party_type, party, company)
account_currency = get_account_currency(party_account)
- account_balance = get_balance_on(party_account, date)
+ account_balance = get_balance_on(party_account, date, cost_center=cost_center)
_party_name = "title" if party_type == "Student" else party_type.lower() + "_name"
party_name = frappe.db.get_value(party_type, party, _party_name)
- party_balance = get_balance_on(party_type=party_type, party=party)
+ party_balance = get_balance_on(party_type=party_type, party=party, cost_center=cost_center)
return {
"party_account": party_account,
@@ -674,11 +690,11 @@
@frappe.whitelist()
-def get_account_details(account, date):
+def get_account_details(account, date, cost_center=None):
frappe.has_permission('Payment Entry', throw=True)
return frappe._dict({
"account_currency": get_account_currency(account),
- "account_balance": get_balance_on(account, date),
+ "account_balance": get_balance_on(account, date, cost_center=cost_center),
"account_type": frappe.db.get_value("Account", account, "account_type")
})
@@ -855,6 +871,7 @@
pe = frappe.new_doc("Payment Entry")
pe.payment_type = payment_type
pe.company = doc.company
+ pe.cost_center = doc.get("cost_center")
pe.posting_date = nowdate()
pe.mode_of_payment = doc.get("mode_of_payment")
pe.party_type = party_type
@@ -912,4 +929,12 @@
and {dr_or_cr} > 0
""".format(dr_or_cr=dr_or_cr), (dt, dn, party_type, party, account, due_date))
- return paid_amount[0][0] if paid_amount else 0
\ No newline at end of file
+ return paid_amount[0][0] if paid_amount else 0
+
+@frappe.whitelist()
+def get_party_and_account_balance(company, date, paid_from, paid_to=None, ptype=None, pty=None, cost_center=None):
+ return frappe._dict({
+ "party_balance": get_balance_on(party_type=ptype, party=pty, cost_center=cost_center),
+ "paid_from_account_balance": get_balance_on(paid_from, date, cost_center=cost_center),
+ "paid_to_account_balance": get_balance_on(paid_to, date=date, cost_center=cost_center)
+ })
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 2408235..a7ab175 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -8,8 +8,8 @@
from frappe.utils import flt, nowdate
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry, InvalidPaymentEntry
-from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
-from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice, create_sales_invoice_against_cost_center
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice, make_purchase_invoice_against_cost_center
from erpnext.hr.doctype.expense_claim.test_expense_claim import make_expense_claim
test_dependencies = ["Item"]
@@ -322,7 +322,7 @@
self.assertTrue(gl_entries)
- for i, gle in enumerate(gl_entries):
+ for gle in gl_entries:
self.assertEqual(expected_gle[gle.account][0], gle.account)
self.assertEqual(expected_gle[gle.account][1], gle.debit)
self.assertEqual(expected_gle[gle.account][2], gle.credit)
@@ -394,3 +394,176 @@
outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
self.assertEqual(outstanding_amount, 0)
+
+ def test_payment_entry_against_sales_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ si = create_sales_invoice_against_cost_center(cost_center=cost_center, debit_to="Debtors - _TC")
+
+ pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
+ self.assertEqual(pe.cost_center, si.cost_center)
+
+ pe.reference_no = "112211-1"
+ pe.reference_date = nowdate()
+ pe.paid_to = "_Test Bank - _TC"
+ pe.paid_amount = si.grand_total
+ pe.insert()
+ pe.submit()
+
+ expected_values = {
+ "_Test Bank - _TC": {
+ "cost_center": cost_center
+ },
+ "Debtors - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
+ order by account asc""", pe.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_payment_entry_against_sales_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+ si = create_sales_invoice(debit_to="Debtors - _TC")
+
+ pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
+
+ pe.reference_no = "112211-2"
+ pe.reference_date = nowdate()
+ pe.paid_to = "_Test Bank - _TC"
+ pe.paid_amount = si.grand_total
+ pe.insert()
+ pe.submit()
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
+ order by account asc""", pe.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(gle.cost_center, None)
+
+ def test_payment_entry_against_purchase_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ pi = make_purchase_invoice_against_cost_center(cost_center=cost_center, credit_to="Creditors - _TC")
+
+ pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
+ self.assertEqual(pe.cost_center, pi.cost_center)
+
+ pe.reference_no = "112222-1"
+ pe.reference_date = nowdate()
+ pe.paid_from = "_Test Bank - _TC"
+ pe.paid_amount = pi.grand_total
+ pe.insert()
+ pe.submit()
+
+ expected_values = {
+ "_Test Bank - _TC": {
+ "cost_center": cost_center
+ },
+ "Creditors - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
+ order by account asc""", pe.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_payment_entry_against_purchase_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+ pi = make_purchase_invoice(credit_to="Creditors - _TC")
+
+ pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank - _TC")
+
+ pe.reference_no = "112222-2"
+ pe.reference_date = nowdate()
+ pe.paid_from = "_Test Bank - _TC"
+ pe.paid_amount = pi.grand_total
+ pe.insert()
+ pe.submit()
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
+ order by account asc""", pe.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(gle.cost_center, None)
+
+ def test_payment_entry_account_and_party_balance_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ from erpnext.accounts.utils import get_balance_on
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ si = create_sales_invoice_against_cost_center(cost_center=cost_center, debit_to="Debtors - _TC")
+
+ account_balance = get_balance_on(account="_Test Bank - _TC", cost_center=si.cost_center)
+ party_balance = get_balance_on(party_type="Customer", party=si.customer, cost_center=si.cost_center)
+ party_account_balance = get_balance_on(si.debit_to, cost_center=si.cost_center)
+
+ pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank - _TC")
+ pe.reference_no = "112211-1"
+ pe.reference_date = nowdate()
+ pe.paid_to = "_Test Bank - _TC"
+ pe.paid_amount = si.grand_total
+ pe.insert()
+ pe.submit()
+
+ expected_account_balance = account_balance + si.grand_total
+ expected_party_balance = party_balance - si.grand_total
+ expected_party_account_balance = party_account_balance - si.grand_total
+
+ account_balance = get_balance_on(account=pe.paid_to, cost_center=pe.cost_center)
+ party_balance = get_balance_on(party_type="Customer", party=pe.party, cost_center=pe.cost_center)
+ party_account_balance = get_balance_on(account=pe.paid_from, cost_center=pe.cost_center)
+
+ self.assertEqual(pe.cost_center, si.cost_center)
+ self.assertEqual(expected_account_balance, account_balance)
+ self.assertEqual(expected_party_balance, party_balance)
+ self.assertEqual(expected_party_account_balance, party_account_balance)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 7a1a182..2e82c01 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -525,4 +525,4 @@
}
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted==="Yes");
}
-})
\ No newline at end of file
+})
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 2dd6e17..6c0ee8b 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -386,6 +386,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Cost Center",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Cost Center",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"default": "Today",
"fieldname": "posting_date",
"fieldtype": "Date",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 2660490..273a6e4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -389,6 +389,7 @@
if self.party_account_currency==self.company_currency else grand_total,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
@@ -472,7 +473,8 @@
"account": self.stock_received_but_not_billed,
"against": self.supplier,
"debit": flt(item.item_tax_amount, item.precision("item_tax_amount")),
- "remarks": self.remarks or "Accounting Entry for Stock"
+ "remarks": self.remarks or "Accounting Entry for Stock",
+ "cost_center": self.cost_center
})
)
@@ -500,7 +502,8 @@
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount
- if asset_rbnb_currency == self.company_currency else asset_amount)
+ if asset_rbnb_currency == self.company_currency else asset_amount),
+ "cost_center": item.cost_center
}))
if item.item_tax_amount:
@@ -526,7 +529,8 @@
"remarks": self.get("remarks") or _("Accounting Entry for Asset"),
"debit": base_asset_amount,
"debit_in_account_currency": (base_asset_amount
- if cwip_account_currency == self.company_currency else asset_amount)
+ if cwip_account_currency == self.company_currency else asset_amount),
+ "cost_center": self.cost_center
}))
if item.item_tax_amount and not cint(erpnext.is_perpetual_inventory_enabled(self.company)):
@@ -626,6 +630,7 @@
if self.party_account_currency==self.company_currency else self.paid_amount,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
@@ -635,7 +640,8 @@
"against": self.supplier,
"credit": self.base_paid_amount,
"credit_in_account_currency": self.base_paid_amount \
- if bank_account_currency==self.company_currency else self.paid_amount
+ if bank_account_currency==self.company_currency else self.paid_amount,
+ "cost_center": self.cost_center
}, bank_account_currency)
)
@@ -656,6 +662,7 @@
if self.party_account_currency==self.company_currency else self.write_off_amount,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
gl_entries.append(
@@ -665,7 +672,7 @@
"credit": flt(self.base_write_off_amount),
"credit_in_account_currency": self.base_write_off_amount \
if write_off_account_currency==self.company_currency else self.write_off_amount,
- "cost_center": self.write_off_cost_center
+ "cost_center": self.cost_center or self.write_off_cost_center
})
)
@@ -680,7 +687,7 @@
"against": self.supplier,
"debit_in_account_currency": self.rounding_adjustment,
"debit": self.base_rounding_adjustment,
- "cost_center": round_off_cost_center,
+ "cost_center": self.cost_center or round_off_cost_center,
}
))
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 8cf6b1a..c8c23c7 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -790,6 +790,66 @@
pi_doc = frappe.get_doc('Purchase Invoice', pi.name)
self.assertEqual(pi_doc.outstanding_amount, 0)
+ def test_purchase_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ pi = make_purchase_invoice_against_cost_center(cost_center=cost_center, credit_to="Creditors - _TC")
+ self.assertEqual(pi.cost_center, cost_center)
+
+ expected_values = {
+ "Creditors - _TC": {
+ "cost_center": cost_center
+ },
+ "_Test Account Cost for Goods Sold - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
+ order by account asc""", pi.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_purchase_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+ cost_center = "_Test Cost Center - _TC"
+ pi = make_purchase_invoice(credit_to="Creditors - _TC")
+
+ expected_values = {
+ "Creditors - _TC": {
+ "cost_center": None
+ },
+ "_Test Account Cost for Goods Sold - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
+ order by account asc""", pi.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+
def unlink_payment_on_cancel_of_invoice(enable=1):
accounts_settings = frappe.get_doc("Accounts Settings")
accounts_settings.unlink_payment_on_cancellation_of_invoice = enable
@@ -839,4 +899,50 @@
pi.submit()
return pi
-test_records = frappe.get_test_records('Purchase Invoice')
\ No newline at end of file
+def make_purchase_invoice_against_cost_center(**args):
+ pi = frappe.new_doc("Purchase Invoice")
+ args = frappe._dict(args)
+ pi.posting_date = args.posting_date or today()
+ if args.posting_time:
+ pi.posting_time = args.posting_time
+ if args.update_stock:
+ pi.update_stock = 1
+ if args.is_paid:
+ pi.is_paid = 1
+
+ if args.cash_bank_account:
+ pi.cash_bank_account=args.cash_bank_account
+
+ pi.company = args.company or "_Test Company"
+ pi.cost_center = args.cost_center or "_Test Cost Center - _TC"
+ pi.supplier = args.supplier or "_Test Supplier"
+ pi.currency = args.currency or "INR"
+ pi.conversion_rate = args.conversion_rate or 1
+ pi.is_return = args.is_return
+ pi.is_return = args.is_return
+ pi.credit_to = args.return_against or "Creditors - _TC"
+ pi.is_subcontracted = args.is_subcontracted or "No"
+ pi.supplier_warehouse = "_Test Warehouse 1 - _TC"
+
+ pi.append("items", {
+ "item_code": args.item or args.item_code or "_Test Item",
+ "warehouse": args.warehouse or "_Test Warehouse - _TC",
+ "qty": args.qty or 5,
+ "received_qty": args.received_qty or 0,
+ "rejected_qty": args.rejected_qty or 0,
+ "rate": args.rate or 50,
+ "conversion_factor": 1.0,
+ "serial_no": args.serial_no,
+ "stock_uom": "_Test UOM",
+ "cost_center": args.cost_center or "_Test Cost Center - _TC",
+ "project": args.project,
+ "rejected_warehouse": args.rejected_warehouse or "",
+ "rejected_serial_no": args.rejected_serial_no or ""
+ })
+ if not args.do_not_save:
+ pi.insert()
+ if not args.do_not_submit:
+ pi.submit()
+ return pi
+
+test_records = frappe.get_test_records('Purchase Invoice')
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 05b8300..a3f90cd 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -451,6 +451,39 @@
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "cost_center",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Cost Center",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Cost Center",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
"bold": 1,
"collapsible": 0,
"columns": 0,
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 031d04a..4eeedac 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -735,7 +735,8 @@
"debit_in_account_currency": grand_total_in_company_currency \
if self.party_account_currency==self.company_currency else grand_total,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
- "against_voucher_type": self.doctype
+ "against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
@@ -796,13 +797,14 @@
"against": "Expense account - " + cstr(self.loyalty_redemption_account) + " for the Loyalty Program",
"credit": self.loyalty_amount,
"against_voucher": self.return_against if cint(self.is_return) else self.name,
- "against_voucher_type": self.doctype
+ "against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
})
)
gl_entries.append(
self.get_gl_dict({
"account": self.loyalty_redemption_account,
- "cost_center": self.loyalty_redemption_cost_center,
+ "cost_center": self.cost_center or self.loyalty_redemption_cost_center,
"against": self.customer,
"debit": self.loyalty_amount,
"remark": "Loyalty Points redeemed by the customer"
@@ -826,6 +828,7 @@
else payment_mode.amount,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
"against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
@@ -837,7 +840,8 @@
"debit": payment_mode.base_amount,
"debit_in_account_currency": payment_mode.base_amount \
if payment_mode_account_currency==self.company_currency \
- else payment_mode.amount
+ else payment_mode.amount,
+ "cost_center": self.cost_center
}, payment_mode_account_currency)
)
@@ -854,7 +858,8 @@
"debit_in_account_currency": flt(self.base_change_amount) \
if self.party_account_currency==self.company_currency else flt(self.change_amount),
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
- "against_voucher_type": self.doctype
+ "against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
@@ -862,7 +867,8 @@
self.get_gl_dict({
"account": self.account_for_change_amount,
"against": self.customer,
- "credit": self.base_change_amount
+ "credit": self.base_change_amount,
+ "cost_center": self.cost_center
})
)
else:
@@ -884,7 +890,8 @@
"credit_in_account_currency": self.base_write_off_amount \
if self.party_account_currency==self.company_currency else self.write_off_amount,
"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
- "against_voucher_type": self.doctype
+ "against_voucher_type": self.doctype,
+ "cost_center": self.cost_center
}, self.party_account_currency)
)
gl_entries.append(
@@ -894,7 +901,7 @@
"debit": self.base_write_off_amount,
"debit_in_account_currency": self.base_write_off_amount \
if write_off_account_currency==self.company_currency else self.write_off_amount,
- "cost_center": self.write_off_cost_center or default_cost_center
+ "cost_center": self.cost_center or self.write_off_cost_center or default_cost_center
}, write_off_account_currency)
)
@@ -909,7 +916,7 @@
"against": self.customer,
"credit_in_account_currency": self.base_rounding_adjustment,
"credit": self.base_rounding_adjustment,
- "cost_center": round_off_cost_center,
+ "cost_center": self.cost_center or round_off_cost_center,
}
))
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 468ed9f..b0fbc98 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1438,6 +1438,66 @@
si_doc = frappe.get_doc('Sales Invoice', si.name)
self.assertEqual(si_doc.outstanding_amount, 0)
+ def test_sales_invoice_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ si = create_sales_invoice_against_cost_center(cost_center=cost_center, debit_to="Debtors - _TC")
+ self.assertEqual(si.cost_center, cost_center)
+
+ expected_values = {
+ "Debtors - _TC": {
+ "cost_center": cost_center
+ },
+ "Sales - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
+ order by account asc""", si.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_sales_invoice_for_disable_allow_cost_center_in_entry_of_bs_account(self):
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center - _TC"
+ si = create_sales_invoice(debit_to="Debtors - _TC")
+
+ expected_values = {
+ "Debtors - _TC": {
+ "cost_center": None
+ },
+ "Sales - _TC": {
+ "cost_center": cost_center
+ }
+ }
+
+ gl_entries = frappe.db.sql("""select account, cost_center, account_currency, debit, credit,
+ debit_in_account_currency, credit_in_account_currency
+ from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s
+ order by account asc""", si.name, as_dict=1)
+
+ self.assertTrue(gl_entries)
+
+ for gle in gl_entries:
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+
def create_sales_invoice(**args):
si = frappe.new_doc("Sales Invoice")
args = frappe._dict(args)
@@ -1478,6 +1538,48 @@
return si
+def create_sales_invoice_against_cost_center(**args):
+ si = frappe.new_doc("Sales Invoice")
+ args = frappe._dict(args)
+ if args.posting_date:
+ si.set_posting_time = 1
+ si.posting_date = args.posting_date or nowdate()
+
+ si.company = args.company or "_Test Company"
+ si.cost_center = args.cost_center or "_Test Cost Center - _TC"
+ si.customer = args.customer or "_Test Customer"
+ si.debit_to = args.debit_to or "Debtors - _TC"
+ si.update_stock = args.update_stock
+ si.is_pos = args.is_pos
+ si.is_return = args.is_return
+ si.return_against = args.return_against
+ si.currency=args.currency or "INR"
+ si.conversion_rate = args.conversion_rate or 1
+
+ si.append("items", {
+ "item_code": args.item or args.item_code or "_Test Item",
+ "gst_hsn_code": "999800",
+ "warehouse": args.warehouse or "_Test Warehouse - _TC",
+ "qty": args.qty or 1,
+ "rate": args.rate or 100,
+ "income_account": "Sales - _TC",
+ "expense_account": "Cost of Goods Sold - _TC",
+ "cost_center": args.cost_center or "_Test Cost Center - _TC",
+ "serial_no": args.serial_no
+ })
+
+ if not args.do_not_save:
+ si.insert()
+ if not args.do_not_submit:
+ si.submit()
+ else:
+ si.payment_schedule = []
+ else:
+ si.payment_schedule = []
+
+ return si
+
+
test_dependencies = ["Journal Entry", "Contact", "Address"]
test_records = frappe.get_test_records('Sales Invoice')
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 602e671..df69b51 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -18,6 +18,21 @@
"options": "Finance Book"
},
{
+ "fieldname":"cost_center",
+ "label": __("Cost Center"),
+ "fieldtype": "Link",
+ "options": "Cost Center",
+ "get_query": function() {
+ var company = frappe.query_report.get_filter_value('company');
+ return {
+ "doctype": "Cost Center",
+ "filters": {
+ "company": company,
+ }
+ }
+ }
+ },
+ {
"fieldname":"from_date",
"label": __("From Date"),
"fieldtype": "Date",
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index 2d174ff..4524367 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -154,6 +154,11 @@
conditions.append("""account in (select name from tabAccount
where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))
+ if filters.get("cost_center"):
+ lft, rgt = frappe.db.get_value("Cost Center", filters["cost_center"], ["lft", "rgt"])
+ conditions.append("""cost_center in (select name from `tabCost Center`
+ where lft>=%s and rgt<=%s and docstatus<2)""" % (lft, rgt))
+
if filters.get("voucher_no"):
conditions.append("voucher_no=%(voucher_no)s")
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index 8e95d8c..c09fa71 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -13,6 +13,21 @@
"reqd": 1
},
{
+ "fieldname":"cost_center",
+ "label": __("Cost Center"),
+ "fieldtype": "Link",
+ "options": "Cost Center",
+ "get_query": function() {
+ var company = frappe.query_report.get_filter_value('company');
+ return {
+ "doctype": "Cost Center",
+ "filters": {
+ "company": company,
+ }
+ }
+ }
+ },
+ {
"fieldname": "fiscal_year",
"label": __("Fiscal Year"),
"fieldtype": "Link",
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index ae128a7..6fbe97d 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -84,7 +84,7 @@
throw(_("{0} '{1}' not in Fiscal Year {2}").format(label, formatdate(date), fiscal_year))
@frappe.whitelist()
-def get_balance_on(account=None, date=None, party_type=None, party=None, company=None, in_account_currency=True):
+def get_balance_on(account=None, date=None, party_type=None, party=None, company=None, in_account_currency=True, cost_center=None):
if not account and frappe.form_dict.get("account"):
account = frappe.form_dict.get("account")
if not date and frappe.form_dict.get("date"):
@@ -93,6 +93,9 @@
party_type = frappe.form_dict.get("party_type")
if not party and frappe.form_dict.get("party"):
party = frappe.form_dict.get("party")
+ if not cost_center and frappe.form_dict.get("cost_center"):
+ cost_center = frappe.form_dict.get("cost_center")
+
cond = []
if date:
@@ -113,17 +116,36 @@
# hence, assuming balance as 0.0
return 0.0
+ allow_cost_center_in_entry_of_bs_account = get_allow_cost_center_in_entry_of_bs_account()
+
+ if cost_center and allow_cost_center_in_entry_of_bs_account:
+ cc = frappe.get_doc("Cost Center", cost_center)
+ if cc.is_group:
+ cond.append(""" exists (
+ select 1 from `tabCost Center` cc where cc.name = gle.cost_center
+ and cc.lft >= %s and cc.rgt <= %s
+ )""" % (cc.lft, cc.rgt))
+
+ else:
+ cond.append("""gle.cost_center = "%s" """ % (frappe.db.escape(cost_center, percent=False), ))
+
+
if account:
+
acc = frappe.get_doc("Account", account)
if not frappe.flags.ignore_account_permission:
acc.check_permission("read")
- # for pl accounts, get balance within a fiscal year
- if acc.report_type == 'Profit and Loss':
+
+ if not allow_cost_center_in_entry_of_bs_account and acc.report_type == 'Profit and Loss':
+ # for pl accounts, get balance within a fiscal year
cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
% year_start_date)
-
+ elif allow_cost_center_in_entry_of_bs_account:
+ # for all accounts, get balance within a fiscal year if maintain cost center in balance account is checked
+ cond.append("posting_date >= '%s' and voucher_type != 'Period Closing Voucher'" \
+ % year_start_date)
# different filter for group and ledger - improved performance
if acc.is_group:
cond.append("""exists (
@@ -830,3 +852,10 @@
accounts = [d for d in accounts if d['parent_account']==parent]
return accounts
+
+def get_allow_cost_center_in_entry_of_bs_account():
+ def generator():
+ return cint(frappe.db.get_value('Accounts Settings', None, 'allow_cost_center_in_entry_of_bs_account'))
+ return frappe.local_cache("get_allow_cost_center_in_entry_of_bs_account", (), generator, regenerate_if_none=True)
+
+
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 07ddcb4..b3ba053 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -343,7 +343,8 @@
weight_per_unit: item.weight_per_unit,
weight_uom: item.weight_uom,
uom : item.uom,
- pos_profile: me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : ''
+ pos_profile: me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : '',
+ cost_center: item.cost_center
}
},
diff --git a/erpnext/public/js/financial_statements.js b/erpnext/public/js/financial_statements.js
index 8648687..f313ed1 100644
--- a/erpnext/public/js/financial_statements.js
+++ b/erpnext/public/js/financial_statements.js
@@ -79,6 +79,21 @@
"options": "Finance Book"
},
{
+ "fieldname":"cost_center",
+ "label": __("Cost Center"),
+ "fieldtype": "Link",
+ "options": "Cost Center",
+ "get_query": function() {
+ var company = frappe.query_report.get_filter_value('company');
+ return {
+ "doctype": "Cost Center",
+ "filters": {
+ "company": company,
+ }
+ };
+ }
+ },
+ {
"fieldname":"from_fiscal_year",
"label": __("Start Year"),
"fieldtype": "Link",
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 682577b..434b58c 100644
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -201,7 +201,18 @@
} else {
return options[0];
}
- }
+ },
+ copy_parent_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname, parent_fieldname) {
+ var d = locals[dt][dn];
+ if(d[fieldname]){
+ var cl = doc[table_fieldname] || [];
+ for(var i = 0; i < cl.length; i++) {
+ cl[i][fieldname] = doc[parent_fieldname];
+ }
+ }
+ refresh_field(table_fieldname);
+ },
+
});
erpnext.utils.select_alternate_items = function(opts) {
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 3683695..026d83c 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -569,6 +569,74 @@
dt = make_delivery_trip(dn.name)
self.assertEqual(dn.name, dt.delivery_stops[0].delivery_note)
+ def test_delivery_note_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
+ set_perpetual_inventory(1, company)
+
+ set_valuation_method("_Test Item", "FIFO")
+
+ make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
+
+ stock_in_hand_account = get_inventory_account('_Test Company')
+ dn = create_delivery_note(cost_center=cost_center)
+
+ gl_entries = get_gl_entries("Delivery Note", dn.name)
+ self.assertTrue(gl_entries)
+
+ expected_values = {
+ "Cost of Goods Sold - _TC": {
+ "cost_center": cost_center
+ },
+ stock_in_hand_account: {
+ "cost_center": cost_center
+ }
+ }
+ for i, gle in enumerate(gl_entries):
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ set_perpetual_inventory(0, company)
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_delivery_note_for_disable_allow_cost_center_in_entry_of_bs_account(self):
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+ cost_center = "_Test Cost Center - _TC"
+
+ company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
+ set_perpetual_inventory(1, company)
+
+ set_valuation_method("_Test Item", "FIFO")
+
+ make_stock_entry(target="_Test Warehouse - _TC", qty=5, basic_rate=100)
+
+ stock_in_hand_account = get_inventory_account('_Test Company')
+ dn = create_delivery_note()
+
+ gl_entries = get_gl_entries("Delivery Note", dn.name)
+
+ self.assertTrue(gl_entries)
+ expected_values = {
+ "Cost of Goods Sold - _TC": {
+ "cost_center": cost_center
+ },
+ stock_in_hand_account: {
+ "cost_center": None
+ }
+ }
+ for i, gle in enumerate(gl_entries):
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ set_perpetual_inventory(0, company)
+
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
args = frappe._dict(args)
@@ -589,7 +657,7 @@
"rate": args.rate or 100,
"conversion_factor": 1.0,
"expense_account": "Cost of Goods Sold - _TC",
- "cost_center": "_Test Cost Center - _TC",
+ "cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no,
"target_warehouse": args.target_warehouse
})
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 5c370d3..e482f58 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -470,4 +470,4 @@
@frappe.whitelist()
def update_purchase_receipt_status(docname, status):
pr = frappe.get_doc("Purchase Receipt", docname)
- pr.update_status(status)
\ No newline at end of file
+ pr.update_status(status)
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 6e2863e..a2da924 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -333,11 +333,78 @@
pr.cancel()
serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or []
self.assertEquals(len(serial_nos), 0)
- frappe.db.sql("delete from `tabLocation")
+ #frappe.db.sql("delete from `tabLocation")
frappe.db.sql("delete from `tabAsset`")
+ def test_purchase_receipt_for_enable_allow_cost_center_in_entry_of_bs_account(self):
+ from erpnext.accounts.doctype.cost_center.test_cost_center import create_cost_center
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 1
+ accounts_settings.save()
+ cost_center = "_Test Cost Center for BS Account - _TC"
+ create_cost_center(cost_center_name="_Test Cost Center for BS Account", company="_Test Company")
+
+ if not frappe.db.exists('Location', 'Test Location'):
+ frappe.get_doc({
+ 'doctype': 'Location',
+ 'location_name': 'Test Location'
+ }).insert()
+
+ pr = make_purchase_receipt(cost_center=cost_center)
+ set_perpetual_inventory(1, pr.company)
+ stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
+ gl_entries = get_gl_entries("Purchase Receipt", pr.name)
+
+ self.assertTrue(gl_entries)
+
+ expected_values = {
+ "Stock Received But Not Billed - _TC": {
+ "cost_center": cost_center
+ },
+ stock_in_hand_account: {
+ "cost_center": cost_center
+ }
+ }
+ for i, gle in enumerate(gl_entries):
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ set_perpetual_inventory(0, pr.company)
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ def test_purchase_receipt_for_disable_allow_cost_center_in_entry_of_bs_account(self):
+ accounts_settings = frappe.get_doc('Accounts Settings', 'Accounts Settings')
+ accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
+ accounts_settings.save()
+
+ if not frappe.db.exists('Location', 'Test Location'):
+ frappe.get_doc({
+ 'doctype': 'Location',
+ 'location_name': 'Test Location'
+ }).insert()
+
+ pr = make_purchase_receipt()
+ set_perpetual_inventory(1, pr.company)
+ stock_in_hand_account = get_inventory_account(pr.company, pr.get("items")[0].warehouse)
+ gl_entries = get_gl_entries("Purchase Receipt", pr.name)
+
+ self.assertTrue(gl_entries)
+
+ expected_values = {
+ "Stock Received But Not Billed - _TC": {
+ "cost_center": None
+ },
+ stock_in_hand_account: {
+ "cost_center": None
+ }
+ }
+ for i, gle in enumerate(gl_entries):
+ self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
+
+ set_perpetual_inventory(0, pr.company)
+
def get_gl_entries(voucher_type, voucher_no):
- return frappe.db.sql("""select account, debit, credit
+ return frappe.db.sql("""select account, debit, credit, cost_center
from `tabGL Entry` where voucher_type=%s and voucher_no=%s
order by account desc""", (voucher_type, voucher_no), as_dict=1)